summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk6
-rw-r--r--api/current.txt367
-rw-r--r--api/system-current.txt377
-rw-r--r--api/test-current.txt367
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java22
-rw-r--r--cmds/svc/src/com/android/commands/svc/UsbCommand.java10
-rw-r--r--cmds/telecom/src/com/android/commands/telecom/Telecom.java14
-rw-r--r--cmds/uiautomator/library/core-src/com/android/uiautomator/core/InteractionController.java4
-rw-r--r--compiled-classes-phone1
-rw-r--r--core/java/android/app/ActivityManager.java3
-rw-r--r--core/java/android/app/ActivityThread.java23
-rw-r--r--core/java/android/app/ApplicationThreadNative.java16
-rw-r--r--core/java/android/app/IApplicationThread.java2
-rw-r--r--core/java/android/app/LoadedApk.java20
-rw-r--r--core/java/android/app/ProfilerInfo.java9
-rw-r--r--core/java/android/bluetooth/BluetoothA2dp.java17
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java19
-rw-r--r--core/java/android/bluetooth/BluetoothCodecConfig.java154
-rw-r--r--core/java/android/bluetooth/BluetoothCodecStatus.aidl19
-rw-r--r--core/java/android/bluetooth/BluetoothCodecStatus.java134
-rw-r--r--core/java/android/bluetooth/IBluetooth.aidl1
-rw-r--r--core/java/android/bluetooth/IBluetoothA2dp.aidl3
-rw-r--r--core/java/android/content/Intent.java9
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl1
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java2
-rw-r--r--core/java/android/net/ConnectivityManager.java282
-rw-r--r--core/java/android/net/ConnectivityMetricsLogger.java103
-rw-r--r--core/java/android/net/NetworkRecommendationProvider.java68
-rw-r--r--core/java/android/net/NetworkRequest.java14
-rw-r--r--core/java/android/net/SSLCertificateSocketFactory.java6
-rw-r--r--core/java/android/nfc/NdefRecord.java5
-rw-r--r--core/java/android/os/Debug.java12
-rw-r--r--core/java/android/os/FactoryTest.java4
-rw-r--r--core/java/android/os/Seccomp.java24
-rw-r--r--core/java/android/os/ShellCommand.java2
-rw-r--r--core/java/android/os/SystemProperties.java48
-rw-r--r--core/java/android/os/UserManager.java3
-rw-r--r--core/java/android/os/ZygoteProcess.java10
-rw-r--r--core/java/android/os/storage/StorageManager.java14
-rw-r--r--core/java/android/preference/SeekBarVolumizer.java7
-rwxr-xr-xcore/java/android/provider/Settings.java16
-rw-r--r--core/java/android/service/quicksettings/TileService.java5
-rw-r--r--core/java/android/text/Hyphenator.java2
-rw-r--r--core/java/android/view/AccessibilityInteractionController.java4
-rw-r--r--core/java/android/view/View.java14
-rw-r--r--core/java/android/view/ViewGroup.java4
-rw-r--r--core/java/android/webkit/WebViewZygote.java2
-rw-r--r--core/java/android/widget/DayPickerViewPager.java4
-rw-r--r--core/java/android/widget/ListView.java2
-rw-r--r--core/java/com/android/internal/os/RoSystemProperties.java51
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java52
-rw-r--r--core/java/com/android/internal/os/WrapperInit.java24
-rw-r--r--core/java/com/android/internal/os/Zygote.java6
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java27
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java38
-rw-r--r--core/java/com/android/internal/util/MessageUtils.java6
-rw-r--r--core/java/com/android/internal/util/Predicate.java3
-rw-r--r--core/java/com/android/internal/util/StateMachine.java15
-rw-r--r--core/java/com/android/internal/widget/WatchHeaderListView.java3
-rw-r--r--core/jni/Android.mk5
-rw-r--r--core/jni/AndroidRuntime.cpp31
-rw-r--r--core/jni/android_hardware_Radio.cpp5
-rw-r--r--core/jni/android_hardware_SoundTrigger.cpp2
-rw-r--r--core/jni/android_os_Debug.cpp17
-rw-r--r--core/jni/android_os_HwBinder.cpp104
-rw-r--r--core/jni/android_os_HwBlob.cpp2
-rw-r--r--core/jni/android_os_seccomp.cpp40
-rw-r--r--core/jni/android_util_Process.cpp58
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp33
-rw-r--r--core/jni/com_google_android_gles_jni_GLImpl.cpp2
-rw-r--r--core/res/AndroidManifest.xml10
-rw-r--r--core/res/res/layout/resolver_list.xml4
-rw-r--r--core/res/res/values-mcc208-mnc10/config.xml24
-rw-r--r--core/res/res/values-mcc214-mnc01/config.xml23
-rw-r--r--core/res/res/values-mcc334-mnc050/config.xml4
-rw-r--r--core/res/res/values-mcc334-mnc090/config.xml28
-rw-r--r--core/res/res/values-mcc704-mnc01/config.xml27
-rwxr-xr-xcore/res/res/values-mcc708-mnc001/config.xml27
-rw-r--r--core/res/res/values/config.xml11
-rw-r--r--core/res/res/values/strings.xml2
-rw-r--r--core/res/res/values/symbols.xml5
-rw-r--r--core/tests/coretests/Android.mk1
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk19
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk38
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk12
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk19
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk19
-rw-r--r--core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk20
-rw-r--r--core/tests/systemproperties/Android.mk1
-rw-r--r--legacy-test/Android.mk2
-rw-r--r--libs/hwui/Android.mk2
-rw-r--r--libs/hwui/hwui_static_deps.mk2
-rw-r--r--libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp68
-rw-r--r--native/android/Android.mk21
-rw-r--r--obex/javax/obex/ServerSession.java5
-rw-r--r--packages/CarrierDefaultApp/AndroidManifest.xml2
-rw-r--r--packages/DocumentsUI/Android.mk3
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java25
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java12
-rw-r--r--packages/ExternalStorageProvider/Android.mk5
-rw-r--r--packages/PrintSpooler/res/layout/no_print_services_message.xml42
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java99
-rw-r--r--packages/SettingsLib/common.mk4
-rw-r--r--packages/SettingsLib/res/values/arrays.xml27
-rw-r--r--packages/SettingsLib/res/values/strings.xml2
-rwxr-xr-xpackages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java11
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java41
-rw-r--r--packages/Shell/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_signal_in.xml27
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_signal_inout.xml31
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_signal_out.xml27
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_wifi_in.xml27
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml31
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_wifi_out.xml27
-rw-r--r--packages/SystemUI/res/layout/mobile_signal_group.xml6
-rw-r--r--packages/SystemUI/res/layout/signal_cluster_view.xml5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java2
-rw-r--r--packages/SystemUI/tests/Android.mk1
-rw-r--r--packages/WallpaperCropper/Android.mk2
-rw-r--r--packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java4
-rw-r--r--packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java4
-rw-r--r--packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java6
-rw-r--r--preloaded-classes1
-rw-r--r--proto/src/metrics_constants.proto24
-rw-r--r--proto/src/wifi.proto462
-rw-r--r--rs/jni/Android.mk9
-rw-r--r--rs/jni/android_renderscript_RenderScript.cpp6
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java68
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java50
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java86
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java42
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java19
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java3
-rw-r--r--services/core/java/com/android/server/connectivity/MetricsLoggerService.java375
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkMonitor.java33
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java31
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java51
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java241
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecController.java10
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java9
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java28
-rw-r--r--services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java17
-rw-r--r--services/core/java/com/android/server/pm/KeySetManagerService.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java14
-rw-r--r--services/core/java/com/android/server/pm/SELinuxMMAC.java5
-rw-r--r--services/core/java/com/android/server/updates/TzDataInstallReceiver.java8
-rw-r--r--services/java/com/android/server/SystemServer.java5
-rw-r--r--services/net/java/android/net/apf/ApfFilter.java17
-rw-r--r--services/net/java/android/net/ip/IpManager.java14
-rw-r--r--services/net/java/android/net/ip/IpReachabilityMonitor.java10
-rw-r--r--services/net/java/android/net/util/MultinetworkPolicyTracker.java (renamed from services/net/java/android/net/util/AvoidBadWifiTracker.java)36
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java42
-rw-r--r--telecomm/java/android/telecom/Call.java270
-rw-r--r--telecomm/java/android/telecom/Connection.java167
-rw-r--r--telecomm/java/android/telecom/ConnectionRequest.java187
-rw-r--r--telecomm/java/android/telecom/ConnectionService.java79
-rw-r--r--telecomm/java/android/telecom/InCallAdapter.java46
-rw-r--r--telecomm/java/android/telecom/InCallService.java18
-rw-r--r--telecomm/java/android/telecom/ParcelableCall.java28
-rw-r--r--telecomm/java/android/telecom/ParcelableRttCall.aidl22
-rw-r--r--telecomm/java/android/telecom/ParcelableRttCall.java88
-rw-r--r--telecomm/java/android/telecom/Phone.java14
-rw-r--r--telecomm/java/android/telecom/PhoneAccount.java12
-rw-r--r--telecomm/java/android/telecom/RemoteConference.java3
-rw-r--r--telecomm/java/android/telecom/RemoteConnection.java22
-rw-r--r--telecomm/java/android/telecom/RemoteConnectionService.java48
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java21
-rw-r--r--telecomm/java/android/telecom/VideoCallImpl.java7
-rw-r--r--telecomm/java/android/telecom/VideoProfile.java5
-rw-r--r--telecomm/java/com/android/internal/telecom/IConnectionService.aidl3
-rw-r--r--telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl8
-rw-r--r--telecomm/java/com/android/internal/telecom/IInCallService.aidl2
-rw-r--r--telecomm/java/com/android/internal/telecom/ITelecomService.aidl5
-rw-r--r--telecomm/java/com/android/internal/telecom/IVideoProvider.aidl2
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java37
-rw-r--r--telephony/java/android/telephony/ClientRequestStats.aidl22
-rw-r--r--telephony/java/android/telephony/ClientRequestStats.java175
-rw-r--r--telephony/java/android/telephony/DisconnectCause.java22
-rw-r--r--telephony/java/android/telephony/PhoneNumberUtils.java24
-rw-r--r--telephony/java/android/telephony/PhoneStateListener.java76
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java242
-rw-r--r--telephony/java/android/telephony/ims/ImsService.java467
-rw-r--r--telephony/java/android/telephony/ims/ImsServiceBase.java37
-rw-r--r--telephony/java/android/telephony/ims/ImsServiceProxy.java313
-rw-r--r--telephony/java/android/telephony/ims/ImsServiceProxyCompat.java183
-rw-r--r--telephony/java/android/telephony/ims/feature/IMMTelFeature.java187
-rw-r--r--telephony/java/android/telephony/ims/feature/IRcsFeature.java26
-rw-r--r--telephony/java/android/telephony/ims/feature/ImsFeature.java190
-rw-r--r--telephony/java/android/telephony/ims/feature/MMTelFeature.java122
-rw-r--r--telephony/java/android/telephony/ims/feature/RcsFeature.java35
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java348
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsCallSessionListenerImplBase.java251
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java150
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java51
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java53
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsStreamMediaSessionImplBase.java40
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsUtImplBase.java174
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java88
-rw-r--r--telephony/java/com/android/ims/ImsConfig.java694
-rw-r--r--telephony/java/com/android/ims/ImsException.java52
-rw-r--r--telephony/java/com/android/ims/ImsReasonInfo.java11
-rw-r--r--telephony/java/com/android/ims/ImsUtInterface.java179
-rw-r--r--telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl25
-rw-r--r--telephony/java/com/android/ims/internal/IImsServiceController.aidl64
-rw-r--r--telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl28
-rw-r--r--telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl2
-rw-r--r--telephony/java/com/android/ims/internal/ImsCallSession.java1290
-rw-r--r--telephony/java/com/android/ims/internal/ImsVideoCallProvider.java294
-rw-r--r--telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl2
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl53
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl2
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneConstants.java3
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java3
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyIntents.java15
-rw-r--r--test-runner/src/android/test/suitebuilder/TestMethod.java4
-rw-r--r--test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java8
-rw-r--r--test-runner/src/junit/runner/package-info.java2
-rw-r--r--test-runner/src/junit/runner/package.html5
-rw-r--r--test-runner/src/junit/textui/package-info.java2
-rw-r--r--test-runner/src/junit/textui/package.html6
-rw-r--r--tests/net/java/android/net/ConnectivityManagerTest.java176
-rw-r--r--tests/net/java/android/net/ConnectivityMetricsLoggerTest.java136
-rw-r--r--tests/net/java/android/net/apf/ApfTest.java87
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java169
-rw-r--r--tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java188
-rw-r--r--tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java75
-rw-r--r--tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java140
-rwxr-xr-xtools/fonts/fontchain_lint.py2
-rw-r--r--tools/layoutlib/create/Android.mk2
-rw-r--r--tools/layoutlib/create/tests/Android.mk2
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java37
-rw-r--r--wifi/java/android/net/wifi/WifiEnterpriseConfig.java102
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java206
-rwxr-xr-xwifi/java/android/net/wifi/WifiNetworkScoreCache.java12
-rw-r--r--wifi/java/android/net/wifi/WifiSsid.java8
-rw-r--r--wifi/java/android/net/wifi/aware/ConfigRequest.java93
-rw-r--r--wifi/java/android/net/wifi/aware/DiscoverySession.java9
-rw-r--r--wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java11
-rw-r--r--wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl2
-rw-r--r--wifi/java/android/net/wifi/aware/WifiAwareManager.java36
-rw-r--r--wifi/java/android/net/wifi/hotspot2/ConfigParser.java (renamed from wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java)28
-rw-r--r--wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java401
-rw-r--r--wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java786
-rw-r--r--wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java1652
-rw-r--r--wifi/java/android/net/wifi/hotspot2/omadm/XMLNode.java6
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/Credential.java484
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java137
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/HomeSp.aidl (renamed from wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl)2
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java338
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl19
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/Policy.java539
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.aidl19
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java357
-rw-r--r--wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base642
-rw-r--r--wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf2
-rw-r--r--wifi/tests/assets/pps/PerProviderSubscription.xml321
-rw-r--r--wifi/tests/src/android/net/wifi/WifiConfigurationTest.java32
-rw-r--r--wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java61
-rw-r--r--wifi/tests/src/android/net/wifi/WifiSsidTest.java40
-rw-r--r--wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java62
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java (renamed from wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java)64
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java288
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java173
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java261
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java260
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java148
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java221
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java312
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java348
274 files changed, 17730 insertions, 3700 deletions
diff --git a/Android.mk b/Android.mk
index 5dfa58a6ba62..4e1479a4d2de 100644
--- a/Android.mk
+++ b/Android.mk
@@ -435,8 +435,11 @@ LOCAL_SRC_FILES += \
telephony/java/com/android/ims/internal/IImsEcbm.aidl \
telephony/java/com/android/ims/internal/IImsEcbmListener.aidl \
telephony/java/com/android/ims/internal/IImsExternalCallStateListener.aidl \
+ telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl \
telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl \
telephony/java/com/android/ims/internal/IImsService.aidl \
+ telephony/java/com/android/ims/internal/IImsServiceController.aidl \
+ telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl \
telephony/java/com/android/ims/internal/IImsStreamMediaSession.aidl \
telephony/java/com/android/ims/internal/IImsUt.aidl \
telephony/java/com/android/ims/internal/IImsUtListener.aidl \
@@ -511,6 +514,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := framework-protos
LOCAL_MODULE := framework
+LOCAL_DX_FLAGS := --core-library --multi-dex
LOCAL_JACK_FLAGS := --multi-dex native
LOCAL_RMTYPEDEFS := true
@@ -1346,6 +1350,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := libphonenumber-platform
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := ext
+LOCAL_DX_FLAGS := --core-library
+
ifneq ($(INCREMENTAL_BUILDS),)
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_JACK_ENABLED := incremental
diff --git a/api/current.txt b/api/current.txt
index 6e52af61d24d..159b025008ae 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8553,6 +8553,7 @@ package android.content {
field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+ field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
field public static final java.lang.String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
@@ -24629,9 +24630,10 @@ package android.net.wifi {
field public java.util.BitSet allowedProtocols;
field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
field public boolean hiddenSSID;
+ field public boolean isHomeProviderNetwork;
field public int networkId;
field public java.lang.String preSharedKey;
- field public int priority;
+ field public deprecated int priority;
field public java.lang.String providerFriendlyName;
field public long[] roamingConsortiumIds;
field public int status;
@@ -24696,6 +24698,7 @@ package android.net.wifi {
method public java.security.cert.X509Certificate getCaCertificate();
method public java.security.cert.X509Certificate[] getCaCertificates();
method public java.security.cert.X509Certificate getClientCertificate();
+ method public java.security.cert.X509Certificate[] getClientCertificateChain();
method public java.lang.String getDomainSuffixMatch();
method public int getEapMethod();
method public java.lang.String getIdentity();
@@ -24709,6 +24712,7 @@ package android.net.wifi {
method public void setCaCertificate(java.security.cert.X509Certificate);
method public void setCaCertificates(java.security.cert.X509Certificate[]);
method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
+ method public void setClientKeyEntryWithCertificateChain(java.security.PrivateKey, java.security.cert.X509Certificate[]);
method public void setDomainSuffixMatch(java.lang.String);
method public void setEapMethod(int);
method public void setIdentity(java.lang.String);
@@ -24734,11 +24738,14 @@ package android.net.wifi {
}
public static final class WifiEnterpriseConfig.Phase2 {
+ field public static final int AKA = 6; // 0x6
+ field public static final int AKA_PRIME = 7; // 0x7
field public static final int GTC = 4; // 0x4
field public static final int MSCHAP = 2; // 0x2
field public static final int MSCHAPV2 = 3; // 0x3
field public static final int NONE = 0; // 0x0
field public static final int PAP = 1; // 0x1
+ field public static final int SIM = 5; // 0x5
}
public class WifiInfo implements android.os.Parcelable {
@@ -24761,6 +24768,7 @@ package android.net.wifi {
public class WifiManager {
method public int addNetwork(android.net.wifi.WifiConfiguration);
+ method public boolean addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
method public static int calculateSignalLevel(int, int);
method public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
method public static int compareSignalLevel(int, int);
@@ -24773,6 +24781,7 @@ package android.net.wifi {
method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
method public android.net.wifi.WifiInfo getConnectionInfo();
method public android.net.DhcpInfo getDhcpInfo();
+ method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
method public java.util.List<android.net.wifi.ScanResult> getScanResults();
method public int getWifiState();
method public boolean is5GHzBandSupported();
@@ -24783,17 +24792,23 @@ package android.net.wifi {
method public boolean isScanAlwaysAvailable();
method public boolean isTdlsSupported();
method public boolean isWifiEnabled();
- method public boolean pingSupplicant();
+ method public deprecated boolean pingSupplicant();
+ method public void queryPasspointIcon(long, java.lang.String);
method public boolean reassociate();
method public boolean reconnect();
method public boolean removeNetwork(int);
- method public boolean saveConfiguration();
+ method public boolean removePasspointConfiguration(java.lang.String);
+ method public deprecated boolean saveConfiguration();
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
method public boolean setWifiEnabled(boolean);
method public boolean startScan();
method public void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
method public int updateNetwork(android.net.wifi.WifiConfiguration);
+ field public static final java.lang.String ACTION_PASSPOINT_DEAUTH_IMMINENT = "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT";
+ field public static final java.lang.String ACTION_PASSPOINT_ICON = "android.net.wifi.action.PASSPOINT_ICON";
+ field public static final java.lang.String ACTION_PASSPOINT_OSU_PROVIDERS_LIST = "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST";
+ field public static final java.lang.String ACTION_PASSPOINT_SUBSCRIPTION_REMEDIATION = "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION";
field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
field public static final int ERROR_AUTHENTICATING = 1; // 0x1
@@ -24801,6 +24816,18 @@ package android.net.wifi {
field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
field public static final java.lang.String EXTRA_NEW_RSSI = "newRssi";
field public static final java.lang.String EXTRA_NEW_STATE = "newState";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_BSSID = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_ESS = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_ESS";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_REASON_URL = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_REASON_URL";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_REAUTH_DELAY = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_REAUTH_DELAY";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_BSSID = "android.net.wifi.extra.PASSPOINT_ICON_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_DATA = "android.net.wifi.extra.PASSPOINT_ICON_DATA";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_FILENAME = "android.net.wifi.extra.PASSPOINT_ICON_FILENAME";
+ field public static final java.lang.String EXTRA_PASSPOINT_OSU_PROVIDERS_LIST_BSSID = "android.net.wifi.extra.PASSPOINT_OSU_PROVIDERS_LIST_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_OSU_PROVIDERS_LIST_DATA = "android.net.wifi.extra.PASSPOINT_OSU_PROVIDERS_LIST_DATA";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_BSSID = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_METHOD = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_METHOD";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_URL = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_URL";
field public static final java.lang.String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
field public static final java.lang.String EXTRA_RESULTS_UPDATED = "resultsUpdated";
field public static final java.lang.String EXTRA_SUPPLICANT_CONNECTED = "connected";
@@ -24889,8 +24916,6 @@ package android.net.wifi.aware {
public class DiscoverySession {
method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
method public void destroy();
- method public static int getMaxSendRetryCount();
- method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
}
@@ -24985,6 +25010,241 @@ package android.net.wifi.aware {
}
+package android.net.wifi.hotspot2 {
+
+ public final class ConfigParser {
+ method public static android.net.wifi.hotspot2.PasspointConfiguration parsePasspointConfig(java.lang.String, byte[]);
+ }
+
+ public final class PasspointConfiguration implements android.os.Parcelable {
+ ctor public PasspointConfiguration();
+ ctor public PasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
+ method public int describeContents();
+ method public android.net.wifi.hotspot2.pps.Credential getCredential();
+ method public int getCredentialPriority();
+ method public android.net.wifi.hotspot2.pps.HomeSp getHomeSp();
+ method public android.net.wifi.hotspot2.pps.Policy getPolicy();
+ method public long getSubscriptionCreationTimeInMs();
+ method public long getSubscriptionExpirationTimeInMs();
+ method public java.lang.String getSubscriptionType();
+ method public android.net.wifi.hotspot2.pps.UpdateParameter getSubscriptionUpdate();
+ method public java.util.Map<java.lang.String, byte[]> getTrustRootCertList();
+ method public int getUpdateIdentifier();
+ method public long getUsageLimitDataLimit();
+ method public long getUsageLimitStartTimeInMs();
+ method public long getUsageLimitTimeLimitInMinutes();
+ method public long getUsageLimitUsageTimePeriodInMinutes();
+ method public void setCredential(android.net.wifi.hotspot2.pps.Credential);
+ method public void setCredentialPriority(int);
+ method public void setHomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+ method public void setPolicy(android.net.wifi.hotspot2.pps.Policy);
+ method public void setSubscriptionCreationTimeInMs(long);
+ method public void setSubscriptionExpirationTimeInMs(long);
+ method public void setSubscriptionType(java.lang.String);
+ method public void setSubscriptionUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public void setTrustRootCertList(java.util.Map<java.lang.String, byte[]>);
+ method public void setUpdateIdentifier(int);
+ method public void setUsageLimitDataLimit(long);
+ method public void setUsageLimitStartTimeInMs(long);
+ method public void setUsageLimitTimeLimitInMinutes(long);
+ method public void setUsageLimitUsageTimePeriodInMinutes(long);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.PasspointConfiguration> CREATOR;
+ }
+
+}
+
+package android.net.wifi.hotspot2.omadm {
+
+ public final class PpsMoParser {
+ method public static android.net.wifi.hotspot2.PasspointConfiguration parseMoText(java.lang.String);
+ }
+
+}
+
+package android.net.wifi.hotspot2.pps {
+
+ public final class Credential implements android.os.Parcelable {
+ ctor public Credential();
+ ctor public Credential(android.net.wifi.hotspot2.pps.Credential);
+ method public int describeContents();
+ method public java.security.cert.X509Certificate getCaCertificate();
+ method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
+ method public boolean getCheckAaaServerCertStatus();
+ method public java.security.cert.X509Certificate[] getClientCertificateChain();
+ method public java.security.PrivateKey getClientPrivateKey();
+ method public long getCreationTimeInMs();
+ method public long getExpirationTimeInMs();
+ method public java.lang.String getRealm();
+ method public android.net.wifi.hotspot2.pps.Credential.SimCredential getSimCredential();
+ method public android.net.wifi.hotspot2.pps.Credential.UserCredential getUserCredential();
+ method public void setCaCertificate(java.security.cert.X509Certificate);
+ method public void setCertCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+ method public void setCheckAaaServerCertStatus(boolean);
+ method public void setClientCertificateChain(java.security.cert.X509Certificate[]);
+ method public void setClientPrivateKey(java.security.PrivateKey);
+ method public void setCreationTimeInMs(long);
+ method public void setExpirationTimeInMs(long);
+ method public void setRealm(java.lang.String);
+ method public void setSimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+ method public void setUserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential> CREATOR;
+ }
+
+ public static final class Credential.CertificateCredential implements android.os.Parcelable {
+ ctor public Credential.CertificateCredential();
+ ctor public Credential.CertificateCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+ method public int describeContents();
+ method public byte[] getCertSha256Fingerprint();
+ method public java.lang.String getCertType();
+ method public void setCertSha256Fingerprint(byte[]);
+ method public void setCertType(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.CertificateCredential> CREATOR;
+ }
+
+ public static final class Credential.SimCredential implements android.os.Parcelable {
+ ctor public Credential.SimCredential();
+ ctor public Credential.SimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+ method public int describeContents();
+ method public int getEapType();
+ method public java.lang.String getImsi();
+ method public void setEapType(int);
+ method public void setImsi(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.SimCredential> CREATOR;
+ }
+
+ public static final class Credential.UserCredential implements android.os.Parcelable {
+ ctor public Credential.UserCredential();
+ ctor public Credential.UserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+ method public int describeContents();
+ method public boolean getAbleToShare();
+ method public int getEapType();
+ method public boolean getMachineManaged();
+ method public java.lang.String getNonEapInnerMethod();
+ method public java.lang.String getPassword();
+ method public java.lang.String getSoftTokenApp();
+ method public java.lang.String getUsername();
+ method public void setAbleToShare(boolean);
+ method public void setEapType(int);
+ method public void setMachineManaged(boolean);
+ method public void setNonEapInnerMethod(java.lang.String);
+ method public void setPassword(java.lang.String);
+ method public void setSoftTokenApp(java.lang.String);
+ method public void setUsername(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.UserCredential> CREATOR;
+ }
+
+ public final class HomeSp implements android.os.Parcelable {
+ ctor public HomeSp();
+ ctor public HomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+ method public int describeContents();
+ method public java.lang.String getFqdn();
+ method public java.lang.String getFriendlyName();
+ method public java.util.Map<java.lang.String, java.lang.Long> getHomeNetworkIds();
+ method public java.lang.String getIconUrl();
+ method public long[] getMatchAllOis();
+ method public long[] getMatchAnyOis();
+ method public java.lang.String[] getOtherHomePartners();
+ method public long[] getRoamingConsortiumOis();
+ method public void setFqdn(java.lang.String);
+ method public void setFriendlyName(java.lang.String);
+ method public void setHomeNetworkIds(java.util.Map<java.lang.String, java.lang.Long>);
+ method public void setIconUrl(java.lang.String);
+ method public void setMatchAllOis(long[]);
+ method public void setMatchAnyOis(long[]);
+ method public void setOtherHomePartners(java.lang.String[]);
+ method public void setRoamingConsortiumOis(long[]);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.HomeSp> CREATOR;
+ }
+
+ public final class Policy implements android.os.Parcelable {
+ ctor public Policy();
+ ctor public Policy(android.net.wifi.hotspot2.pps.Policy);
+ method public int describeContents();
+ method public java.lang.String[] getExcludedSsidList();
+ method public int getMaximumBssLoadValue();
+ method public long getMinHomeDownlinkBandwidth();
+ method public long getMinHomeUplinkBandwidth();
+ method public long getMinRoamingDownlinkBandwidth();
+ method public long getMinRoamingUplinkBandwidth();
+ method public android.net.wifi.hotspot2.pps.UpdateParameter getPolicyUpdate();
+ method public java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> getPreferredRoamingPartnerList();
+ method public java.util.Map<java.lang.Integer, java.lang.String> getRequiredProtoPortMap();
+ method public void setExcludedSsidList(java.lang.String[]);
+ method public void setMaximumBssLoadValue(int);
+ method public void setMinHomeDownlinkBandwidth(long);
+ method public void setMinHomeUplinkBandwidth(long);
+ method public void setMinRoamingDownlinkBandwidth(long);
+ method public void setMinRoamingUplinkBandwidth(long);
+ method public void setPolicyUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public void setPreferredRoamingPartnerList(java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner>);
+ method public void setRequiredProtoPortMap(java.util.Map<java.lang.Integer, java.lang.String>);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy> CREATOR;
+ }
+
+ public static final class Policy.RoamingPartner implements android.os.Parcelable {
+ ctor public Policy.RoamingPartner();
+ ctor public Policy.RoamingPartner(android.net.wifi.hotspot2.pps.Policy.RoamingPartner);
+ method public int describeContents();
+ method public java.lang.String getCountries();
+ method public java.lang.String getFqdn();
+ method public boolean getFqdnExactMatch();
+ method public int getPriority();
+ method public void setCountries(java.lang.String);
+ method public void setFqdn(java.lang.String);
+ method public void setFqdnExactMatch(boolean);
+ method public void setPriority(int);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> CREATOR;
+ }
+
+ public final class UpdateParameter implements android.os.Parcelable {
+ ctor public UpdateParameter();
+ ctor public UpdateParameter(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public int describeContents();
+ method public java.lang.String getBase64EncodedPassword();
+ method public java.lang.String getRestriction();
+ method public java.lang.String getServerUri();
+ method public byte[] getTrustRootCertSha256Fingerprint();
+ method public java.lang.String getTrustRootCertUrl();
+ method public long getUpdateIntervalInMinutes();
+ method public java.lang.String getUpdateMethod();
+ method public java.lang.String getUsername();
+ method public void setBase64EncodedPassword(java.lang.String);
+ method public void setRestriction(java.lang.String);
+ method public void setServerUri(java.lang.String);
+ method public void setTrustRootCertSha256Fingerprint(byte[]);
+ method public void setTrustRootCertUrl(java.lang.String);
+ method public void setUpdateIntervalInMinutes(long);
+ method public void setUpdateMethod(java.lang.String);
+ method public void setUsername(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.UpdateParameter> CREATOR;
+ field public static final long UPDATE_CHECK_INTERVAL_NEVER = 4294967295L; // 0xffffffffL
+ field public static final java.lang.String UPDATE_METHOD_OMADM = "OMA-DM-ClientInitiated";
+ field public static final java.lang.String UPDATE_METHOD_SSP = "SSP-ClientInitiated";
+ field public static final java.lang.String UPDATE_RESTRICTION_HOMESP = "HomeSP";
+ field public static final java.lang.String UPDATE_RESTRICTION_ROAMING_PARTNER = "RoamingPartner";
+ field public static final java.lang.String UPDATE_RESTRICTION_UNRESTRICTED = "Unrestricted";
+ }
+
+}
+
package android.net.wifi.p2p {
public class WifiP2pConfig implements android.os.Parcelable {
@@ -36320,9 +36580,11 @@ package android.telecom {
method public android.telecom.Call.Details getDetails();
method public android.telecom.Call getParent();
method public java.lang.String getRemainingPostDialSequence();
+ method public android.telecom.Call.RttCall getRttCall();
method public int getState();
method public android.telecom.InCallService.VideoCall getVideoCall();
method public void hold();
+ method public boolean isRttActive();
method public void mergeConference();
method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
method public void playDtmfTone(char);
@@ -36334,9 +36596,12 @@ package android.telecom {
method public void reject(boolean, java.lang.String);
method public final void removeExtras(java.util.List<java.lang.String>);
method public final void removeExtras(java.lang.String...);
+ method public void respondToRttRequest(int, boolean);
method public void sendCallEvent(java.lang.String, android.os.Bundle);
+ method public void sendRttRequest();
method public void splitFromConference();
method public void stopDtmfTone();
+ method public void stopRtt();
method public void swapConference();
method public void unhold();
method public void unregisterCallback(android.telecom.Call.Callback);
@@ -36363,6 +36628,9 @@ package android.telecom {
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
+ method public void onRttModeChanged(android.telecom.Call, int);
+ method public void onRttRequest(android.telecom.Call, int);
+ method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
method public void onStateChanged(android.telecom.Call, int);
method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
}
@@ -36416,6 +36684,16 @@ package android.telecom {
field public static final int PROPERTY_WIFI = 8; // 0x8
}
+ public static final class Call.RttCall {
+ method public int getRttAudioMode();
+ method public java.lang.String read();
+ method public void setRttMode(int);
+ method public void write(java.lang.String) throws java.io.IOException;
+ field public static final int RTT_MODE_FULL = 1; // 0x1
+ field public static final int RTT_MODE_HCO = 2; // 0x2
+ field public static final int RTT_MODE_VCO = 3; // 0x3
+ }
+
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -36635,6 +36913,7 @@ package android.telecom {
method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
method public void setCallDataUsage(long);
field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5
+ field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7
field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6
field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
@@ -36786,6 +37065,7 @@ package android.telecom {
field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40
field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
+ field public static final int CAPABILITY_RTT = 4096; // 0x1000
field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800
field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
@@ -36998,6 +37278,7 @@ package android.telecom {
field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
+ field public static final java.lang.String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
@@ -37090,6 +37371,7 @@ package android.telephony {
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string";
+ field public static final java.lang.String KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING = "config_ims_package_override_string";
field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
@@ -37150,6 +37432,7 @@ package android.telephony {
field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
field public static final java.lang.String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
+ field public static final java.lang.String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
@@ -38474,7 +38757,7 @@ package android.test.mock {
package android.test.suitebuilder {
- public class TestMethod {
+ public deprecated class TestMethod {
ctor public TestMethod(java.lang.reflect.Method, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(junit.framework.TestCase);
@@ -38485,7 +38768,7 @@ package android.test.suitebuilder {
method public java.lang.String getName();
}
- public class TestSuiteBuilder {
+ public deprecated class TestSuiteBuilder {
ctor public TestSuiteBuilder(java.lang.Class);
ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
method public android.test.suitebuilder.TestSuiteBuilder addRequirements(java.util.List<com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>>);
@@ -38498,7 +38781,7 @@ package android.test.suitebuilder {
method public android.test.suitebuilder.TestSuiteBuilder named(java.lang.String);
}
- public static class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
+ public static deprecated class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
ctor public TestSuiteBuilder.FailedToCreateTests(java.lang.Exception);
method public void testSuiteConstructionFailed();
}
@@ -48868,7 +49151,7 @@ package android.widget {
package com.android.internal.util {
- public abstract interface Predicate<T> {
+ public abstract deprecated interface Predicate<T> {
method public abstract boolean apply(T);
}
@@ -49006,6 +49289,8 @@ package dalvik.bytecode {
field public static final int OP_INT_TO_FLOAT = 130; // 0x82
field public static final int OP_INT_TO_LONG = 129; // 0x81
field public static final int OP_INT_TO_SHORT = 143; // 0x8f
+ field public static final int OP_INVOKE_CUSTOM = 252; // 0xfc
+ field public static final int OP_INVOKE_CUSTOM_RANGE = 253; // 0xfd
field public static final int OP_INVOKE_DIRECT = 112; // 0x70
field public static final deprecated int OP_INVOKE_DIRECT_EMPTY = 240; // 0xf0
field public static final int OP_INVOKE_DIRECT_JUMBO = 9471; // 0x24ff
@@ -49013,6 +49298,8 @@ package dalvik.bytecode {
field public static final int OP_INVOKE_INTERFACE = 114; // 0x72
field public static final int OP_INVOKE_INTERFACE_JUMBO = 9983; // 0x26ff
field public static final int OP_INVOKE_INTERFACE_RANGE = 120; // 0x78
+ field public static final int OP_INVOKE_POLYMORPHIC = 250; // 0xfa
+ field public static final int OP_INVOKE_POLYMORPHIC_RANGE = 251; // 0xfb
field public static final int OP_INVOKE_STATIC = 113; // 0x71
field public static final int OP_INVOKE_STATIC_JUMBO = 9727; // 0x25ff
field public static final int OP_INVOKE_STATIC_RANGE = 119; // 0x77
@@ -49194,7 +49481,7 @@ package dalvik.system {
method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
}
- public final class InMemoryDexClassLoader extends java.lang.ClassLoader {
+ public final class InMemoryDexClassLoader extends dalvik.system.BaseDexClassLoader {
ctor public InMemoryDexClassLoader(java.nio.ByteBuffer, java.lang.ClassLoader);
}
@@ -50412,6 +50699,13 @@ package java.lang {
field public static final java.lang.Class<java.lang.Boolean> TYPE;
}
+ public class BootstrapMethodError extends java.lang.LinkageError {
+ ctor public BootstrapMethodError();
+ ctor public BootstrapMethodError(java.lang.String);
+ ctor public BootstrapMethodError(java.lang.String, java.lang.Throwable);
+ ctor public BootstrapMethodError(java.lang.Throwable);
+ }
+
public final class Byte extends java.lang.Number implements java.lang.Comparable {
ctor public Byte(byte);
ctor public Byte(java.lang.String) throws java.lang.NumberFormatException;
@@ -52298,6 +52592,21 @@ package java.lang.annotation {
package java.lang.invoke {
+ public abstract class CallSite {
+ method public abstract java.lang.invoke.MethodHandle dynamicInvoker();
+ method public abstract java.lang.invoke.MethodHandle getTarget();
+ method public abstract void setTarget(java.lang.invoke.MethodHandle);
+ method public java.lang.invoke.MethodType type();
+ }
+
+ public class ConstantCallSite extends java.lang.invoke.CallSite {
+ ctor public ConstantCallSite(java.lang.invoke.MethodHandle);
+ ctor protected ConstantCallSite(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle) throws java.lang.Throwable;
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public final void setTarget(java.lang.invoke.MethodHandle);
+ }
+
public class LambdaConversionException extends java.lang.Exception {
ctor public LambdaConversionException();
ctor public LambdaConversionException(java.lang.String);
@@ -52307,12 +52616,15 @@ package java.lang.invoke {
}
public abstract class MethodHandle {
+ method public java.lang.invoke.MethodHandle asCollector(java.lang.Class<?>, int);
method public java.lang.invoke.MethodHandle asFixedArity();
+ method public java.lang.invoke.MethodHandle asSpreader(java.lang.Class<?>, int);
method public java.lang.invoke.MethodHandle asType(java.lang.invoke.MethodType);
method public java.lang.invoke.MethodHandle asVarargsCollector(java.lang.Class<?>);
method public java.lang.invoke.MethodHandle bindTo(java.lang.Object);
method public final java.lang.Object invoke(java.lang.Object...) throws java.lang.Throwable;
method public final java.lang.Object invokeExact(java.lang.Object...) throws java.lang.Throwable;
+ method public java.lang.Object invokeWithArguments(java.lang.Object...) throws java.lang.Throwable;
method public java.lang.Object invokeWithArguments(java.util.List<?>) throws java.lang.Throwable;
method public boolean isVarargsCollector();
method public java.lang.invoke.MethodType type();
@@ -52346,17 +52658,23 @@ package java.lang.invoke {
method public static java.lang.invoke.MethodHandle arrayElementGetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
method public static java.lang.invoke.MethodHandle arrayElementSetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
method public static java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class<? extends java.lang.Throwable>, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle collectArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle constant(java.lang.Class<?>, java.lang.Object);
method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>);
method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...);
method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType);
+ method public static java.lang.invoke.MethodHandle filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...);
method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle identity(java.lang.Class<?>);
+ method public static java.lang.invoke.MethodHandle insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...);
method public static java.lang.invoke.MethodHandle invoker(java.lang.invoke.MethodType);
method public static java.lang.invoke.MethodHandles.Lookup lookup();
method public static java.lang.invoke.MethodHandle permuteArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int...);
method public static java.lang.invoke.MethodHandles.Lookup publicLookup();
+ method public static <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle spreadInvoker(java.lang.invoke.MethodType, int);
method public static java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
}
@@ -52373,7 +52691,7 @@ package java.lang.invoke {
method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
method public java.lang.Class<?> lookupClass();
method public int lookupModes();
- method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
+ method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflectGetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
@@ -52416,6 +52734,22 @@ package java.lang.invoke {
method public java.lang.invoke.MethodType wrap();
}
+ public class MutableCallSite extends java.lang.invoke.CallSite {
+ ctor public MutableCallSite(java.lang.invoke.MethodType);
+ ctor public MutableCallSite(java.lang.invoke.MethodHandle);
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public void setTarget(java.lang.invoke.MethodHandle);
+ }
+
+ public class VolatileCallSite extends java.lang.invoke.CallSite {
+ ctor public VolatileCallSite(java.lang.invoke.MethodType);
+ ctor public VolatileCallSite(java.lang.invoke.MethodHandle);
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public void setTarget(java.lang.invoke.MethodHandle);
+ }
+
public class WrongMethodTypeException extends java.lang.RuntimeException {
ctor public WrongMethodTypeException();
ctor public WrongMethodTypeException(java.lang.String);
@@ -60704,6 +61038,9 @@ package java.util {
method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <K, V> java.util.NavigableMap<K, V> checkedNavigableMap(java.util.NavigableMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <E> java.util.NavigableSet<E> checkedNavigableSet(java.util.NavigableSet<E>, java.lang.Class<E>);
+ method public static <E> java.util.Queue<E> checkedQueue(java.util.Queue<E>, java.lang.Class<E>);
method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
@@ -60714,7 +61051,11 @@ package java.util {
method public static final <T> java.util.List<T> emptyList();
method public static <T> java.util.ListIterator<T> emptyListIterator();
method public static final <K, V> java.util.Map<K, V> emptyMap();
+ method public static final <K, V> java.util.NavigableMap<K, V> emptyNavigableMap();
+ method public static <E> java.util.NavigableSet<E> emptyNavigableSet();
method public static final <T> java.util.Set<T> emptySet();
+ method public static final <K, V> java.util.SortedMap<K, V> emptySortedMap();
+ method public static <E> java.util.SortedSet<E> emptySortedSet();
method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
method public static <T> void fill(java.util.List<? super T>, T);
method public static int frequency(java.util.Collection<?>, java.lang.Object);
@@ -60743,12 +61084,16 @@ package java.util {
method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
+ method public static <K, V> java.util.NavigableMap<K, V> synchronizedNavigableMap(java.util.NavigableMap<K, V>);
+ method public static <T> java.util.NavigableSet<T> synchronizedNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
+ method public static <K, V> java.util.NavigableMap<K, V> unmodifiableNavigableMap(java.util.NavigableMap<K, ? extends V>);
+ method public static <T> java.util.NavigableSet<T> unmodifiableNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
diff --git a/api/system-current.txt b/api/system-current.txt
index 17ec7a1a34fe..deeb6794d193 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -36,6 +36,7 @@ package android {
field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
field public static final java.lang.String BIND_DIRECTORY_SEARCH = "android.permission.BIND_DIRECTORY_SEARCH";
field public static final java.lang.String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
+ field public static final java.lang.String BIND_IMS_SERVICE = "android.permission.BIND_IMS_SERVICE";
field public static final java.lang.String BIND_INCALL_SERVICE = "android.permission.BIND_INCALL_SERVICE";
field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
field public static final java.lang.String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
@@ -8894,6 +8895,7 @@ package android.content {
field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+ field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
field public static final java.lang.String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
@@ -26978,6 +26980,7 @@ package android.net.wifi {
field public int creatorUid;
field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
field public boolean hiddenSSID;
+ field public boolean isHomeProviderNetwork;
field public java.lang.String lastUpdateName;
field public int lastUpdateUid;
field public boolean meteredHint;
@@ -26986,7 +26989,7 @@ package android.net.wifi {
field public int numScorerOverride;
field public int numScorerOverrideAndSwitchedNetwork;
field public java.lang.String preSharedKey;
- field public int priority;
+ field public deprecated int priority;
field public java.lang.String providerFriendlyName;
field public long[] roamingConsortiumIds;
field public int status;
@@ -27068,6 +27071,7 @@ package android.net.wifi {
method public java.security.cert.X509Certificate getCaCertificate();
method public java.security.cert.X509Certificate[] getCaCertificates();
method public java.security.cert.X509Certificate getClientCertificate();
+ method public java.security.cert.X509Certificate[] getClientCertificateChain();
method public java.lang.String getDomainSuffixMatch();
method public int getEapMethod();
method public java.lang.String getIdentity();
@@ -27081,6 +27085,7 @@ package android.net.wifi {
method public void setCaCertificate(java.security.cert.X509Certificate);
method public void setCaCertificates(java.security.cert.X509Certificate[]);
method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
+ method public void setClientKeyEntryWithCertificateChain(java.security.PrivateKey, java.security.cert.X509Certificate[]);
method public void setDomainSuffixMatch(java.lang.String);
method public void setEapMethod(int);
method public void setIdentity(java.lang.String);
@@ -27106,11 +27111,14 @@ package android.net.wifi {
}
public static final class WifiEnterpriseConfig.Phase2 {
+ field public static final int AKA = 6; // 0x6
+ field public static final int AKA_PRIME = 7; // 0x7
field public static final int GTC = 4; // 0x4
field public static final int MSCHAP = 2; // 0x2
field public static final int MSCHAPV2 = 3; // 0x3
field public static final int NONE = 0; // 0x0
field public static final int PAP = 1; // 0x1
+ field public static final int SIM = 5; // 0x5
}
public class WifiInfo implements android.os.Parcelable {
@@ -27133,6 +27141,7 @@ package android.net.wifi {
public class WifiManager {
method public int addNetwork(android.net.wifi.WifiConfiguration);
+ method public boolean addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
method public static int calculateSignalLevel(int, int);
method public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
method public static int compareSignalLevel(int, int);
@@ -27148,6 +27157,7 @@ package android.net.wifi {
method public android.net.wifi.WifiInfo getConnectionInfo();
method public android.net.wifi.WifiConnectionStatistics getConnectionStatistics();
method public android.net.DhcpInfo getDhcpInfo();
+ method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
method public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
method public java.util.List<android.net.wifi.ScanResult> getScanResults();
method public android.net.wifi.WifiConfiguration getWifiApConfiguration();
@@ -27166,11 +27176,13 @@ package android.net.wifi {
method public boolean isWifiApEnabled();
method public boolean isWifiEnabled();
method public boolean isWifiScannerSupported();
- method public boolean pingSupplicant();
+ method public deprecated boolean pingSupplicant();
+ method public void queryPasspointIcon(long, java.lang.String);
method public boolean reassociate();
method public boolean reconnect();
method public boolean removeNetwork(int);
- method public boolean saveConfiguration();
+ method public boolean removePasspointConfiguration(java.lang.String);
+ method public deprecated boolean saveConfiguration();
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
@@ -27181,6 +27193,10 @@ package android.net.wifi {
method public boolean startScan(android.os.WorkSource);
method public void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
method public int updateNetwork(android.net.wifi.WifiConfiguration);
+ field public static final java.lang.String ACTION_PASSPOINT_DEAUTH_IMMINENT = "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT";
+ field public static final java.lang.String ACTION_PASSPOINT_ICON = "android.net.wifi.action.PASSPOINT_ICON";
+ field public static final java.lang.String ACTION_PASSPOINT_OSU_PROVIDERS_LIST = "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST";
+ field public static final java.lang.String ACTION_PASSPOINT_SUBSCRIPTION_REMEDIATION = "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION";
field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
field public static final int CHANGE_REASON_ADDED = 0; // 0x0
@@ -27194,6 +27210,18 @@ package android.net.wifi {
field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
field public static final java.lang.String EXTRA_NEW_RSSI = "newRssi";
field public static final java.lang.String EXTRA_NEW_STATE = "newState";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_BSSID = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_ESS = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_ESS";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_REASON_URL = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_REASON_URL";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_REAUTH_DELAY = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_REAUTH_DELAY";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_BSSID = "android.net.wifi.extra.PASSPOINT_ICON_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_DATA = "android.net.wifi.extra.PASSPOINT_ICON_DATA";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_FILENAME = "android.net.wifi.extra.PASSPOINT_ICON_FILENAME";
+ field public static final java.lang.String EXTRA_PASSPOINT_OSU_PROVIDERS_LIST_BSSID = "android.net.wifi.extra.PASSPOINT_OSU_PROVIDERS_LIST_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_OSU_PROVIDERS_LIST_DATA = "android.net.wifi.extra.PASSPOINT_OSU_PROVIDERS_LIST_DATA";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_BSSID = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_METHOD = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_METHOD";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_URL = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_URL";
field public static final java.lang.String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
field public static final java.lang.String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
field public static final java.lang.String EXTRA_RESULTS_UPDATED = "resultsUpdated";
@@ -27441,8 +27469,6 @@ package android.net.wifi.aware {
public class DiscoverySession {
method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
method public void destroy();
- method public static int getMaxSendRetryCount();
- method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
}
@@ -27537,6 +27563,241 @@ package android.net.wifi.aware {
}
+package android.net.wifi.hotspot2 {
+
+ public final class ConfigParser {
+ method public static android.net.wifi.hotspot2.PasspointConfiguration parsePasspointConfig(java.lang.String, byte[]);
+ }
+
+ public final class PasspointConfiguration implements android.os.Parcelable {
+ ctor public PasspointConfiguration();
+ ctor public PasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
+ method public int describeContents();
+ method public android.net.wifi.hotspot2.pps.Credential getCredential();
+ method public int getCredentialPriority();
+ method public android.net.wifi.hotspot2.pps.HomeSp getHomeSp();
+ method public android.net.wifi.hotspot2.pps.Policy getPolicy();
+ method public long getSubscriptionCreationTimeInMs();
+ method public long getSubscriptionExpirationTimeInMs();
+ method public java.lang.String getSubscriptionType();
+ method public android.net.wifi.hotspot2.pps.UpdateParameter getSubscriptionUpdate();
+ method public java.util.Map<java.lang.String, byte[]> getTrustRootCertList();
+ method public int getUpdateIdentifier();
+ method public long getUsageLimitDataLimit();
+ method public long getUsageLimitStartTimeInMs();
+ method public long getUsageLimitTimeLimitInMinutes();
+ method public long getUsageLimitUsageTimePeriodInMinutes();
+ method public void setCredential(android.net.wifi.hotspot2.pps.Credential);
+ method public void setCredentialPriority(int);
+ method public void setHomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+ method public void setPolicy(android.net.wifi.hotspot2.pps.Policy);
+ method public void setSubscriptionCreationTimeInMs(long);
+ method public void setSubscriptionExpirationTimeInMs(long);
+ method public void setSubscriptionType(java.lang.String);
+ method public void setSubscriptionUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public void setTrustRootCertList(java.util.Map<java.lang.String, byte[]>);
+ method public void setUpdateIdentifier(int);
+ method public void setUsageLimitDataLimit(long);
+ method public void setUsageLimitStartTimeInMs(long);
+ method public void setUsageLimitTimeLimitInMinutes(long);
+ method public void setUsageLimitUsageTimePeriodInMinutes(long);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.PasspointConfiguration> CREATOR;
+ }
+
+}
+
+package android.net.wifi.hotspot2.omadm {
+
+ public final class PpsMoParser {
+ method public static android.net.wifi.hotspot2.PasspointConfiguration parseMoText(java.lang.String);
+ }
+
+}
+
+package android.net.wifi.hotspot2.pps {
+
+ public final class Credential implements android.os.Parcelable {
+ ctor public Credential();
+ ctor public Credential(android.net.wifi.hotspot2.pps.Credential);
+ method public int describeContents();
+ method public java.security.cert.X509Certificate getCaCertificate();
+ method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
+ method public boolean getCheckAaaServerCertStatus();
+ method public java.security.cert.X509Certificate[] getClientCertificateChain();
+ method public java.security.PrivateKey getClientPrivateKey();
+ method public long getCreationTimeInMs();
+ method public long getExpirationTimeInMs();
+ method public java.lang.String getRealm();
+ method public android.net.wifi.hotspot2.pps.Credential.SimCredential getSimCredential();
+ method public android.net.wifi.hotspot2.pps.Credential.UserCredential getUserCredential();
+ method public void setCaCertificate(java.security.cert.X509Certificate);
+ method public void setCertCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+ method public void setCheckAaaServerCertStatus(boolean);
+ method public void setClientCertificateChain(java.security.cert.X509Certificate[]);
+ method public void setClientPrivateKey(java.security.PrivateKey);
+ method public void setCreationTimeInMs(long);
+ method public void setExpirationTimeInMs(long);
+ method public void setRealm(java.lang.String);
+ method public void setSimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+ method public void setUserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential> CREATOR;
+ }
+
+ public static final class Credential.CertificateCredential implements android.os.Parcelable {
+ ctor public Credential.CertificateCredential();
+ ctor public Credential.CertificateCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+ method public int describeContents();
+ method public byte[] getCertSha256Fingerprint();
+ method public java.lang.String getCertType();
+ method public void setCertSha256Fingerprint(byte[]);
+ method public void setCertType(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.CertificateCredential> CREATOR;
+ }
+
+ public static final class Credential.SimCredential implements android.os.Parcelable {
+ ctor public Credential.SimCredential();
+ ctor public Credential.SimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+ method public int describeContents();
+ method public int getEapType();
+ method public java.lang.String getImsi();
+ method public void setEapType(int);
+ method public void setImsi(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.SimCredential> CREATOR;
+ }
+
+ public static final class Credential.UserCredential implements android.os.Parcelable {
+ ctor public Credential.UserCredential();
+ ctor public Credential.UserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+ method public int describeContents();
+ method public boolean getAbleToShare();
+ method public int getEapType();
+ method public boolean getMachineManaged();
+ method public java.lang.String getNonEapInnerMethod();
+ method public java.lang.String getPassword();
+ method public java.lang.String getSoftTokenApp();
+ method public java.lang.String getUsername();
+ method public void setAbleToShare(boolean);
+ method public void setEapType(int);
+ method public void setMachineManaged(boolean);
+ method public void setNonEapInnerMethod(java.lang.String);
+ method public void setPassword(java.lang.String);
+ method public void setSoftTokenApp(java.lang.String);
+ method public void setUsername(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.UserCredential> CREATOR;
+ }
+
+ public final class HomeSp implements android.os.Parcelable {
+ ctor public HomeSp();
+ ctor public HomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+ method public int describeContents();
+ method public java.lang.String getFqdn();
+ method public java.lang.String getFriendlyName();
+ method public java.util.Map<java.lang.String, java.lang.Long> getHomeNetworkIds();
+ method public java.lang.String getIconUrl();
+ method public long[] getMatchAllOis();
+ method public long[] getMatchAnyOis();
+ method public java.lang.String[] getOtherHomePartners();
+ method public long[] getRoamingConsortiumOis();
+ method public void setFqdn(java.lang.String);
+ method public void setFriendlyName(java.lang.String);
+ method public void setHomeNetworkIds(java.util.Map<java.lang.String, java.lang.Long>);
+ method public void setIconUrl(java.lang.String);
+ method public void setMatchAllOis(long[]);
+ method public void setMatchAnyOis(long[]);
+ method public void setOtherHomePartners(java.lang.String[]);
+ method public void setRoamingConsortiumOis(long[]);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.HomeSp> CREATOR;
+ }
+
+ public final class Policy implements android.os.Parcelable {
+ ctor public Policy();
+ ctor public Policy(android.net.wifi.hotspot2.pps.Policy);
+ method public int describeContents();
+ method public java.lang.String[] getExcludedSsidList();
+ method public int getMaximumBssLoadValue();
+ method public long getMinHomeDownlinkBandwidth();
+ method public long getMinHomeUplinkBandwidth();
+ method public long getMinRoamingDownlinkBandwidth();
+ method public long getMinRoamingUplinkBandwidth();
+ method public android.net.wifi.hotspot2.pps.UpdateParameter getPolicyUpdate();
+ method public java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> getPreferredRoamingPartnerList();
+ method public java.util.Map<java.lang.Integer, java.lang.String> getRequiredProtoPortMap();
+ method public void setExcludedSsidList(java.lang.String[]);
+ method public void setMaximumBssLoadValue(int);
+ method public void setMinHomeDownlinkBandwidth(long);
+ method public void setMinHomeUplinkBandwidth(long);
+ method public void setMinRoamingDownlinkBandwidth(long);
+ method public void setMinRoamingUplinkBandwidth(long);
+ method public void setPolicyUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public void setPreferredRoamingPartnerList(java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner>);
+ method public void setRequiredProtoPortMap(java.util.Map<java.lang.Integer, java.lang.String>);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy> CREATOR;
+ }
+
+ public static final class Policy.RoamingPartner implements android.os.Parcelable {
+ ctor public Policy.RoamingPartner();
+ ctor public Policy.RoamingPartner(android.net.wifi.hotspot2.pps.Policy.RoamingPartner);
+ method public int describeContents();
+ method public java.lang.String getCountries();
+ method public java.lang.String getFqdn();
+ method public boolean getFqdnExactMatch();
+ method public int getPriority();
+ method public void setCountries(java.lang.String);
+ method public void setFqdn(java.lang.String);
+ method public void setFqdnExactMatch(boolean);
+ method public void setPriority(int);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> CREATOR;
+ }
+
+ public final class UpdateParameter implements android.os.Parcelable {
+ ctor public UpdateParameter();
+ ctor public UpdateParameter(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public int describeContents();
+ method public java.lang.String getBase64EncodedPassword();
+ method public java.lang.String getRestriction();
+ method public java.lang.String getServerUri();
+ method public byte[] getTrustRootCertSha256Fingerprint();
+ method public java.lang.String getTrustRootCertUrl();
+ method public long getUpdateIntervalInMinutes();
+ method public java.lang.String getUpdateMethod();
+ method public java.lang.String getUsername();
+ method public void setBase64EncodedPassword(java.lang.String);
+ method public void setRestriction(java.lang.String);
+ method public void setServerUri(java.lang.String);
+ method public void setTrustRootCertSha256Fingerprint(byte[]);
+ method public void setTrustRootCertUrl(java.lang.String);
+ method public void setUpdateIntervalInMinutes(long);
+ method public void setUpdateMethod(java.lang.String);
+ method public void setUsername(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.UpdateParameter> CREATOR;
+ field public static final long UPDATE_CHECK_INTERVAL_NEVER = 4294967295L; // 0xffffffffL
+ field public static final java.lang.String UPDATE_METHOD_OMADM = "OMA-DM-ClientInitiated";
+ field public static final java.lang.String UPDATE_METHOD_SSP = "SSP-ClientInitiated";
+ field public static final java.lang.String UPDATE_RESTRICTION_HOMESP = "HomeSP";
+ field public static final java.lang.String UPDATE_RESTRICTION_ROAMING_PARTNER = "RoamingPartner";
+ field public static final java.lang.String UPDATE_RESTRICTION_UNRESTRICTED = "Unrestricted";
+ }
+
+}
+
package android.net.wifi.p2p {
public class WifiP2pConfig implements android.os.Parcelable {
@@ -39286,9 +39547,11 @@ package android.telecom {
method public android.telecom.Call.Details getDetails();
method public android.telecom.Call getParent();
method public java.lang.String getRemainingPostDialSequence();
+ method public android.telecom.Call.RttCall getRttCall();
method public int getState();
method public android.telecom.InCallService.VideoCall getVideoCall();
method public void hold();
+ method public boolean isRttActive();
method public void mergeConference();
method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
method public void playDtmfTone(char);
@@ -39301,9 +39564,12 @@ package android.telecom {
method public final void removeExtras(java.util.List<java.lang.String>);
method public final void removeExtras(java.lang.String...);
method public deprecated void removeListener(android.telecom.Call.Listener);
+ method public void respondToRttRequest(int, boolean);
method public void sendCallEvent(java.lang.String, android.os.Bundle);
+ method public void sendRttRequest();
method public void splitFromConference();
method public void stopDtmfTone();
+ method public void stopRtt();
method public void swapConference();
method public void unhold();
method public void unregisterCallback(android.telecom.Call.Callback);
@@ -39331,6 +39597,9 @@ package android.telecom {
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
+ method public void onRttModeChanged(android.telecom.Call, int);
+ method public void onRttRequest(android.telecom.Call, int);
+ method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
method public void onStateChanged(android.telecom.Call, int);
method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
}
@@ -39388,6 +39657,16 @@ package android.telecom {
ctor public Call.Listener();
}
+ public static final class Call.RttCall {
+ method public int getRttAudioMode();
+ method public java.lang.String read();
+ method public void setRttMode(int);
+ method public void write(java.lang.String) throws java.io.IOException;
+ field public static final int RTT_MODE_FULL = 1; // 0x1
+ field public static final int RTT_MODE_HCO = 2; // 0x2
+ field public static final int RTT_MODE_VCO = 3; // 0x3
+ }
+
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -39614,6 +39893,7 @@ package android.telecom {
method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
method public void setCallDataUsage(long);
field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5
+ field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7
field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6
field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
@@ -39889,6 +40169,7 @@ package android.telecom {
field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
field public static final int CAPABILITY_MULTI_USER = 32; // 0x20
field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
+ field public static final int CAPABILITY_RTT = 4096; // 0x1000
field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800
field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
@@ -40165,6 +40446,7 @@ package android.telecom {
field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
+ field public static final java.lang.String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
@@ -40259,6 +40541,7 @@ package android.telephony {
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string";
+ field public static final java.lang.String KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING = "config_ims_package_override_string";
field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
@@ -40319,6 +40602,7 @@ package android.telephony {
field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
field public static final java.lang.String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
+ field public static final java.lang.String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
@@ -41136,6 +41420,15 @@ package android.telephony.gsm {
}
+package android.telephony.ims {
+
+ public class ImsServiceBase extends android.app.Service {
+ ctor public ImsServiceBase();
+ method public android.os.IBinder onBind(android.content.Intent);
+ }
+
+}
+
package android.test {
public abstract deprecated class ActivityInstrumentationTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
@@ -41728,7 +42021,7 @@ package android.test.mock {
package android.test.suitebuilder {
- public class TestMethod {
+ public deprecated class TestMethod {
ctor public TestMethod(java.lang.reflect.Method, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(junit.framework.TestCase);
@@ -41739,7 +42032,7 @@ package android.test.suitebuilder {
method public java.lang.String getName();
}
- public class TestSuiteBuilder {
+ public deprecated class TestSuiteBuilder {
ctor public TestSuiteBuilder(java.lang.Class);
ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
method public android.test.suitebuilder.TestSuiteBuilder addRequirements(java.util.List<com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>>);
@@ -41752,7 +42045,7 @@ package android.test.suitebuilder {
method public android.test.suitebuilder.TestSuiteBuilder named(java.lang.String);
}
- public static class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
+ public static deprecated class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
ctor public TestSuiteBuilder.FailedToCreateTests(java.lang.Exception);
method public void testSuiteConstructionFailed();
}
@@ -52479,7 +52772,7 @@ package android.widget {
package com.android.internal.util {
- public abstract interface Predicate<T> {
+ public abstract deprecated interface Predicate<T> {
method public abstract boolean apply(T);
}
@@ -52617,6 +52910,8 @@ package dalvik.bytecode {
field public static final int OP_INT_TO_FLOAT = 130; // 0x82
field public static final int OP_INT_TO_LONG = 129; // 0x81
field public static final int OP_INT_TO_SHORT = 143; // 0x8f
+ field public static final int OP_INVOKE_CUSTOM = 252; // 0xfc
+ field public static final int OP_INVOKE_CUSTOM_RANGE = 253; // 0xfd
field public static final int OP_INVOKE_DIRECT = 112; // 0x70
field public static final deprecated int OP_INVOKE_DIRECT_EMPTY = 240; // 0xf0
field public static final int OP_INVOKE_DIRECT_JUMBO = 9471; // 0x24ff
@@ -52624,6 +52919,8 @@ package dalvik.bytecode {
field public static final int OP_INVOKE_INTERFACE = 114; // 0x72
field public static final int OP_INVOKE_INTERFACE_JUMBO = 9983; // 0x26ff
field public static final int OP_INVOKE_INTERFACE_RANGE = 120; // 0x78
+ field public static final int OP_INVOKE_POLYMORPHIC = 250; // 0xfa
+ field public static final int OP_INVOKE_POLYMORPHIC_RANGE = 251; // 0xfb
field public static final int OP_INVOKE_STATIC = 113; // 0x71
field public static final int OP_INVOKE_STATIC_JUMBO = 9727; // 0x25ff
field public static final int OP_INVOKE_STATIC_RANGE = 119; // 0x77
@@ -52805,7 +53102,7 @@ package dalvik.system {
method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
}
- public final class InMemoryDexClassLoader extends java.lang.ClassLoader {
+ public final class InMemoryDexClassLoader extends dalvik.system.BaseDexClassLoader {
ctor public InMemoryDexClassLoader(java.nio.ByteBuffer, java.lang.ClassLoader);
}
@@ -54023,6 +54320,13 @@ package java.lang {
field public static final java.lang.Class<java.lang.Boolean> TYPE;
}
+ public class BootstrapMethodError extends java.lang.LinkageError {
+ ctor public BootstrapMethodError();
+ ctor public BootstrapMethodError(java.lang.String);
+ ctor public BootstrapMethodError(java.lang.String, java.lang.Throwable);
+ ctor public BootstrapMethodError(java.lang.Throwable);
+ }
+
public final class Byte extends java.lang.Number implements java.lang.Comparable {
ctor public Byte(byte);
ctor public Byte(java.lang.String) throws java.lang.NumberFormatException;
@@ -55909,6 +56213,21 @@ package java.lang.annotation {
package java.lang.invoke {
+ public abstract class CallSite {
+ method public abstract java.lang.invoke.MethodHandle dynamicInvoker();
+ method public abstract java.lang.invoke.MethodHandle getTarget();
+ method public abstract void setTarget(java.lang.invoke.MethodHandle);
+ method public java.lang.invoke.MethodType type();
+ }
+
+ public class ConstantCallSite extends java.lang.invoke.CallSite {
+ ctor public ConstantCallSite(java.lang.invoke.MethodHandle);
+ ctor protected ConstantCallSite(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle) throws java.lang.Throwable;
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public final void setTarget(java.lang.invoke.MethodHandle);
+ }
+
public class LambdaConversionException extends java.lang.Exception {
ctor public LambdaConversionException();
ctor public LambdaConversionException(java.lang.String);
@@ -55918,12 +56237,15 @@ package java.lang.invoke {
}
public abstract class MethodHandle {
+ method public java.lang.invoke.MethodHandle asCollector(java.lang.Class<?>, int);
method public java.lang.invoke.MethodHandle asFixedArity();
+ method public java.lang.invoke.MethodHandle asSpreader(java.lang.Class<?>, int);
method public java.lang.invoke.MethodHandle asType(java.lang.invoke.MethodType);
method public java.lang.invoke.MethodHandle asVarargsCollector(java.lang.Class<?>);
method public java.lang.invoke.MethodHandle bindTo(java.lang.Object);
method public final java.lang.Object invoke(java.lang.Object...) throws java.lang.Throwable;
method public final java.lang.Object invokeExact(java.lang.Object...) throws java.lang.Throwable;
+ method public java.lang.Object invokeWithArguments(java.lang.Object...) throws java.lang.Throwable;
method public java.lang.Object invokeWithArguments(java.util.List<?>) throws java.lang.Throwable;
method public boolean isVarargsCollector();
method public java.lang.invoke.MethodType type();
@@ -55957,17 +56279,23 @@ package java.lang.invoke {
method public static java.lang.invoke.MethodHandle arrayElementGetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
method public static java.lang.invoke.MethodHandle arrayElementSetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
method public static java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class<? extends java.lang.Throwable>, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle collectArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle constant(java.lang.Class<?>, java.lang.Object);
method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>);
method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...);
method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType);
+ method public static java.lang.invoke.MethodHandle filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...);
method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle identity(java.lang.Class<?>);
+ method public static java.lang.invoke.MethodHandle insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...);
method public static java.lang.invoke.MethodHandle invoker(java.lang.invoke.MethodType);
method public static java.lang.invoke.MethodHandles.Lookup lookup();
method public static java.lang.invoke.MethodHandle permuteArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int...);
method public static java.lang.invoke.MethodHandles.Lookup publicLookup();
+ method public static <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle spreadInvoker(java.lang.invoke.MethodType, int);
method public static java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
}
@@ -55984,7 +56312,7 @@ package java.lang.invoke {
method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
method public java.lang.Class<?> lookupClass();
method public int lookupModes();
- method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
+ method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflectGetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
@@ -56027,6 +56355,22 @@ package java.lang.invoke {
method public java.lang.invoke.MethodType wrap();
}
+ public class MutableCallSite extends java.lang.invoke.CallSite {
+ ctor public MutableCallSite(java.lang.invoke.MethodType);
+ ctor public MutableCallSite(java.lang.invoke.MethodHandle);
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public void setTarget(java.lang.invoke.MethodHandle);
+ }
+
+ public class VolatileCallSite extends java.lang.invoke.CallSite {
+ ctor public VolatileCallSite(java.lang.invoke.MethodType);
+ ctor public VolatileCallSite(java.lang.invoke.MethodHandle);
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public void setTarget(java.lang.invoke.MethodHandle);
+ }
+
public class WrongMethodTypeException extends java.lang.RuntimeException {
ctor public WrongMethodTypeException();
ctor public WrongMethodTypeException(java.lang.String);
@@ -64315,6 +64659,9 @@ package java.util {
method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <K, V> java.util.NavigableMap<K, V> checkedNavigableMap(java.util.NavigableMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <E> java.util.NavigableSet<E> checkedNavigableSet(java.util.NavigableSet<E>, java.lang.Class<E>);
+ method public static <E> java.util.Queue<E> checkedQueue(java.util.Queue<E>, java.lang.Class<E>);
method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
@@ -64325,7 +64672,11 @@ package java.util {
method public static final <T> java.util.List<T> emptyList();
method public static <T> java.util.ListIterator<T> emptyListIterator();
method public static final <K, V> java.util.Map<K, V> emptyMap();
+ method public static final <K, V> java.util.NavigableMap<K, V> emptyNavigableMap();
+ method public static <E> java.util.NavigableSet<E> emptyNavigableSet();
method public static final <T> java.util.Set<T> emptySet();
+ method public static final <K, V> java.util.SortedMap<K, V> emptySortedMap();
+ method public static <E> java.util.SortedSet<E> emptySortedSet();
method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
method public static <T> void fill(java.util.List<? super T>, T);
method public static int frequency(java.util.Collection<?>, java.lang.Object);
@@ -64354,12 +64705,16 @@ package java.util {
method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
+ method public static <K, V> java.util.NavigableMap<K, V> synchronizedNavigableMap(java.util.NavigableMap<K, V>);
+ method public static <T> java.util.NavigableSet<T> synchronizedNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
+ method public static <K, V> java.util.NavigableMap<K, V> unmodifiableNavigableMap(java.util.NavigableMap<K, ? extends V>);
+ method public static <T> java.util.NavigableSet<T> unmodifiableNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
diff --git a/api/test-current.txt b/api/test-current.txt
index dc3ea996a451..694415f4ff71 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -8565,6 +8565,7 @@ package android.content {
field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+ field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
field public static final java.lang.String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
@@ -24702,9 +24703,10 @@ package android.net.wifi {
field public java.util.BitSet allowedProtocols;
field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
field public boolean hiddenSSID;
+ field public boolean isHomeProviderNetwork;
field public int networkId;
field public java.lang.String preSharedKey;
- field public int priority;
+ field public deprecated int priority;
field public java.lang.String providerFriendlyName;
field public long[] roamingConsortiumIds;
field public int status;
@@ -24769,6 +24771,7 @@ package android.net.wifi {
method public java.security.cert.X509Certificate getCaCertificate();
method public java.security.cert.X509Certificate[] getCaCertificates();
method public java.security.cert.X509Certificate getClientCertificate();
+ method public java.security.cert.X509Certificate[] getClientCertificateChain();
method public java.lang.String getDomainSuffixMatch();
method public int getEapMethod();
method public java.lang.String getIdentity();
@@ -24782,6 +24785,7 @@ package android.net.wifi {
method public void setCaCertificate(java.security.cert.X509Certificate);
method public void setCaCertificates(java.security.cert.X509Certificate[]);
method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
+ method public void setClientKeyEntryWithCertificateChain(java.security.PrivateKey, java.security.cert.X509Certificate[]);
method public void setDomainSuffixMatch(java.lang.String);
method public void setEapMethod(int);
method public void setIdentity(java.lang.String);
@@ -24807,11 +24811,14 @@ package android.net.wifi {
}
public static final class WifiEnterpriseConfig.Phase2 {
+ field public static final int AKA = 6; // 0x6
+ field public static final int AKA_PRIME = 7; // 0x7
field public static final int GTC = 4; // 0x4
field public static final int MSCHAP = 2; // 0x2
field public static final int MSCHAPV2 = 3; // 0x3
field public static final int NONE = 0; // 0x0
field public static final int PAP = 1; // 0x1
+ field public static final int SIM = 5; // 0x5
}
public class WifiInfo implements android.os.Parcelable {
@@ -24834,6 +24841,7 @@ package android.net.wifi {
public class WifiManager {
method public int addNetwork(android.net.wifi.WifiConfiguration);
+ method public boolean addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
method public static int calculateSignalLevel(int, int);
method public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
method public static int compareSignalLevel(int, int);
@@ -24846,6 +24854,7 @@ package android.net.wifi {
method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
method public android.net.wifi.WifiInfo getConnectionInfo();
method public android.net.DhcpInfo getDhcpInfo();
+ method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
method public java.util.List<android.net.wifi.ScanResult> getScanResults();
method public int getWifiState();
method public boolean is5GHzBandSupported();
@@ -24856,17 +24865,23 @@ package android.net.wifi {
method public boolean isScanAlwaysAvailable();
method public boolean isTdlsSupported();
method public boolean isWifiEnabled();
- method public boolean pingSupplicant();
+ method public deprecated boolean pingSupplicant();
+ method public void queryPasspointIcon(long, java.lang.String);
method public boolean reassociate();
method public boolean reconnect();
method public boolean removeNetwork(int);
- method public boolean saveConfiguration();
+ method public boolean removePasspointConfiguration(java.lang.String);
+ method public deprecated boolean saveConfiguration();
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
method public boolean setWifiEnabled(boolean);
method public boolean startScan();
method public void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
method public int updateNetwork(android.net.wifi.WifiConfiguration);
+ field public static final java.lang.String ACTION_PASSPOINT_DEAUTH_IMMINENT = "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT";
+ field public static final java.lang.String ACTION_PASSPOINT_ICON = "android.net.wifi.action.PASSPOINT_ICON";
+ field public static final java.lang.String ACTION_PASSPOINT_OSU_PROVIDERS_LIST = "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST";
+ field public static final java.lang.String ACTION_PASSPOINT_SUBSCRIPTION_REMEDIATION = "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION";
field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
field public static final int ERROR_AUTHENTICATING = 1; // 0x1
@@ -24874,6 +24889,18 @@ package android.net.wifi {
field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
field public static final java.lang.String EXTRA_NEW_RSSI = "newRssi";
field public static final java.lang.String EXTRA_NEW_STATE = "newState";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_BSSID = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_ESS = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_ESS";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_REASON_URL = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_REASON_URL";
+ field public static final java.lang.String EXTRA_PASSPOINT_DEAUTH_IMMINENT_REAUTH_DELAY = "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_REAUTH_DELAY";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_BSSID = "android.net.wifi.extra.PASSPOINT_ICON_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_DATA = "android.net.wifi.extra.PASSPOINT_ICON_DATA";
+ field public static final java.lang.String EXTRA_PASSPOINT_ICON_FILENAME = "android.net.wifi.extra.PASSPOINT_ICON_FILENAME";
+ field public static final java.lang.String EXTRA_PASSPOINT_OSU_PROVIDERS_LIST_BSSID = "android.net.wifi.extra.PASSPOINT_OSU_PROVIDERS_LIST_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_OSU_PROVIDERS_LIST_DATA = "android.net.wifi.extra.PASSPOINT_OSU_PROVIDERS_LIST_DATA";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_BSSID = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_BSSID";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_METHOD = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_METHOD";
+ field public static final java.lang.String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_URL = "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_URL";
field public static final java.lang.String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
field public static final java.lang.String EXTRA_RESULTS_UPDATED = "resultsUpdated";
field public static final java.lang.String EXTRA_SUPPLICANT_CONNECTED = "connected";
@@ -24962,8 +24989,6 @@ package android.net.wifi.aware {
public class DiscoverySession {
method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
method public void destroy();
- method public static int getMaxSendRetryCount();
- method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
}
@@ -25058,6 +25083,241 @@ package android.net.wifi.aware {
}
+package android.net.wifi.hotspot2 {
+
+ public final class ConfigParser {
+ method public static android.net.wifi.hotspot2.PasspointConfiguration parsePasspointConfig(java.lang.String, byte[]);
+ }
+
+ public final class PasspointConfiguration implements android.os.Parcelable {
+ ctor public PasspointConfiguration();
+ ctor public PasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
+ method public int describeContents();
+ method public android.net.wifi.hotspot2.pps.Credential getCredential();
+ method public int getCredentialPriority();
+ method public android.net.wifi.hotspot2.pps.HomeSp getHomeSp();
+ method public android.net.wifi.hotspot2.pps.Policy getPolicy();
+ method public long getSubscriptionCreationTimeInMs();
+ method public long getSubscriptionExpirationTimeInMs();
+ method public java.lang.String getSubscriptionType();
+ method public android.net.wifi.hotspot2.pps.UpdateParameter getSubscriptionUpdate();
+ method public java.util.Map<java.lang.String, byte[]> getTrustRootCertList();
+ method public int getUpdateIdentifier();
+ method public long getUsageLimitDataLimit();
+ method public long getUsageLimitStartTimeInMs();
+ method public long getUsageLimitTimeLimitInMinutes();
+ method public long getUsageLimitUsageTimePeriodInMinutes();
+ method public void setCredential(android.net.wifi.hotspot2.pps.Credential);
+ method public void setCredentialPriority(int);
+ method public void setHomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+ method public void setPolicy(android.net.wifi.hotspot2.pps.Policy);
+ method public void setSubscriptionCreationTimeInMs(long);
+ method public void setSubscriptionExpirationTimeInMs(long);
+ method public void setSubscriptionType(java.lang.String);
+ method public void setSubscriptionUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public void setTrustRootCertList(java.util.Map<java.lang.String, byte[]>);
+ method public void setUpdateIdentifier(int);
+ method public void setUsageLimitDataLimit(long);
+ method public void setUsageLimitStartTimeInMs(long);
+ method public void setUsageLimitTimeLimitInMinutes(long);
+ method public void setUsageLimitUsageTimePeriodInMinutes(long);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.PasspointConfiguration> CREATOR;
+ }
+
+}
+
+package android.net.wifi.hotspot2.omadm {
+
+ public final class PpsMoParser {
+ method public static android.net.wifi.hotspot2.PasspointConfiguration parseMoText(java.lang.String);
+ }
+
+}
+
+package android.net.wifi.hotspot2.pps {
+
+ public final class Credential implements android.os.Parcelable {
+ ctor public Credential();
+ ctor public Credential(android.net.wifi.hotspot2.pps.Credential);
+ method public int describeContents();
+ method public java.security.cert.X509Certificate getCaCertificate();
+ method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
+ method public boolean getCheckAaaServerCertStatus();
+ method public java.security.cert.X509Certificate[] getClientCertificateChain();
+ method public java.security.PrivateKey getClientPrivateKey();
+ method public long getCreationTimeInMs();
+ method public long getExpirationTimeInMs();
+ method public java.lang.String getRealm();
+ method public android.net.wifi.hotspot2.pps.Credential.SimCredential getSimCredential();
+ method public android.net.wifi.hotspot2.pps.Credential.UserCredential getUserCredential();
+ method public void setCaCertificate(java.security.cert.X509Certificate);
+ method public void setCertCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+ method public void setCheckAaaServerCertStatus(boolean);
+ method public void setClientCertificateChain(java.security.cert.X509Certificate[]);
+ method public void setClientPrivateKey(java.security.PrivateKey);
+ method public void setCreationTimeInMs(long);
+ method public void setExpirationTimeInMs(long);
+ method public void setRealm(java.lang.String);
+ method public void setSimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+ method public void setUserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential> CREATOR;
+ }
+
+ public static final class Credential.CertificateCredential implements android.os.Parcelable {
+ ctor public Credential.CertificateCredential();
+ ctor public Credential.CertificateCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+ method public int describeContents();
+ method public byte[] getCertSha256Fingerprint();
+ method public java.lang.String getCertType();
+ method public void setCertSha256Fingerprint(byte[]);
+ method public void setCertType(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.CertificateCredential> CREATOR;
+ }
+
+ public static final class Credential.SimCredential implements android.os.Parcelable {
+ ctor public Credential.SimCredential();
+ ctor public Credential.SimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+ method public int describeContents();
+ method public int getEapType();
+ method public java.lang.String getImsi();
+ method public void setEapType(int);
+ method public void setImsi(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.SimCredential> CREATOR;
+ }
+
+ public static final class Credential.UserCredential implements android.os.Parcelable {
+ ctor public Credential.UserCredential();
+ ctor public Credential.UserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+ method public int describeContents();
+ method public boolean getAbleToShare();
+ method public int getEapType();
+ method public boolean getMachineManaged();
+ method public java.lang.String getNonEapInnerMethod();
+ method public java.lang.String getPassword();
+ method public java.lang.String getSoftTokenApp();
+ method public java.lang.String getUsername();
+ method public void setAbleToShare(boolean);
+ method public void setEapType(int);
+ method public void setMachineManaged(boolean);
+ method public void setNonEapInnerMethod(java.lang.String);
+ method public void setPassword(java.lang.String);
+ method public void setSoftTokenApp(java.lang.String);
+ method public void setUsername(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.UserCredential> CREATOR;
+ }
+
+ public final class HomeSp implements android.os.Parcelable {
+ ctor public HomeSp();
+ ctor public HomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+ method public int describeContents();
+ method public java.lang.String getFqdn();
+ method public java.lang.String getFriendlyName();
+ method public java.util.Map<java.lang.String, java.lang.Long> getHomeNetworkIds();
+ method public java.lang.String getIconUrl();
+ method public long[] getMatchAllOis();
+ method public long[] getMatchAnyOis();
+ method public java.lang.String[] getOtherHomePartners();
+ method public long[] getRoamingConsortiumOis();
+ method public void setFqdn(java.lang.String);
+ method public void setFriendlyName(java.lang.String);
+ method public void setHomeNetworkIds(java.util.Map<java.lang.String, java.lang.Long>);
+ method public void setIconUrl(java.lang.String);
+ method public void setMatchAllOis(long[]);
+ method public void setMatchAnyOis(long[]);
+ method public void setOtherHomePartners(java.lang.String[]);
+ method public void setRoamingConsortiumOis(long[]);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.HomeSp> CREATOR;
+ }
+
+ public final class Policy implements android.os.Parcelable {
+ ctor public Policy();
+ ctor public Policy(android.net.wifi.hotspot2.pps.Policy);
+ method public int describeContents();
+ method public java.lang.String[] getExcludedSsidList();
+ method public int getMaximumBssLoadValue();
+ method public long getMinHomeDownlinkBandwidth();
+ method public long getMinHomeUplinkBandwidth();
+ method public long getMinRoamingDownlinkBandwidth();
+ method public long getMinRoamingUplinkBandwidth();
+ method public android.net.wifi.hotspot2.pps.UpdateParameter getPolicyUpdate();
+ method public java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> getPreferredRoamingPartnerList();
+ method public java.util.Map<java.lang.Integer, java.lang.String> getRequiredProtoPortMap();
+ method public void setExcludedSsidList(java.lang.String[]);
+ method public void setMaximumBssLoadValue(int);
+ method public void setMinHomeDownlinkBandwidth(long);
+ method public void setMinHomeUplinkBandwidth(long);
+ method public void setMinRoamingDownlinkBandwidth(long);
+ method public void setMinRoamingUplinkBandwidth(long);
+ method public void setPolicyUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public void setPreferredRoamingPartnerList(java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner>);
+ method public void setRequiredProtoPortMap(java.util.Map<java.lang.Integer, java.lang.String>);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy> CREATOR;
+ }
+
+ public static final class Policy.RoamingPartner implements android.os.Parcelable {
+ ctor public Policy.RoamingPartner();
+ ctor public Policy.RoamingPartner(android.net.wifi.hotspot2.pps.Policy.RoamingPartner);
+ method public int describeContents();
+ method public java.lang.String getCountries();
+ method public java.lang.String getFqdn();
+ method public boolean getFqdnExactMatch();
+ method public int getPriority();
+ method public void setCountries(java.lang.String);
+ method public void setFqdn(java.lang.String);
+ method public void setFqdnExactMatch(boolean);
+ method public void setPriority(int);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> CREATOR;
+ }
+
+ public final class UpdateParameter implements android.os.Parcelable {
+ ctor public UpdateParameter();
+ ctor public UpdateParameter(android.net.wifi.hotspot2.pps.UpdateParameter);
+ method public int describeContents();
+ method public java.lang.String getBase64EncodedPassword();
+ method public java.lang.String getRestriction();
+ method public java.lang.String getServerUri();
+ method public byte[] getTrustRootCertSha256Fingerprint();
+ method public java.lang.String getTrustRootCertUrl();
+ method public long getUpdateIntervalInMinutes();
+ method public java.lang.String getUpdateMethod();
+ method public java.lang.String getUsername();
+ method public void setBase64EncodedPassword(java.lang.String);
+ method public void setRestriction(java.lang.String);
+ method public void setServerUri(java.lang.String);
+ method public void setTrustRootCertSha256Fingerprint(byte[]);
+ method public void setTrustRootCertUrl(java.lang.String);
+ method public void setUpdateIntervalInMinutes(long);
+ method public void setUpdateMethod(java.lang.String);
+ method public void setUsername(java.lang.String);
+ method public boolean validate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.UpdateParameter> CREATOR;
+ field public static final long UPDATE_CHECK_INTERVAL_NEVER = 4294967295L; // 0xffffffffL
+ field public static final java.lang.String UPDATE_METHOD_OMADM = "OMA-DM-ClientInitiated";
+ field public static final java.lang.String UPDATE_METHOD_SSP = "SSP-ClientInitiated";
+ field public static final java.lang.String UPDATE_RESTRICTION_HOMESP = "HomeSP";
+ field public static final java.lang.String UPDATE_RESTRICTION_ROAMING_PARTNER = "RoamingPartner";
+ field public static final java.lang.String UPDATE_RESTRICTION_UNRESTRICTED = "Unrestricted";
+ }
+
+}
+
package android.net.wifi.p2p {
public class WifiP2pConfig implements android.os.Parcelable {
@@ -36402,9 +36662,11 @@ package android.telecom {
method public android.telecom.Call.Details getDetails();
method public android.telecom.Call getParent();
method public java.lang.String getRemainingPostDialSequence();
+ method public android.telecom.Call.RttCall getRttCall();
method public int getState();
method public android.telecom.InCallService.VideoCall getVideoCall();
method public void hold();
+ method public boolean isRttActive();
method public void mergeConference();
method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
method public void playDtmfTone(char);
@@ -36416,9 +36678,12 @@ package android.telecom {
method public void reject(boolean, java.lang.String);
method public final void removeExtras(java.util.List<java.lang.String>);
method public final void removeExtras(java.lang.String...);
+ method public void respondToRttRequest(int, boolean);
method public void sendCallEvent(java.lang.String, android.os.Bundle);
+ method public void sendRttRequest();
method public void splitFromConference();
method public void stopDtmfTone();
+ method public void stopRtt();
method public void swapConference();
method public void unhold();
method public void unregisterCallback(android.telecom.Call.Callback);
@@ -36445,6 +36710,9 @@ package android.telecom {
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
+ method public void onRttModeChanged(android.telecom.Call, int);
+ method public void onRttRequest(android.telecom.Call, int);
+ method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
method public void onStateChanged(android.telecom.Call, int);
method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
}
@@ -36498,6 +36766,16 @@ package android.telecom {
field public static final int PROPERTY_WIFI = 8; // 0x8
}
+ public static final class Call.RttCall {
+ method public int getRttAudioMode();
+ method public java.lang.String read();
+ method public void setRttMode(int);
+ method public void write(java.lang.String) throws java.io.IOException;
+ field public static final int RTT_MODE_FULL = 1; // 0x1
+ field public static final int RTT_MODE_HCO = 2; // 0x2
+ field public static final int RTT_MODE_VCO = 3; // 0x3
+ }
+
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -36717,6 +36995,7 @@ package android.telecom {
method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
method public void setCallDataUsage(long);
field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5
+ field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7
field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6
field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
@@ -36868,6 +37147,7 @@ package android.telecom {
field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40
field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
+ field public static final int CAPABILITY_RTT = 4096; // 0x1000
field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800
field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
@@ -37080,6 +37360,7 @@ package android.telecom {
field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
+ field public static final java.lang.String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
@@ -37172,6 +37453,7 @@ package android.telephony {
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string";
+ field public static final java.lang.String KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING = "config_ims_package_override_string";
field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
@@ -37232,6 +37514,7 @@ package android.telephony {
field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
field public static final java.lang.String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
+ field public static final java.lang.String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
@@ -38558,7 +38841,7 @@ package android.test.mock {
package android.test.suitebuilder {
- public class TestMethod {
+ public deprecated class TestMethod {
ctor public TestMethod(java.lang.reflect.Method, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(junit.framework.TestCase);
@@ -38569,7 +38852,7 @@ package android.test.suitebuilder {
method public java.lang.String getName();
}
- public class TestSuiteBuilder {
+ public deprecated class TestSuiteBuilder {
ctor public TestSuiteBuilder(java.lang.Class);
ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
method public android.test.suitebuilder.TestSuiteBuilder addRequirements(java.util.List<com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>>);
@@ -38582,7 +38865,7 @@ package android.test.suitebuilder {
method public android.test.suitebuilder.TestSuiteBuilder named(java.lang.String);
}
- public static class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
+ public static deprecated class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
ctor public TestSuiteBuilder.FailedToCreateTests(java.lang.Exception);
method public void testSuiteConstructionFailed();
}
@@ -48959,7 +49242,7 @@ package android.widget {
package com.android.internal.util {
- public abstract interface Predicate<T> {
+ public abstract deprecated interface Predicate<T> {
method public abstract boolean apply(T);
}
@@ -49097,6 +49380,8 @@ package dalvik.bytecode {
field public static final int OP_INT_TO_FLOAT = 130; // 0x82
field public static final int OP_INT_TO_LONG = 129; // 0x81
field public static final int OP_INT_TO_SHORT = 143; // 0x8f
+ field public static final int OP_INVOKE_CUSTOM = 252; // 0xfc
+ field public static final int OP_INVOKE_CUSTOM_RANGE = 253; // 0xfd
field public static final int OP_INVOKE_DIRECT = 112; // 0x70
field public static final deprecated int OP_INVOKE_DIRECT_EMPTY = 240; // 0xf0
field public static final int OP_INVOKE_DIRECT_JUMBO = 9471; // 0x24ff
@@ -49104,6 +49389,8 @@ package dalvik.bytecode {
field public static final int OP_INVOKE_INTERFACE = 114; // 0x72
field public static final int OP_INVOKE_INTERFACE_JUMBO = 9983; // 0x26ff
field public static final int OP_INVOKE_INTERFACE_RANGE = 120; // 0x78
+ field public static final int OP_INVOKE_POLYMORPHIC = 250; // 0xfa
+ field public static final int OP_INVOKE_POLYMORPHIC_RANGE = 251; // 0xfb
field public static final int OP_INVOKE_STATIC = 113; // 0x71
field public static final int OP_INVOKE_STATIC_JUMBO = 9727; // 0x25ff
field public static final int OP_INVOKE_STATIC_RANGE = 119; // 0x77
@@ -49285,7 +49572,7 @@ package dalvik.system {
method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
}
- public final class InMemoryDexClassLoader extends java.lang.ClassLoader {
+ public final class InMemoryDexClassLoader extends dalvik.system.BaseDexClassLoader {
ctor public InMemoryDexClassLoader(java.nio.ByteBuffer, java.lang.ClassLoader);
}
@@ -50503,6 +50790,13 @@ package java.lang {
field public static final java.lang.Class<java.lang.Boolean> TYPE;
}
+ public class BootstrapMethodError extends java.lang.LinkageError {
+ ctor public BootstrapMethodError();
+ ctor public BootstrapMethodError(java.lang.String);
+ ctor public BootstrapMethodError(java.lang.String, java.lang.Throwable);
+ ctor public BootstrapMethodError(java.lang.Throwable);
+ }
+
public final class Byte extends java.lang.Number implements java.lang.Comparable {
ctor public Byte(byte);
ctor public Byte(java.lang.String) throws java.lang.NumberFormatException;
@@ -52389,6 +52683,21 @@ package java.lang.annotation {
package java.lang.invoke {
+ public abstract class CallSite {
+ method public abstract java.lang.invoke.MethodHandle dynamicInvoker();
+ method public abstract java.lang.invoke.MethodHandle getTarget();
+ method public abstract void setTarget(java.lang.invoke.MethodHandle);
+ method public java.lang.invoke.MethodType type();
+ }
+
+ public class ConstantCallSite extends java.lang.invoke.CallSite {
+ ctor public ConstantCallSite(java.lang.invoke.MethodHandle);
+ ctor protected ConstantCallSite(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle) throws java.lang.Throwable;
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public final void setTarget(java.lang.invoke.MethodHandle);
+ }
+
public class LambdaConversionException extends java.lang.Exception {
ctor public LambdaConversionException();
ctor public LambdaConversionException(java.lang.String);
@@ -52398,12 +52707,15 @@ package java.lang.invoke {
}
public abstract class MethodHandle {
+ method public java.lang.invoke.MethodHandle asCollector(java.lang.Class<?>, int);
method public java.lang.invoke.MethodHandle asFixedArity();
+ method public java.lang.invoke.MethodHandle asSpreader(java.lang.Class<?>, int);
method public java.lang.invoke.MethodHandle asType(java.lang.invoke.MethodType);
method public java.lang.invoke.MethodHandle asVarargsCollector(java.lang.Class<?>);
method public java.lang.invoke.MethodHandle bindTo(java.lang.Object);
method public final java.lang.Object invoke(java.lang.Object...) throws java.lang.Throwable;
method public final java.lang.Object invokeExact(java.lang.Object...) throws java.lang.Throwable;
+ method public java.lang.Object invokeWithArguments(java.lang.Object...) throws java.lang.Throwable;
method public java.lang.Object invokeWithArguments(java.util.List<?>) throws java.lang.Throwable;
method public boolean isVarargsCollector();
method public java.lang.invoke.MethodType type();
@@ -52437,17 +52749,23 @@ package java.lang.invoke {
method public static java.lang.invoke.MethodHandle arrayElementGetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
method public static java.lang.invoke.MethodHandle arrayElementSetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
method public static java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class<? extends java.lang.Throwable>, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle collectArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle constant(java.lang.Class<?>, java.lang.Object);
method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>);
method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...);
method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType);
+ method public static java.lang.invoke.MethodHandle filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...);
method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
method public static java.lang.invoke.MethodHandle identity(java.lang.Class<?>);
+ method public static java.lang.invoke.MethodHandle insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...);
method public static java.lang.invoke.MethodHandle invoker(java.lang.invoke.MethodType);
method public static java.lang.invoke.MethodHandles.Lookup lookup();
method public static java.lang.invoke.MethodHandle permuteArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int...);
method public static java.lang.invoke.MethodHandles.Lookup publicLookup();
+ method public static <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandle);
+ method public static java.lang.invoke.MethodHandle spreadInvoker(java.lang.invoke.MethodType, int);
method public static java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
}
@@ -52464,7 +52782,7 @@ package java.lang.invoke {
method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
method public java.lang.Class<?> lookupClass();
method public int lookupModes();
- method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
+ method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflectGetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
@@ -52507,6 +52825,22 @@ package java.lang.invoke {
method public java.lang.invoke.MethodType wrap();
}
+ public class MutableCallSite extends java.lang.invoke.CallSite {
+ ctor public MutableCallSite(java.lang.invoke.MethodType);
+ ctor public MutableCallSite(java.lang.invoke.MethodHandle);
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public void setTarget(java.lang.invoke.MethodHandle);
+ }
+
+ public class VolatileCallSite extends java.lang.invoke.CallSite {
+ ctor public VolatileCallSite(java.lang.invoke.MethodType);
+ ctor public VolatileCallSite(java.lang.invoke.MethodHandle);
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public void setTarget(java.lang.invoke.MethodHandle);
+ }
+
public class WrongMethodTypeException extends java.lang.RuntimeException {
ctor public WrongMethodTypeException();
ctor public WrongMethodTypeException(java.lang.String);
@@ -60795,6 +61129,9 @@ package java.util {
method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <K, V> java.util.NavigableMap<K, V> checkedNavigableMap(java.util.NavigableMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
+ method public static <E> java.util.NavigableSet<E> checkedNavigableSet(java.util.NavigableSet<E>, java.lang.Class<E>);
+ method public static <E> java.util.Queue<E> checkedQueue(java.util.Queue<E>, java.lang.Class<E>);
method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
@@ -60805,7 +61142,11 @@ package java.util {
method public static final <T> java.util.List<T> emptyList();
method public static <T> java.util.ListIterator<T> emptyListIterator();
method public static final <K, V> java.util.Map<K, V> emptyMap();
+ method public static final <K, V> java.util.NavigableMap<K, V> emptyNavigableMap();
+ method public static <E> java.util.NavigableSet<E> emptyNavigableSet();
method public static final <T> java.util.Set<T> emptySet();
+ method public static final <K, V> java.util.SortedMap<K, V> emptySortedMap();
+ method public static <E> java.util.SortedSet<E> emptySortedSet();
method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
method public static <T> void fill(java.util.List<? super T>, T);
method public static int frequency(java.util.Collection<?>, java.lang.Object);
@@ -60834,12 +61175,16 @@ package java.util {
method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
+ method public static <K, V> java.util.NavigableMap<K, V> synchronizedNavigableMap(java.util.NavigableMap<K, V>);
+ method public static <T> java.util.NavigableSet<T> synchronizedNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
+ method public static <K, V> java.util.NavigableMap<K, V> unmodifiableNavigableMap(java.util.NavigableMap<K, ? extends V>);
+ method public static <T> java.util.NavigableSet<T> unmodifiableNavigableSet(java.util.NavigableSet<T>);
method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index d6c00589e7c2..a66b0b9ddec9 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -110,6 +110,7 @@ public class Am extends BaseCommand {
private String mProfileFile;
private int mSamplingInterval;
private boolean mAutoStop;
+ private boolean mStreaming; // Streaming the profiling output to a file.
private int mStackId;
/**
@@ -127,7 +128,7 @@ public class Am extends BaseCommand {
pw.println(
"usage: am [subcommand] [options]\n" +
"usage: am start [-D] [-N] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" +
- " [--sampling INTERVAL] [-R COUNT] [-S]\n" +
+ " [--sampling INTERVAL] [--streaming] [-R COUNT] [-S]\n" +
" [--track-allocation] [--user <USER_ID> | current] <INTENT>\n" +
" am startservice [--user <USER_ID> | current] <INTENT>\n" +
" am stopservice [--user <USER_ID> | current] <INTENT>\n" +
@@ -138,7 +139,8 @@ public class Am extends BaseCommand {
" am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" +
" [--user <USER_ID> | current]\n" +
" [--no-window-animation] [--abi <ABI>] <COMPONENT>\n" +
- " am profile start [--user <USER_ID> current] [--sampling INTERVAL] <PROCESS> <FILE>\n" +
+ " am profile start [--user <USER_ID> current] [--sampling INTERVAL]\n"+
+ " [--streaming] <PROCESS> <FILE>\n" +
" am profile stop [--user <USER_ID> current] [<PROCESS>]\n" +
" am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" +
" am set-debug-app [-w] [--persistent] <PACKAGE>\n" +
@@ -191,6 +193,8 @@ public class Am extends BaseCommand {
" --start-profiler <FILE>: start profiler and send results to <FILE>\n" +
" --sampling INTERVAL: use sample profiling with INTERVAL microseconds\n" +
" between samples (use with --start-profiler)\n" +
+ " --streaming: stream the profiling output to the specified file (use\n" +
+ " with --start-profiler)\n" +
" -P <FILE>: like above, but profiling stops when app goes idle\n" +
" -R: repeat the activity launch <COUNT> times. Prior to each repeat,\n" +
" the top activity will be finished.\n" +
@@ -250,6 +254,9 @@ public class Am extends BaseCommand {
" may be either a process name or pid. Options are:\n" +
" --user <USER_ID> | current: When supplying a process name,\n" +
" specify user of process to profile; uses current user if not specified.\n" +
+ " --sampling INTERVAL: use sample profiling with INTERVAL microseconds\n" +
+ " between samples\n" +
+ " --streaming: stream the profiling output to the specified file\n" +
"\n" +
"am dumpheap: dump the heap of a process. The given <PROCESS> argument may\n" +
" be either a process name or pid. Options are:\n" +
@@ -483,6 +490,7 @@ public class Am extends BaseCommand {
mProfileFile = null;
mSamplingInterval = 0;
mAutoStop = false;
+ mStreaming = false;
mUserId = defUser;
mStackId = INVALID_STACK_ID;
@@ -503,6 +511,8 @@ public class Am extends BaseCommand {
mAutoStop = false;
} else if (opt.equals("--sampling")) {
mSamplingInterval = Integer.parseInt(nextArgRequired());
+ } else if (opt.equals("--streaming")) {
+ mStreaming = true;
} else if (opt.equals("-R")) {
mRepeat = Integer.parseInt(nextArgRequired());
} else if (opt.equals("-S")) {
@@ -615,7 +625,8 @@ public class Am extends BaseCommand {
System.err.println("Consider using a file under /data/local/tmp/");
return;
}
- profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop);
+ profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop,
+ mStreaming);
}
IActivityManager.WaitResult result = null;
@@ -973,6 +984,7 @@ public class Am extends BaseCommand {
int userId = UserHandle.USER_CURRENT;
int profileType = 0;
mSamplingInterval = 0;
+ mStreaming = false;
String process = null;
@@ -986,6 +998,8 @@ public class Am extends BaseCommand {
userId = parseUserArg(nextArgRequired());
} else if (opt.equals("--wall")) {
wall = true;
+ } else if (opt.equals("--streaming")) {
+ mStreaming = true;
} else if (opt.equals("--sampling")) {
mSamplingInterval = Integer.parseInt(nextArgRequired());
} else {
@@ -1037,7 +1051,7 @@ public class Am extends BaseCommand {
System.err.println("Consider using a file under /data/local/tmp/");
return;
}
- profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false);
+ profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false, mStreaming);
}
try {
diff --git a/cmds/svc/src/com/android/commands/svc/UsbCommand.java b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
index 4dcb05e4f85d..adbe9d015626 100644
--- a/cmds/svc/src/com/android/commands/svc/UsbCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
@@ -36,8 +36,8 @@ public class UsbCommand extends Svc.Command {
public String longHelp() {
return shortHelp() + "\n"
+ "\n"
- + "usage: svc usb setFunction [function]\n"
- + " Set the current usb function.\n\n"
+ + "usage: svc usb setFunction [function] [usbDataUnlocked=false]\n"
+ + " Set the current usb function and optionally the data lock state.\n\n"
+ " svc usb getFunction\n"
+ " Gets the list of currently enabled functions\n";
}
@@ -49,8 +49,12 @@ public class UsbCommand extends Svc.Command {
if ("setFunction".equals(args[1])) {
IUsbManager usbMgr = IUsbManager.Stub.asInterface(ServiceManager.getService(
Context.USB_SERVICE));
+ boolean unlockData = false;
+ if (args.length >= 4) {
+ unlockData = Boolean.valueOf(args[3]);
+ }
try {
- usbMgr.setCurrentFunction((args.length >=3 ? args[2] : null), false);
+ usbMgr.setCurrentFunction((args.length >=3 ? args[2] : null), unlockData);
} catch (RemoteException e) {
System.err.println("Error communicating with UsbManager: " + e);
}
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index 63f6c9267f45..8e9b91dab95d 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -20,7 +20,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.net.Uri;
import android.os.IUserManager;
-import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -51,6 +50,7 @@ public final class Telecom extends BaseCommand {
private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer";
private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer";
private static final String COMMAND_GET_SYSTEM_DIALER = "get-system-dialer";
+ private static final String COMMAND_WAIT_ON_HANDLERS = "wait-on-handlers";
private ComponentName mComponent;
private String mAccountId;
@@ -69,6 +69,7 @@ public final class Telecom extends BaseCommand {
"usage: telecom set-default-dialer <PACKAGE>\n" +
"usage: telecom get-default-dialer\n" +
"usage: telecom get-system-dialer\n" +
+ "usage: telecom wait-on-handlers\n" +
"\n" +
"telecom set-phone-account-enabled: Enables the given phone account, if it has \n" +
" already been registered with Telecom.\n" +
@@ -80,7 +81,9 @@ public final class Telecom extends BaseCommand {
"\n" +
"telecom get-default-dialer: Displays the current default dialer. \n" +
"\n" +
- "telecom get-system-dialer: Displays the current system dialer. \n"
+ "telecom get-system-dialer: Displays the current system dialer. \n" +
+ "\n" +
+ "telecom wait-on-handlers: Wait until all handlers finish their work. \n"
);
}
@@ -125,6 +128,9 @@ public final class Telecom extends BaseCommand {
case COMMAND_GET_SYSTEM_DIALER:
runGetSystemDialer();
break;
+ case COMMAND_WAIT_ON_HANDLERS:
+ runWaitOnHandler();
+ break;
default:
throw new IllegalArgumentException ("unknown command '" + command + "'");
}
@@ -192,6 +198,10 @@ public final class Telecom extends BaseCommand {
System.out.println(mTelecomService.getSystemDialerPackage());
}
+ private void runWaitOnHandler() throws RemoteException {
+
+ }
+
private PhoneAccountHandle getPhoneAccountHandleFromArgs() throws RemoteException{
final ComponentName component = parseComponentName(nextArgRequired());
final String accountId = nextArgRequired();
diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/InteractionController.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/InteractionController.java
index 73e46f1775c2..28a5646abb33 100644
--- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/InteractionController.java
+++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/InteractionController.java
@@ -32,8 +32,6 @@ import android.view.MotionEvent.PointerCoords;
import android.view.MotionEvent.PointerProperties;
import android.view.accessibility.AccessibilityEvent;
-import com.android.internal.util.Predicate;
-
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;
@@ -261,7 +259,7 @@ class InteractionController {
}
/**
- * Returns a Runnable for use in {@link #runAndWaitForEvents(Runnable, Predicate, long) to
+ * Returns a Runnable for use in {@link #runAndWaitForEvents(Runnable, AccessibilityEventFilter, long) to
* perform a click.
*
* @param x coordinate
diff --git a/compiled-classes-phone b/compiled-classes-phone
index ec3371e45711..2cbfc2264ebb 100644
--- a/compiled-classes-phone
+++ b/compiled-classes-phone
@@ -633,6 +633,7 @@ android.bluetooth.BluetoothAudioConfig
android.bluetooth.BluetoothClass
android.bluetooth.BluetoothClass$1
android.bluetooth.BluetoothCodecConfig
+android.bluetooth.BluetoothCodecStatus
android.bluetooth.BluetoothDevice
android.bluetooth.BluetoothDevice$1
android.bluetooth.BluetoothDevice$2
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index af981f69d3b6..e1ff38365c51 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -32,6 +32,7 @@ import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.os.RoSystemProperties;
import com.android.internal.os.TransferPipe;
import com.android.internal.util.FastPrintWriter;
@@ -895,7 +896,7 @@ public class ActivityManager {
/** @hide */
public static boolean isLowRamDeviceStatic() {
- return "true".equals(SystemProperties.get("ro.config.low_ram", "false"));
+ return RoSystemProperties.CONFIG_LOW_RAM;
}
/**
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2d22f26069f3..c7fc860a055c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -534,6 +534,7 @@ public final class ActivityThread {
ParcelFileDescriptor profileFd;
int samplingInterval;
boolean autoStopProfiler;
+ boolean streamingOutput;
boolean profiling;
boolean handlingProfiling;
public void setProfiler(ProfilerInfo profilerInfo) {
@@ -559,6 +560,7 @@ public final class ActivityThread {
profileFd = fd;
samplingInterval = profilerInfo.samplingInterval;
autoStopProfiler = profilerInfo.autoStopProfiler;
+ streamingOutput = profilerInfo.streamingOutput;
}
public void startProfiling() {
if (profileFd == null || profiling) {
@@ -567,7 +569,8 @@ public final class ActivityThread {
try {
int bufferSize = SystemProperties.getInt("debug.traceview-buffer-size-mb", 8);
VMDebug.startMethodTracing(profileFile, profileFd.getFileDescriptor(),
- bufferSize * 1024 * 1024, 0, samplingInterval != 0, samplingInterval);
+ bufferSize * 1024 * 1024, 0, samplingInterval != 0, samplingInterval,
+ streamingOutput);
profiling = true;
} catch (RuntimeException e) {
Slog.w(TAG, "Profiling failed on path " + profileFile);
@@ -971,6 +974,10 @@ public final class ActivityThread {
sendMessage(H.DUMP_HEAP, dhd, managed ? 1 : 0, 0, true /*async*/);
}
+ public void attachAgent(String agent) {
+ sendMessage(H.ATTACH_AGENT, agent);
+ }
+
public void setSchedulingGroup(int group) {
// Note: do this immediately, since going into the foreground
// should happen regardless of what pending work we have to do
@@ -1405,6 +1412,7 @@ public final class ActivityThread {
public static final int MULTI_WINDOW_MODE_CHANGED = 152;
public static final int PICTURE_IN_PICTURE_MODE_CHANGED = 153;
public static final int LOCAL_VOICE_INTERACTION_STARTED = 154;
+ public static final int ATTACH_AGENT = 155;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
@@ -1461,6 +1469,7 @@ public final class ActivityThread {
case MULTI_WINDOW_MODE_CHANGED: return "MULTI_WINDOW_MODE_CHANGED";
case PICTURE_IN_PICTURE_MODE_CHANGED: return "PICTURE_IN_PICTURE_MODE_CHANGED";
case LOCAL_VOICE_INTERACTION_STARTED: return "LOCAL_VOICE_INTERACTION_STARTED";
+ case ATTACH_AGENT: return "ATTACH_AGENT";
}
}
return Integer.toString(code);
@@ -1716,6 +1725,9 @@ public final class ActivityThread {
handleLocalVoiceInteractionStarted((IBinder) ((SomeArgs) msg.obj).arg1,
(IVoiceInteractor) ((SomeArgs) msg.obj).arg2);
break;
+ case ATTACH_AGENT:
+ handleAttachAgent((String) msg.obj);
+ break;
}
Object obj = msg.obj;
if (obj instanceof SomeArgs) {
@@ -2984,6 +2996,14 @@ public final class ActivityThread {
}
}
+ static final void handleAttachAgent(String agent) {
+ try {
+ VMDebug.attachAgent(agent);
+ } catch (IOException e) {
+ Slog.e(TAG, "Attaching agent failed: " + agent);
+ }
+ }
+
private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>();
/**
@@ -5109,6 +5129,7 @@ public final class ActivityThread {
mProfiler.profileFd = data.initProfilerInfo.profileFd;
mProfiler.samplingInterval = data.initProfilerInfo.samplingInterval;
mProfiler.autoStopProfiler = data.initProfilerInfo.autoStopProfiler;
+ mProfiler.streamingOutput = data.initProfilerInfo.streamingOutput;
}
// send up app name; do this *before* waiting for debugger
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 05d9d7e412f0..ad7f577f1e1d 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -502,6 +502,14 @@ public abstract class ApplicationThreadNative extends Binder
return true;
}
+ case ATTACH_AGENT_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ String agent = data.readString();
+ attachAgent(agent);
+ return true;
+ }
+
case DUMP_ACTIVITY_TRANSACTION: {
data.enforceInterface(IApplicationThread.descriptor);
ParcelFileDescriptor fd = data.readFileDescriptor();
@@ -1305,6 +1313,14 @@ class ApplicationThreadProxy implements IApplicationThread {
data.recycle();
}
+ public void attachAgent(String agent) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeString(agent);
+ mRemote.transact(ATTACH_AGENT_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+ data.recycle();
+ }
+
public void setCoreSettings(Bundle coreSettings) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 3fa88ae674a4..bfd97f8a2b27 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -123,6 +123,7 @@ public interface IApplicationThread extends IInterface {
throws RemoteException;
void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd)
throws RemoteException;
+ void attachAgent(String path) throws RemoteException;
void setSchedulingGroup(int group) throws RemoteException;
// the package has been removed, clean up internal references
static final int PACKAGE_REMOVED = 0;
@@ -225,4 +226,5 @@ public interface IApplicationThread extends IInterface {
int SCHEDULE_MULTI_WINDOW_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+58;
int SCHEDULE_PICTURE_IN_PICTURE_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+59;
int SCHEDULE_LOCAL_VOICE_INTERACTION_STARTED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+60;
+ int ATTACH_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+61;
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index afe9651d82f5..e00a7f0e4ab9 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -266,7 +266,7 @@ public final class LoadedApk {
setApplicationInfo(aInfo);
final List<String> newPaths = new ArrayList<>();
- makePaths(mActivityThread, aInfo, newPaths, null /*libPaths*/);
+ makePaths(mActivityThread, aInfo, newPaths);
final List<String> addedPaths = new ArrayList<>(newPaths.size());
if (oldPaths != null) {
@@ -314,8 +314,17 @@ public final class LoadedApk {
mCredentialProtectedDataDirFile = FileUtils.newFileOrNull(aInfo.credentialProtectedDataDir);
}
- public static void makePaths(ActivityThread activityThread, ApplicationInfo aInfo,
- List<String> outZipPaths, List<String> outLibPaths) {
+ public static void makePaths(ActivityThread activityThread,
+ ApplicationInfo aInfo,
+ List<String> outZipPaths) {
+ makePaths(activityThread, false, aInfo, outZipPaths, null);
+ }
+
+ public static void makePaths(ActivityThread activityThread,
+ boolean isBundledApp,
+ ApplicationInfo aInfo,
+ List<String> outZipPaths,
+ List<String> outLibPaths) {
final String appDir = aInfo.sourceDir;
final String[] splitAppDirs = aInfo.splitSourceDirs;
final String libDir = aInfo.nativeLibraryDir;
@@ -398,7 +407,7 @@ public final class LoadedApk {
}
}
- if (aInfo.isSystemApp() && !aInfo.isUpdatedSystemApp()) {
+ if (isBundledApp) {
// Add path to system libraries to libPaths;
// Access to system libs should be limited
// to bundled applications; this is why updated
@@ -471,11 +480,12 @@ public final class LoadedApk {
// space and initialize to a small value (instead of incurring growth code).
final List<String> zipPaths = new ArrayList<>(10);
final List<String> libPaths = new ArrayList<>(10);
- makePaths(mActivityThread, mApplicationInfo, zipPaths, libPaths);
final boolean isBundledApp = mApplicationInfo.isSystemApp()
&& !mApplicationInfo.isUpdatedSystemApp();
+ makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths);
+
String libraryPermittedPath = mDataDir;
if (isBundledApp) {
// This is necessary to grant bundled apps access to
diff --git a/core/java/android/app/ProfilerInfo.java b/core/java/android/app/ProfilerInfo.java
index cea7c3cbe8c3..f3fe6778375b 100644
--- a/core/java/android/app/ProfilerInfo.java
+++ b/core/java/android/app/ProfilerInfo.java
@@ -39,11 +39,16 @@ public class ProfilerInfo implements Parcelable {
/* Automatically stop the profiler when the app goes idle. */
public final boolean autoStopProfiler;
- public ProfilerInfo(String filename, ParcelFileDescriptor fd, int interval, boolean autoStop) {
+ /* Indicates whether to stream the profiling info to the out file continuously. */
+ public final boolean streamingOutput;
+
+ public ProfilerInfo(String filename, ParcelFileDescriptor fd, int interval, boolean autoStop,
+ boolean streaming) {
profileFile = filename;
profileFd = fd;
samplingInterval = interval;
autoStopProfiler = autoStop;
+ streamingOutput = streaming;
}
public int describeContents() {
@@ -64,6 +69,7 @@ public class ProfilerInfo implements Parcelable {
}
out.writeInt(samplingInterval);
out.writeInt(autoStopProfiler ? 1 : 0);
+ out.writeInt(streamingOutput ? 1 : 0);
}
public static final Parcelable.Creator<ProfilerInfo> CREATOR =
@@ -82,5 +88,6 @@ public class ProfilerInfo implements Parcelable {
profileFd = in.readInt() != 0 ? ParcelFileDescriptor.CREATOR.createFromParcel(in) : null;
samplingInterval = in.readInt();
autoStopProfiler = in.readInt() != 0;
+ streamingOutput = in.readInt() != 0;
}
}
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 1165fce3ce0a..4960159db212 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -105,10 +105,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
* Intent used to broadcast the change in the Audio Codec state of the
* A2DP Source profile.
*
- * <p>This intent will have 3 extras:
+ * <p>This intent will have 2 extras:
* <ul>
- * <li> {@link #EXTRA_CODEC_CONFIG} - The current codec configuration. </li>
- * <li> {@link #EXTRA_PREVIOUS_CODEC_CONFIG} - The previous codec configuration. </li>
+ * <li> {@link BluetoothCodecStatus#EXTRA_CODEC_STATUS} - The codec status. </li>
* <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device if the device is currently
* connected, otherwise it is not included.</li>
* </ul>
@@ -564,24 +563,24 @@ public final class BluetoothA2dp implements BluetoothProfile {
}
/**
- * Gets the current codec configuration.
+ * Gets the current codec status (configuration and capability).
*
- * @return the current codec configuration
+ * @return the current codec status
* @hide
*/
- public BluetoothCodecConfig getCodecConfig() {
- if (DBG) Log.d(TAG, "getCodecConfig");
+ public BluetoothCodecStatus getCodecStatus() {
+ if (DBG) Log.d(TAG, "getCodecStatus");
try {
mServiceLock.readLock().lock();
if (mService != null && isEnabled()) {
- return mService.getCodecConfig();
+ return mService.getCodecStatus();
}
if (mService == null) {
Log.w(TAG, "Proxy not attached to service");
}
return null;
} catch (RemoteException e) {
- Log.e(TAG, "Error talking to BT service in getCodecConfig()", e);
+ Log.e(TAG, "Error talking to BT service in getCodecStatus()", e);
return null;
} finally {
mServiceLock.readLock().unlock();
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index f9be3a1d7f0b..9302cbc480e1 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1184,6 +1184,25 @@ public final class BluetoothAdapter {
}
/**
+ * Get the end time of the latest remote device discovery process.
+ * @return the latest time that the bluetooth adapter was/will be in discovery mode,
+ * in milliseconds since the epoch.
+ * This time can be in the future if {@link #startDiscovery()} has been called recently.
+ * @hide
+ */
+ public long getDiscoveryEndMillis() {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) return mService.getDiscoveryEndMillis();
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return -1;
+ }
+
+ /**
* Start the remote device discovery process.
* <p>The discovery process usually involves an inquiry scan of about 12
* seconds, followed by a page scan of each new device to retrieve its
diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java
index 52cd2de4c2b6..176e48fb6e08 100644
--- a/core/java/android/bluetooth/BluetoothCodecConfig.java
+++ b/core/java/android/bluetooth/BluetoothCodecConfig.java
@@ -29,34 +29,19 @@ import java.util.Objects;
* {@hide}
*/
public final class BluetoothCodecConfig implements Parcelable {
-
- /**
- * Extra for the codec configuration intents of the individual profiles.
- *
- * This extra represents the current codec configuration of the A2DP
- * profile.
- */
- public static final String EXTRA_CODEC_CONFIG = "android.bluetooth.codec.extra.CODEC_CONFIG";
-
- /**
- * Extra for the codec configuration intents of the individual profiles.
- *
- * This extra represents the previous codec configuration of the A2DP
- * profile.
- */
- public static final String EXTRA_PREVIOUS_CODEC_CONFIG =
- "android.bluetooth.codec.extra.PREVIOUS_CODEC_CONFIG";
-
// Add an entry for each source codec here.
// NOTE: The values should be same as those listed in the following file:
// hardware/libhardware/include/hardware/bt_av.h
public static final int SOURCE_CODEC_TYPE_SBC = 0;
- public static final int SOURCE_CODEC_TYPE_APTX = 1;
- public static final int SOURCE_CODEC_TYPE_APTX_HD = 2;
- public static final int SOURCE_CODEC_TYPE_LDAC = 3;
+ public static final int SOURCE_CODEC_TYPE_AAC = 1;
+ public static final int SOURCE_CODEC_TYPE_APTX = 2;
+ public static final int SOURCE_CODEC_TYPE_APTX_HD = 3;
+ public static final int SOURCE_CODEC_TYPE_LDAC = 4;
+ public static final int SOURCE_CODEC_TYPE_MAX = 5;
public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000;
+ public static final int CODEC_PRIORITY_DISABLED = -1;
public static final int CODEC_PRIORITY_DEFAULT = 0;
public static final int CODEC_PRIORITY_HIGHEST = 1000 * 1000;
@@ -89,7 +74,7 @@ public final class BluetoothCodecConfig implements Parcelable {
public BluetoothCodecConfig(int codecType, int codecPriority,
int sampleRate, int bitsPerSample,
- int channelMode,long codecSpecific1,
+ int channelMode, long codecSpecific1,
long codecSpecific2, long codecSpecific3,
long codecSpecific4) {
mCodecType = codecType;
@@ -127,13 +112,93 @@ public final class BluetoothCodecConfig implements Parcelable {
mCodecSpecific2, mCodecSpecific3, mCodecSpecific4);
}
+ /**
+ * Checks whether the object contains valid codec configuration.
+ *
+ * @return true if the object contains valid codec configuration,
+ * otherwise false.
+ */
+ public boolean isValid() {
+ return (mSampleRate != SAMPLE_RATE_NONE) &&
+ (mBitsPerSample != BITS_PER_SAMPLE_NONE) &&
+ (mChannelMode != CHANNEL_MODE_NONE);
+ }
+
+ /**
+ * Adds capability string to an existing string.
+ *
+ * @param prevStr the previous string with the capabilities. Can be
+ * a null pointer.
+ * @param capStr the capability string to append to prevStr argument.
+ * @return the result string in the form "prevStr|capStr".
+ */
+ private static String appendCapabilityToString(String prevStr,
+ String capStr) {
+ if (prevStr == null) {
+ return capStr;
+ }
+ return prevStr + "|" + capStr;
+ }
+
@Override
public String toString() {
- return "{mCodecType:" + mCodecType +
+ String sampleRateStr = null;
+ if (mSampleRate == SAMPLE_RATE_NONE) {
+ sampleRateStr = appendCapabilityToString(sampleRateStr, "NONE");
+ }
+ if ((mSampleRate & SAMPLE_RATE_44100) != 0) {
+ sampleRateStr = appendCapabilityToString(sampleRateStr, "44100");
+ }
+ if ((mSampleRate & SAMPLE_RATE_48000) != 0) {
+ sampleRateStr = appendCapabilityToString(sampleRateStr, "48000");
+ }
+ if ((mSampleRate & SAMPLE_RATE_88200) != 0) {
+ sampleRateStr = appendCapabilityToString(sampleRateStr, "88200");
+ }
+ if ((mSampleRate & SAMPLE_RATE_96000) != 0) {
+ sampleRateStr = appendCapabilityToString(sampleRateStr, "96000");
+ }
+ if ((mSampleRate & SAMPLE_RATE_176400) != 0) {
+ sampleRateStr = appendCapabilityToString(sampleRateStr, "176400");
+ }
+ if ((mSampleRate & SAMPLE_RATE_192000) != 0) {
+ sampleRateStr = appendCapabilityToString(sampleRateStr, "192000");
+ }
+
+ String bitsPerSampleStr = null;
+ if (mBitsPerSample == BITS_PER_SAMPLE_NONE) {
+ bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "NONE");
+ }
+ if ((mBitsPerSample & BITS_PER_SAMPLE_16) != 0) {
+ bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "16");
+ }
+ if ((mBitsPerSample & BITS_PER_SAMPLE_24) != 0) {
+ bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "24");
+ }
+ if ((mBitsPerSample & BITS_PER_SAMPLE_32) != 0) {
+ bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "32");
+ }
+
+ String channelModeStr = null;
+ if (mChannelMode == CHANNEL_MODE_NONE) {
+ channelModeStr = appendCapabilityToString(channelModeStr, "NONE");
+ }
+ if ((mChannelMode & CHANNEL_MODE_MONO) != 0) {
+ channelModeStr = appendCapabilityToString(channelModeStr, "MONO");
+ }
+ if ((mChannelMode & CHANNEL_MODE_STEREO) != 0) {
+ channelModeStr = appendCapabilityToString(channelModeStr, "STEREO");
+ }
+
+ return "{codecName:" + getCodecName() +
+ ",mCodecType:" + mCodecType +
",mCodecPriority:" + mCodecPriority +
",mSampleRate:" + String.format("0x%x", mSampleRate) +
+ "(" + sampleRateStr + ")" +
",mBitsPerSample:" + String.format("0x%x", mBitsPerSample) +
+ "(" + bitsPerSampleStr + ")" +
",mChannelMode:" + String.format("0x%x", mChannelMode) +
+ "(" + channelModeStr + ")" +
",mCodecSpecific1:" + mCodecSpecific1 +
",mCodecSpecific2:" + mCodecSpecific2 +
",mCodecSpecific3:" + mCodecSpecific3 +
@@ -180,7 +245,32 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns the codec type.
+ * Gets the codec name.
+ *
+ * @return the codec name
+ */
+ public String getCodecName() {
+ switch (mCodecType) {
+ case SOURCE_CODEC_TYPE_SBC:
+ return "SBC";
+ case SOURCE_CODEC_TYPE_AAC:
+ return "AAC";
+ case SOURCE_CODEC_TYPE_APTX:
+ return "aptX";
+ case SOURCE_CODEC_TYPE_APTX_HD:
+ return "aptX HD";
+ case SOURCE_CODEC_TYPE_LDAC:
+ return "LDAC";
+ case SOURCE_CODEC_TYPE_INVALID:
+ return "INVALID CODEC";
+ default:
+ break;
+ }
+ return "UNKNOWN CODEC(" + mCodecType + ")";
+ }
+
+ /**
+ * Gets the codec type.
* See {@link android.bluetooth.BluetoothCodecConfig#SOURCE_CODEC_TYPE_SBC}.
*
* @return the codec type
@@ -190,7 +280,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns the codec selection priority.
+ * Gets the codec selection priority.
* The codec selection priority is relative to other codecs: larger value
* means higher priority. If 0, reset to default.
*
@@ -201,7 +291,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns the codec sample rate. The value can be a bitmask with all
+ * Gets the codec sample rate. The value can be a bitmask with all
* supported sample rates:
* {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_NONE} or
* {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_44100} or
@@ -218,7 +308,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns the codec bits per sample. The value can be a bitmask with all
+ * Gets the codec bits per sample. The value can be a bitmask with all
* bits per sample supported:
* {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_NONE} or
* {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_16} or
@@ -232,7 +322,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns the codec channel mode. The value can be a bitmask with all
+ * Gets the codec channel mode. The value can be a bitmask with all
* supported channel modes:
* {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_NONE} or
* {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_MONO} or
@@ -245,7 +335,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns a codec specific value1.
+ * Gets a codec specific value1.
*
* @return a codec specific value1.
*/
@@ -254,7 +344,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns a codec specific value2.
+ * Gets a codec specific value2.
*
* @return a codec specific value2
*/
@@ -263,7 +353,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns a codec specific value3.
+ * Gets a codec specific value3.
*
* @return a codec specific value3
*/
@@ -272,7 +362,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns a codec specific value4.
+ * Gets a codec specific value4.
*
* @return a codec specific value4
*/
diff --git a/core/java/android/bluetooth/BluetoothCodecStatus.aidl b/core/java/android/bluetooth/BluetoothCodecStatus.aidl
new file mode 100644
index 000000000000..f9c3a3de2f4c
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothCodecStatus.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothCodecStatus;
diff --git a/core/java/android/bluetooth/BluetoothCodecStatus.java b/core/java/android/bluetooth/BluetoothCodecStatus.java
new file mode 100644
index 000000000000..c8cd8d17ce36
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothCodecStatus.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Represents the codec status (configuration and capability) for a Bluetooth
+ * A2DP source device.
+ *
+ * {@see BluetoothA2dp}
+ *
+ * {@hide}
+ */
+public final class BluetoothCodecStatus implements Parcelable {
+ /**
+ * Extra for the codec configuration intents of the individual profiles.
+ *
+ * This extra represents the current codec status of the A2DP
+ * profile.
+ */
+ public static final String EXTRA_CODEC_STATUS =
+ "android.bluetooth.codec.extra.CODEC_STATUS";
+
+ private final BluetoothCodecConfig mCodecConfig;
+ private final BluetoothCodecConfig[] mCodecsLocalCapabilities;
+ private final BluetoothCodecConfig[] mCodecsSelectableCapabilities;
+
+ public BluetoothCodecStatus(BluetoothCodecConfig codecConfig,
+ BluetoothCodecConfig[] codecsLocalCapabilities,
+ BluetoothCodecConfig[] codecsSelectableCapabilities) {
+ mCodecConfig = codecConfig;
+ mCodecsLocalCapabilities = codecsLocalCapabilities;
+ mCodecsSelectableCapabilities = codecsSelectableCapabilities;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof BluetoothCodecStatus) {
+ BluetoothCodecStatus other = (BluetoothCodecStatus)o;
+ return (Objects.equals(other.mCodecConfig, mCodecConfig) &&
+ Objects.equals(other.mCodecsLocalCapabilities,
+ mCodecsLocalCapabilities) &&
+ Objects.equals(other.mCodecsSelectableCapabilities,
+ mCodecsSelectableCapabilities));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mCodecConfig, mCodecsLocalCapabilities,
+ mCodecsLocalCapabilities);
+ }
+
+ @Override
+ public String toString() {
+ return "{mCodecConfig:" + mCodecConfig +
+ ",mCodecsLocalCapabilities:" + Arrays.toString(mCodecsLocalCapabilities) +
+ ",mCodecsSelectableCapabilities:" + Arrays.toString(mCodecsSelectableCapabilities) +
+ "}";
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<BluetoothCodecStatus> CREATOR =
+ new Parcelable.Creator<BluetoothCodecStatus>() {
+ public BluetoothCodecStatus createFromParcel(Parcel in) {
+ final BluetoothCodecConfig codecConfig = in.readTypedObject(BluetoothCodecConfig.CREATOR);
+ final BluetoothCodecConfig[] codecsLocalCapabilities = in.createTypedArray(BluetoothCodecConfig.CREATOR);
+ final BluetoothCodecConfig[] codecsSelectableCapabilities = in.createTypedArray(BluetoothCodecConfig.CREATOR);
+
+ return new BluetoothCodecStatus(codecConfig,
+ codecsLocalCapabilities,
+ codecsSelectableCapabilities);
+ }
+ public BluetoothCodecStatus[] newArray(int size) {
+ return new BluetoothCodecStatus[size];
+ }
+ };
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeTypedObject(mCodecConfig, 0);
+ out.writeTypedArray(mCodecsLocalCapabilities, 0);
+ out.writeTypedArray(mCodecsSelectableCapabilities, 0);
+ }
+
+ /**
+ * Gets the current codec configuration.
+ *
+ * @return the current codec configuration
+ */
+ public BluetoothCodecConfig getCodecConfig() {
+ return mCodecConfig;
+ }
+
+ /**
+ * Gets the codecs local capabilities.
+ *
+ * @return an array with the codecs local capabilities
+ */
+ public BluetoothCodecConfig[] getCodecsLocalCapabilities() {
+ return mCodecsLocalCapabilities;
+ }
+
+ /**
+ * Gets the codecs selectable capabilities.
+ *
+ * @return an array with the codecs selectable capabilities
+ */
+ public BluetoothCodecConfig[] getCodecsSelectableCapabilities() {
+ return mCodecsSelectableCapabilities;
+ }
+}
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 7c5458b7704b..53fef2add344 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -52,6 +52,7 @@ interface IBluetooth
boolean startDiscovery();
boolean cancelDiscovery();
boolean isDiscovering();
+ long getDiscoveryEndMillis();
int getAdapterConnectionState();
int getProfileConnectionState(int profile);
diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl
index 5b524eb18a5e..dbb5b7d7944b 100644
--- a/core/java/android/bluetooth/IBluetoothA2dp.aidl
+++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl
@@ -17,6 +17,7 @@
package android.bluetooth;
import android.bluetooth.BluetoothCodecConfig;
+import android.bluetooth.BluetoothCodecStatus;
import android.bluetooth.BluetoothDevice;
/**
@@ -37,6 +38,6 @@ interface IBluetoothA2dp {
oneway void adjustAvrcpAbsoluteVolume(int direction);
oneway void setAvrcpAbsoluteVolume(int volume);
boolean isA2dpPlaying(in BluetoothDevice device);
- BluetoothCodecConfig getCodecConfig();
+ BluetoothCodecStatus getCodecStatus();
oneway void setCodecConfigPreference(in BluetoothCodecConfig codecConfig);
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c6aaa48ddad0..b7876d99bcba 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1096,6 +1096,15 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_SIM_ACTIVATION_REQUEST =
"android.intent.action.SIM_ACTIVATION_REQUEST";
/**
+ * Activity Action: Main entry point for carrier setup apps.
+ * <p>Carrier apps that provide an implementation for this action may be invoked to configure
+ * carrier service and typically require
+ * {@link android.telephony.TelephonyManager#hasCarrierPrivileges() carrier privileges} to
+ * fulfill their duties.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
+ /**
* Activity Action: Send a message to someone specified by the data.
* <p>Input: {@link #getData} is URI describing the target.
* <p>Output: nothing.
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index f35b13d44474..c51945e4e27d 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -563,6 +563,7 @@ interface IPackageManager {
void addOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
void grantDefaultPermissionsToEnabledCarrierApps(in String[] packageNames, int userId);
+ void grantDefaultPermissionsToEnabledImsServices(in String[] packageNames, int userId);
boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId);
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index bb0a04279904..5423ca97eb28 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -646,7 +646,7 @@ public class LegacyMetadataMapper {
// Special case where the only scene mode listed is AUTO => no scene mode
if (sceneModes != null && sceneModes.size() == 1 &&
- sceneModes.get(0) == Parameters.SCENE_MODE_AUTO) {
+ sceneModes.get(0).equals(Parameters.SCENE_MODE_AUTO)) {
supportedSceneModes = null;
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 042481f1727e..30afdc2768c5 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -46,6 +46,7 @@ import android.telephony.SubscriptionManager;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.PhoneConstants;
@@ -1219,36 +1220,27 @@ public class ConnectivityManager {
private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) {
if (networkType == TYPE_MOBILE) {
- int cap = -1;
- if ("enableMMS".equals(feature)) {
- cap = NetworkCapabilities.NET_CAPABILITY_MMS;
- } else if ("enableSUPL".equals(feature)) {
- cap = NetworkCapabilities.NET_CAPABILITY_SUPL;
- } else if ("enableDUN".equals(feature) || "enableDUNAlways".equals(feature)) {
- cap = NetworkCapabilities.NET_CAPABILITY_DUN;
- } else if ("enableHIPRI".equals(feature)) {
- cap = NetworkCapabilities.NET_CAPABILITY_INTERNET;
- } else if ("enableFOTA".equals(feature)) {
- cap = NetworkCapabilities.NET_CAPABILITY_FOTA;
- } else if ("enableIMS".equals(feature)) {
- cap = NetworkCapabilities.NET_CAPABILITY_IMS;
- } else if ("enableCBS".equals(feature)) {
- cap = NetworkCapabilities.NET_CAPABILITY_CBS;
- } else {
- return null;
- }
- NetworkCapabilities netCap = new NetworkCapabilities();
- netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).addCapability(cap);
- netCap.maybeMarkCapabilitiesRestricted();
- return netCap;
- } else if (networkType == TYPE_WIFI) {
- if ("p2p".equals(feature)) {
- NetworkCapabilities netCap = new NetworkCapabilities();
- netCap.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P);
- netCap.maybeMarkCapabilitiesRestricted();
- return netCap;
+ switch (feature) {
+ case "enableCBS":
+ return networkCapabilitiesForType(TYPE_MOBILE_CBS);
+ case "enableDUN":
+ case "enableDUNAlways":
+ return networkCapabilitiesForType(TYPE_MOBILE_DUN);
+ case "enableFOTA":
+ return networkCapabilitiesForType(TYPE_MOBILE_FOTA);
+ case "enableHIPRI":
+ return networkCapabilitiesForType(TYPE_MOBILE_HIPRI);
+ case "enableIMS":
+ return networkCapabilitiesForType(TYPE_MOBILE_IMS);
+ case "enableMMS":
+ return networkCapabilitiesForType(TYPE_MOBILE_MMS);
+ case "enableSUPL":
+ return networkCapabilitiesForType(TYPE_MOBILE_SUPL);
+ default:
+ return null;
}
+ } else if (networkType == TYPE_WIFI && "p2p".equals(feature)) {
+ return networkCapabilitiesForType(TYPE_WIFI_P2P);
}
return null;
}
@@ -1429,8 +1421,8 @@ public class ConnectivityManager {
l.networkCapabilities = netCap;
l.delay = delay;
l.expireSequenceNumber = 0;
- l.networkRequest = sendRequestForNetwork(netCap, l.networkCallback, 0,
- REQUEST, type);
+ l.networkRequest = sendRequestForNetwork(
+ netCap, l.networkCallback, 0, REQUEST, type, getDefaultHandler());
if (l.networkRequest == null) return null;
sLegacyRequests.put(netCap, l);
sendExpireMsgForFeature(netCap, l.expireSequenceNumber, delay);
@@ -1440,8 +1432,9 @@ public class ConnectivityManager {
private void sendExpireMsgForFeature(NetworkCapabilities netCap, int seqNum, int delay) {
if (delay >= 0) {
Log.d(TAG, "sending expire msg with seqNum " + seqNum + " and delay " + delay);
- Message msg = sCallbackHandler.obtainMessage(EXPIRE_LEGACY_REQUEST, seqNum, 0, netCap);
- sCallbackHandler.sendMessageDelayed(msg, delay);
+ CallbackHandler handler = getDefaultHandler();
+ Message msg = handler.obtainMessage(EXPIRE_LEGACY_REQUEST, seqNum, 0, netCap);
+ handler.sendMessageDelayed(msg, delay);
}
}
@@ -1456,6 +1449,59 @@ public class ConnectivityManager {
return true;
}
+ private static final SparseIntArray sLegacyTypeToTransport = new SparseIntArray();
+ static {
+ sLegacyTypeToTransport.put(TYPE_MOBILE, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_MOBILE_CBS, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_MOBILE_DUN, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_MOBILE_FOTA, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_MOBILE_HIPRI, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_MOBILE_IMS, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_MOBILE_MMS, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_MOBILE_SUPL, NetworkCapabilities.TRANSPORT_CELLULAR);
+ sLegacyTypeToTransport.put(TYPE_WIFI, NetworkCapabilities.TRANSPORT_WIFI);
+ sLegacyTypeToTransport.put(TYPE_WIFI_P2P, NetworkCapabilities.TRANSPORT_WIFI);
+ sLegacyTypeToTransport.put(TYPE_BLUETOOTH, NetworkCapabilities.TRANSPORT_BLUETOOTH);
+ sLegacyTypeToTransport.put(TYPE_ETHERNET, NetworkCapabilities.TRANSPORT_ETHERNET);
+ }
+
+ private static final SparseIntArray sLegacyTypeToCapability = new SparseIntArray();
+ static {
+ sLegacyTypeToCapability.put(TYPE_MOBILE_CBS, NetworkCapabilities.NET_CAPABILITY_CBS);
+ sLegacyTypeToCapability.put(TYPE_MOBILE_DUN, NetworkCapabilities.NET_CAPABILITY_DUN);
+ sLegacyTypeToCapability.put(TYPE_MOBILE_FOTA, NetworkCapabilities.NET_CAPABILITY_FOTA);
+ sLegacyTypeToCapability.put(TYPE_MOBILE_IMS, NetworkCapabilities.NET_CAPABILITY_IMS);
+ sLegacyTypeToCapability.put(TYPE_MOBILE_MMS, NetworkCapabilities.NET_CAPABILITY_MMS);
+ sLegacyTypeToCapability.put(TYPE_MOBILE_SUPL, NetworkCapabilities.NET_CAPABILITY_SUPL);
+ sLegacyTypeToCapability.put(TYPE_WIFI_P2P, NetworkCapabilities.NET_CAPABILITY_WIFI_P2P);
+ }
+
+ /**
+ * Given a legacy type (TYPE_WIFI, ...) returns a NetworkCapabilities
+ * instance suitable for registering a request or callback. Throws an
+ * IllegalArgumentException if no mapping from the legacy type to
+ * NetworkCapabilities is known.
+ *
+ * @hide
+ */
+ public static NetworkCapabilities networkCapabilitiesForType(int type) {
+ final NetworkCapabilities nc = new NetworkCapabilities();
+
+ // Map from type to transports.
+ final int NOT_FOUND = -1;
+ final int transport = sLegacyTypeToTransport.get(type, NOT_FOUND);
+ if (transport == NOT_FOUND) {
+ throw new IllegalArgumentException("unknown legacy type: " + type);
+ }
+ nc.addTransportType(transport);
+
+ // Map from type to capabilities.
+ nc.addCapability(sLegacyTypeToCapability.get(
+ type, NetworkCapabilities.NET_CAPABILITY_INTERNET));
+ nc.maybeMarkCapabilitiesRestricted();
+ return nc;
+ }
+
/** @hide */
public static class PacketKeepaliveCallback {
/** The requested keepalive was successfully started. */
@@ -2705,6 +2751,10 @@ public class ConnectivityManager {
super(looper);
}
+ CallbackHandler(Handler handler) {
+ this(handler.getLooper());
+ }
+
@Override
public void handleMessage(Message message) {
NetworkRequest request = getObject(message, NetworkRequest.class);
@@ -2814,7 +2864,7 @@ public class ConnectivityManager {
}
}
- private CallbackHandler getHandler() {
+ private CallbackHandler getDefaultHandler() {
synchronized (sCallbacks) {
if (sCallbackHandler == null) {
sCallbackHandler = new CallbackHandler(ConnectivityThread.getInstanceLooper());
@@ -2823,19 +2873,14 @@ public class ConnectivityManager {
}
}
- static final HashMap<NetworkRequest, NetworkCallback> sCallbacks = new HashMap<>();
- static CallbackHandler sCallbackHandler;
+ private static final HashMap<NetworkRequest, NetworkCallback> sCallbacks = new HashMap<>();
+ private static CallbackHandler sCallbackHandler;
- private final static int LISTEN = 1;
- private final static int REQUEST = 2;
+ private static final int LISTEN = 1;
+ private static final int REQUEST = 2;
- private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
- NetworkCallback callback, int timeoutMs, int action, int legacyType) {
- return sendRequestForNetwork(need, callback, getHandler(), timeoutMs, action, legacyType);
- }
-
- private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
- NetworkCallback callback, Handler handler, int timeoutMs, int action, int legacyType) {
+ private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
+ int timeoutMs, int action, int legacyType, CallbackHandler handler) {
if (callback == null) {
throw new IllegalArgumentException("null NetworkCallback");
}
@@ -2878,9 +2923,10 @@ public class ConnectivityManager {
* @hide
*/
public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
- int timeoutMs, int legacyType) {
- sendRequestForNetwork(request.networkCapabilities, networkCallback, timeoutMs, REQUEST,
- legacyType);
+ int timeoutMs, int legacyType, Handler handler) {
+ CallbackHandler cbHandler = new CallbackHandler(handler);
+ NetworkCapabilities nc = request.networkCapabilities;
+ sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, legacyType, cbHandler);
}
/**
@@ -2906,15 +2952,51 @@ public class ConnectivityManager {
* {@link android.provider.Settings.System#canWrite}.</p>
*
* @param request {@link NetworkRequest} describing this request.
- * @param networkCallback The {@link NetworkCallback} to be utilized for this
- * request. Note the callback must not be shared - they
- * uniquely specify this request.
+ * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+ * the callback must not be shared - it uniquely specifies this request.
+ * The callback is invoked on the default internal Handler.
* @throws IllegalArgumentException if {@code request} specifies any mutable
* {@code NetworkCapabilities}.
*/
public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback) {
- requestNetwork(request, networkCallback, 0,
- inferLegacyTypeForNetworkCapabilities(request.networkCapabilities));
+ requestNetwork(request, networkCallback, getDefaultHandler());
+ }
+
+ /**
+ * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
+ *
+ * This {@link NetworkRequest} will live until released via
+ * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits.
+ * Status of the request can be followed by listening to the various
+ * callbacks described in {@link NetworkCallback}. The {@link Network}
+ * can be used to direct traffic to the network.
+ * <p>It is presently unsupported to request a network with mutable
+ * {@link NetworkCapabilities} such as
+ * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
+ * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}
+ * as these {@code NetworkCapabilities} represent states that a particular
+ * network may never attain, and whether a network will attain these states
+ * is unknown prior to bringing up the network so the framework does not
+ * know how to go about satisfing a request with these capabilities.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
+ *
+ * @param request {@link NetworkRequest} describing this request.
+ * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+ * the callback must not be shared - it uniquely specifies this request.
+ * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * @throws IllegalArgumentException if {@code request} specifies any mutable
+ * {@code NetworkCapabilities}.
+ * @hide
+ */
+ public void requestNetwork(
+ NetworkRequest request, NetworkCallback networkCallback, Handler handler) {
+ int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
+ CallbackHandler cbHandler = new CallbackHandler(handler);
+ requestNetwork(request, networkCallback, 0, legacyType, cbHandler);
}
/**
@@ -2923,8 +3005,8 @@ public class ConnectivityManager {
*
* This function behaves identically to the non-timedout version, but if a suitable
* network is not found within the given time (in milliseconds) the
- * {@link NetworkCallback#unavailable} callback is called. The request must
- * still be released normally by calling {@link unregisterNetworkCallback(NetworkCallback)}.
+ * {@link NetworkCallback#onUnavailable()} callback is called. The request must
+ * still be released normally by calling {@link #unregisterNetworkCallback(NetworkCallback)}.
*
* <p>This method requires the caller to hold either the
* {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
@@ -2932,28 +3014,49 @@ public class ConnectivityManager {
* {@link android.provider.Settings.System#canWrite}.</p>
*
* @param request {@link NetworkRequest} describing this request.
- * @param networkCallback The callbacks to be utilized for this request. Note
- * the callbacks must not be shared - they uniquely specify
- * this request.
+ * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+ * the callback must not be shared - it uniquely specifies this request.
+ * The callback is invoked on the default internal Handler.
* @param timeoutMs The time in milliseconds to attempt looking for a suitable network
- * before {@link NetworkCallback#unavailable} is called.
- *
- * TODO: Make timeouts work and then unhide this method.
- *
+ * before {@link NetworkCallback#onUnavailable()} is called.
* @hide
*/
public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
int timeoutMs) {
- requestNetwork(request, networkCallback, timeoutMs,
- inferLegacyTypeForNetworkCapabilities(request.networkCapabilities));
+ int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
+ requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
}
+
/**
- * The maximum number of milliseconds the framework will look for a suitable network
- * during a timeout-equiped call to {@link requestNetwork}.
- * {@hide}
+ * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
+ * by a timeout.
+ *
+ * This function behaves identically to the non-timedout version, but if a suitable
+ * network is not found within the given time (in milliseconds) the
+ * {@link NetworkCallback#onUnavailable} callback is called. The request must
+ * still be released normally by calling {@link unregisterNetworkCallback(NetworkCallback)}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
+ *
+ * @param request {@link NetworkRequest} describing this request.
+ * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+ * the callback must not be shared - it uniquely specifies this request.
+ * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
+ * before {@link NetworkCallback#onUnavailable} is called.
+ * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ *
+ * @hide
*/
- public final static int MAX_NETWORK_REQUEST_TIMEOUT_MS = 100 * 60 * 1000;
+ public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
+ int timeoutMs, Handler handler) {
+ int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
+ CallbackHandler cbHandler = new CallbackHandler(handler);
+ requestNetwork(request, networkCallback, timeoutMs, legacyType, cbHandler);
+ }
/**
* The lookup key for a {@link Network} object included with the intent after
@@ -3066,9 +3169,30 @@ public class ConnectivityManager {
* @param request {@link NetworkRequest} describing this request.
* @param networkCallback The {@link NetworkCallback} that the system will call as suitable
* networks change state.
+ * The callback is invoked on the default internal Handler.
*/
public void registerNetworkCallback(NetworkRequest request, NetworkCallback networkCallback) {
- sendRequestForNetwork(request.networkCapabilities, networkCallback, 0, LISTEN, TYPE_NONE);
+ registerNetworkCallback(request, networkCallback, getDefaultHandler());
+ }
+
+ /**
+ * Registers to receive notifications about all networks which satisfy the given
+ * {@link NetworkRequest}. The callbacks will continue to be called until
+ * either the application exits or link #unregisterNetworkCallback(NetworkCallback)} is called.
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ *
+ * @param request {@link NetworkRequest} describing this request.
+ * @param networkCallback The {@link NetworkCallback} that the system will call as suitable
+ * networks change state.
+ * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * @hide
+ */
+ public void registerNetworkCallback(
+ NetworkRequest request, NetworkCallback networkCallback, Handler handler) {
+ CallbackHandler cbHandler = new CallbackHandler(handler);
+ NetworkCapabilities nc = request.networkCapabilities;
+ sendRequestForNetwork(nc, networkCallback, 0, LISTEN, TYPE_NONE, cbHandler);
}
/**
@@ -3120,8 +3244,25 @@ public class ConnectivityManager {
*
* @param networkCallback The {@link NetworkCallback} that the system will call as the
* system default network changes.
+ * The callback is invoked on the default internal Handler.
*/
public void registerDefaultNetworkCallback(NetworkCallback networkCallback) {
+ registerDefaultNetworkCallback(networkCallback, getDefaultHandler());
+ }
+
+ /**
+ * Registers to receive notifications about changes in the system default network. The callbacks
+ * will continue to be called until either the application exits or
+ * {@link #unregisterNetworkCallback(NetworkCallback)} is called.
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ *
+ * @param networkCallback The {@link NetworkCallback} that the system will call as the
+ * system default network changes.
+ * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * @hide
+ */
+ public void registerDefaultNetworkCallback(NetworkCallback networkCallback, Handler handler) {
// This works because if the NetworkCapabilities are null,
// ConnectivityService takes them from the default request.
//
@@ -3129,7 +3270,8 @@ public class ConnectivityManager {
// capabilities, this request is guaranteed, at all times, to be
// satisfied by the same network, if any, that satisfies the default
// request, i.e., the system default network.
- sendRequestForNetwork(null, networkCallback, 0, REQUEST, TYPE_NONE);
+ CallbackHandler cbHandler = new CallbackHandler(handler);
+ sendRequestForNetwork(null, networkCallback, 0, REQUEST, TYPE_NONE, cbHandler);
}
/**
diff --git a/core/java/android/net/ConnectivityMetricsLogger.java b/core/java/android/net/ConnectivityMetricsLogger.java
index 9a2d4e0a3124..67b6908ed020 100644
--- a/core/java/android/net/ConnectivityMetricsLogger.java
+++ b/core/java/android/net/ConnectivityMetricsLogger.java
@@ -46,32 +46,7 @@ public class ConnectivityMetricsLogger {
public static final String DATA_KEY_EVENTS_COUNT = "count";
- /** {@hide} */ protected IConnectivityMetricsLogger mService;
- /** {@hide} */ protected volatile long mServiceUnblockedTimestampMillis;
- private int mNumSkippedEvents;
-
public ConnectivityMetricsLogger() {
- // TODO: consider not initializing mService in constructor
- this(IConnectivityMetricsLogger.Stub.asInterface(
- ServiceManager.getService(CONNECTIVITY_METRICS_LOGGER_SERVICE)));
- }
-
- /** {@hide} */
- @VisibleForTesting
- public ConnectivityMetricsLogger(IConnectivityMetricsLogger service) {
- mService = service;
- }
-
- /** {@hide} */
- protected boolean checkLoggerService() {
- if (mService != null) {
- return true;
- }
- // Two threads racing here will write the same pointer because getService
- // is idempotent once MetricsLoggerService is initialized.
- mService = IConnectivityMetricsLogger.Stub.asInterface(
- ServiceManager.getService(CONNECTIVITY_METRICS_LOGGER_SERVICE));
- return mService != null;
}
/**
@@ -88,62 +63,6 @@ public class ConnectivityMetricsLogger {
* @param data is a Parcelable instance representing the event.
*/
public void logEvent(long timestamp, int componentTag, int eventTag, Parcelable data) {
- if (mService == null) {
- if (DBG) {
- Log.d(TAG, "logEvent(" + componentTag + "," + eventTag + ") Service not ready");
- }
- return;
- }
-
- if (mServiceUnblockedTimestampMillis > 0) {
- if (System.currentTimeMillis() < mServiceUnblockedTimestampMillis) {
- // Service is throttling events.
- // Don't send new events because they will be dropped.
- mNumSkippedEvents++;
- return;
- }
- }
-
- ConnectivityMetricsEvent skippedEventsEvent = null;
- if (mNumSkippedEvents > 0) {
- // Log number of skipped events
- Bundle b = new Bundle();
- b.putInt(DATA_KEY_EVENTS_COUNT, mNumSkippedEvents);
-
- // Log the skipped event.
- // TODO: Note that some of the clients push all states events into the server,
- // If we lose some states logged here, we might mess up the statistics happened at the
- // backend. One of the options is to introduce a non-skippable flag for important events
- // that are logged.
- skippedEventsEvent = new ConnectivityMetricsEvent(mServiceUnblockedTimestampMillis,
- componentTag, TAG_SKIPPED_EVENTS, b);
-
- mServiceUnblockedTimestampMillis = 0;
- }
-
- ConnectivityMetricsEvent event = new ConnectivityMetricsEvent(timestamp, componentTag,
- eventTag, data);
-
- try {
- long result;
- if (skippedEventsEvent == null) {
- result = mService.logEvent(event);
- } else {
- result = mService.logEvents(new ConnectivityMetricsEvent[]
- {skippedEventsEvent, event});
- }
-
- if (result == 0) {
- mNumSkippedEvents = 0;
- } else {
- mNumSkippedEvents++;
- if (result > 0) { // events are throttled
- mServiceUnblockedTimestampMillis = result;
- }
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Error logging event", e);
- }
}
/**
@@ -157,33 +76,17 @@ public class ConnectivityMetricsLogger {
* @return events
*/
public ConnectivityMetricsEvent[] getEvents(ConnectivityMetricsEvent.Reference reference) {
- try {
- return mService.getEvents(reference);
- } catch (RemoteException e) {
- Log.e(TAG, "IConnectivityMetricsLogger.getEvents", e);
- return null;
- }
+ return new ConnectivityMetricsEvent[0];
}
/**
* Register PendingIntent which will be sent when new events are ready to be retrieved.
*/
public boolean register(PendingIntent newEventsIntent) {
- try {
- return mService.register(newEventsIntent);
- } catch (RemoteException e) {
- Log.e(TAG, "IConnectivityMetricsLogger.register", e);
- return false;
- }
+ return false;
}
public boolean unregister(PendingIntent newEventsIntent) {
- try {
- mService.unregister(newEventsIntent);
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, "IConnectivityMetricsLogger.unregister", e);
- return false;
- }
+ return false;
}
}
diff --git a/core/java/android/net/NetworkRecommendationProvider.java b/core/java/android/net/NetworkRecommendationProvider.java
index 16ae867d81e7..5739c79b8f96 100644
--- a/core/java/android/net/NetworkRecommendationProvider.java
+++ b/core/java/android/net/NetworkRecommendationProvider.java
@@ -5,8 +5,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
-import android.os.Looper;
-import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
@@ -27,8 +25,6 @@ public abstract class NetworkRecommendationProvider {
"android.net.extra.RECOMMENDATION_RESULT";
/** The key into the callback Bundle where the sequence will be found. */
public static final String EXTRA_SEQUENCE = "android.net.extra.SEQUENCE";
- private static final String EXTRA_RECOMMENDATION_REQUEST =
- "android.net.extra.RECOMMENDATION_REQUEST";
private final IBinder mService;
/**
@@ -39,7 +35,7 @@ public abstract class NetworkRecommendationProvider {
if (handler == null) {
throw new IllegalArgumentException("The provided handler cannot be null.");
}
- mService = new ServiceWrapper(new ServiceHandler(handler.getLooper()));
+ mService = new ServiceWrapper(handler);
}
/**
@@ -125,42 +121,10 @@ public abstract class NetworkRecommendationProvider {
}
}
- private final class ServiceHandler extends Handler {
- static final int MSG_GET_RECOMMENDATION = 1;
- static final int MSG_REQUEST_SCORES = 2;
-
- ServiceHandler(Looper looper) {
- super(looper, null /*callback*/, true /*async*/);
- }
-
- @Override
- public void handleMessage(Message msg) {
- final int what = msg.what;
- switch (what) {
- case MSG_GET_RECOMMENDATION:
- final IRemoteCallback callback = (IRemoteCallback) msg.obj;
- final int seq = msg.arg1;
- final RecommendationRequest request =
- msg.getData().getParcelable(EXTRA_RECOMMENDATION_REQUEST);
- final ResultCallback resultCallback = new ResultCallback(callback, seq);
- onRequestRecommendation(request, resultCallback);
- break;
-
- case MSG_REQUEST_SCORES:
- final NetworkKey[] networks = (NetworkKey[]) msg.obj;
- onRequestScores(networks);
- break;
-
- default:
- throw new IllegalArgumentException("Unknown message: " + what);
- }
- }
- }
-
/**
- * A wrapper around INetworkRecommendationProvider that sends calls to the internal Handler.
+ * A wrapper around INetworkRecommendationProvider that dispatches to the provided Handler.
*/
- private static final class ServiceWrapper extends INetworkRecommendationProvider.Stub {
+ private final class ServiceWrapper extends INetworkRecommendationProvider.Stub {
private final Handler mHandler;
ServiceWrapper(Handler handler) {
@@ -168,20 +132,26 @@ public abstract class NetworkRecommendationProvider {
}
@Override
- public void requestRecommendation(RecommendationRequest request, IRemoteCallback callback,
- int sequence) throws RemoteException {
- final Message msg = mHandler.obtainMessage(
- ServiceHandler.MSG_GET_RECOMMENDATION, sequence, 0 /*arg2*/, callback);
- final Bundle data = new Bundle();
- data.putParcelable(EXTRA_RECOMMENDATION_REQUEST, request);
- msg.setData(data);
- msg.sendToTarget();
+ public void requestRecommendation(final RecommendationRequest request,
+ final IRemoteCallback callback, final int sequence) throws RemoteException {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ ResultCallback resultCallback = new ResultCallback(callback, sequence);
+ onRequestRecommendation(request, resultCallback);
+ }
+ });
}
@Override
- public void requestScores(NetworkKey[] networks) throws RemoteException {
+ public void requestScores(final NetworkKey[] networks) throws RemoteException {
if (networks != null && networks.length > 0) {
- mHandler.obtainMessage(ServiceHandler.MSG_REQUEST_SCORES, networks).sendToTarget();
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ onRequestScores(networks);
+ }
+ });
}
}
}
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index ae724709c6c6..cb780090c46a 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -178,6 +178,20 @@ public class NetworkRequest implements Parcelable {
}
/**
+ * Set the {@code NetworkCapabilities} for this builder instance,
+ * overriding any capabilities that had been previously set.
+ *
+ * @param nc The superseding {@code NetworkCapabilities} instance.
+ * @return The builder to facilitate chaining.
+ * @hide
+ */
+ public Builder setCapabilities(NetworkCapabilities nc) {
+ mNetworkCapabilities.clearAll();
+ mNetworkCapabilities.combineCapabilities(nc);
+ return this;
+ }
+
+ /**
* Completely clears all the {@code NetworkCapabilities} from this builder instance,
* removing even the capabilities that are set by default when the object is constructed.
*
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 27096b182c7f..b56437eba167 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -18,6 +18,8 @@ package android.net;
import android.os.SystemProperties;
import android.util.Log;
+
+import com.android.internal.os.RoSystemProperties;
import com.android.org.conscrypt.OpenSSLContextImpl;
import com.android.org.conscrypt.OpenSSLSocketImpl;
import com.android.org.conscrypt.SSLClientSessionCache;
@@ -221,8 +223,8 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
}
private static boolean isSslCheckRelaxed() {
- return "1".equals(SystemProperties.get("ro.debuggable")) &&
- "yes".equals(SystemProperties.get("socket.relaxsslcheck"));
+ return RoSystemProperties.DEBUGGABLE &&
+ SystemProperties.getBoolean("socket.relaxsslcheck", false);
}
private synchronized SSLSocketFactory getDelegate() {
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index 83d17ba7fdd2..bd3231464ccf 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -805,7 +805,7 @@ public final class NdefRecord implements Parcelable {
if (!mb && records.size() == 0 && !inChunk && !ignoreMbMe) {
throw new FormatException("expected MB flag");
- } else if (mb && records.size() != 0 && !ignoreMbMe) {
+ } else if (mb && (records.size() != 0 || inChunk) && !ignoreMbMe) {
throw new FormatException("unexpected MB flag");
} else if (inChunk && il) {
throw new FormatException("unexpected IL flag in non-leading chunk");
@@ -839,6 +839,9 @@ public final class NdefRecord implements Parcelable {
if (cf && !inChunk) {
// first chunk
+ if (typeLength == 0) {
+ throw new FormatException("expected non-zero type length in first chunk");
+ }
chunks.clear();
chunkTnf = tnf;
}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 175d883da29d..e05bd89079af 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1119,8 +1119,8 @@ public final class Debug
* @hide
*/
public static void startMethodTracing(String traceName, FileDescriptor fd,
- int bufferSize, int flags) {
- VMDebug.startMethodTracing(traceName, fd, bufferSize, flags, false, 0);
+ int bufferSize, int flags, boolean streamOutput) {
+ VMDebug.startMethodTracing(traceName, fd, bufferSize, flags, false, 0, streamOutput);
}
/**
@@ -2219,11 +2219,13 @@ public final class Debug
}
/**
- * Have the stack traces of the given native process dumped to the
- * specified file. Will be appended to the file.
+ * Append the stack traces of a given native process to a specified file.
+ * @param pid pid to dump.
+ * @param file path of file to append dump to.
+ * @param timeoutSecs time to wait in seconds, or 0 to wait forever.
* @hide
*/
- public static native void dumpNativeBacktraceToFile(int pid, String file);
+ public static native void dumpNativeBacktraceToFileTimeout(int pid, String file, int timeoutSecs);
/**
* Get description of unreachable native memory.
diff --git a/core/java/android/os/FactoryTest.java b/core/java/android/os/FactoryTest.java
index 7a252f933446..b59227cf471b 100644
--- a/core/java/android/os/FactoryTest.java
+++ b/core/java/android/os/FactoryTest.java
@@ -16,6 +16,8 @@
package android.os;
+import com.android.internal.os.RoSystemProperties;
+
/**
* Provides support for in-place factory test functions.
*
@@ -36,7 +38,7 @@ public final class FactoryTest {
* or {@link #FACTORY_TEST_HIGH_LEVEL}.
*/
public static int getMode() {
- return SystemProperties.getInt("ro.factorytest", FACTORY_TEST_OFF);
+ return RoSystemProperties.FACTORYTEST;
}
/**
diff --git a/core/java/android/os/Seccomp.java b/core/java/android/os/Seccomp.java
new file mode 100644
index 000000000000..f14e93fe9403
--- /dev/null
+++ b/core/java/android/os/Seccomp.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * @hide
+ */
+public final class Seccomp {
+ public static final native void setPolicy();
+}
diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java
index fc804e592148..0b4c4c12d3df 100644
--- a/core/java/android/os/ShellCommand.java
+++ b/core/java/android/os/ShellCommand.java
@@ -274,7 +274,7 @@ public abstract class ShellCommand {
/**
* Implement parsing and execution of a command. If it isn't a command you understand,
* call {@link #handleDefaultCommands(String)} and return its result as a last resort.
- * User {@link #getNextOption()}, {@link #getNextArg()}, and {@link #getNextArgRequired()}
+ * Use {@link #getNextOption()}, {@link #getNextArg()}, and {@link #getNextArgRequired()}
* to process additional command line arguments. Command output can be written to
* {@link #getOutPrintWriter()} and errors to {@link #getErrPrintWriter()}.
*
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index e47c2380ca83..6a751e808d4b 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -16,7 +16,13 @@
package android.os;
+import android.util.Log;
+import android.util.MutableInt;
+
+import com.android.internal.annotations.GuardedBy;
+
import java.util.ArrayList;
+import java.util.HashMap;
/**
@@ -25,13 +31,45 @@ import java.util.ArrayList;
*
* {@hide}
*/
-public class SystemProperties
-{
+public class SystemProperties {
+ private static final String TAG = "SystemProperties";
+ private static final boolean TRACK_KEY_ACCESS = false;
+
public static final int PROP_NAME_MAX = 31;
public static final int PROP_VALUE_MAX = 91;
private static final ArrayList<Runnable> sChangeCallbacks = new ArrayList<Runnable>();
+ @GuardedBy("sRoReads")
+ private static final HashMap<String, MutableInt> sRoReads;
+ static {
+ if (TRACK_KEY_ACCESS) {
+ sRoReads = new HashMap<>();
+ } else {
+ sRoReads = null;
+ }
+ }
+
+ private static void onKeyAccess(String key) {
+ if (!TRACK_KEY_ACCESS) return;
+
+ if (key != null && key.startsWith("ro.")) {
+ synchronized (sRoReads) {
+ MutableInt numReads = sRoReads.getOrDefault(key, null);
+ if (numReads == null) {
+ numReads = new MutableInt(0);
+ sRoReads.put(key, numReads);
+ }
+ numReads.value++;
+ if (numReads.value > 3) {
+ Log.d(TAG, "Repeated read (count=" + numReads.value
+ + ") of a read-only system property '" + key + "'",
+ new Exception());
+ }
+ }
+ }
+ }
+
private static native String native_get(String key);
private static native String native_get(String key, String def);
private static native int native_get_int(String key, int def);
@@ -50,6 +88,7 @@ public class SystemProperties
if (key.length() > PROP_NAME_MAX) {
throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
}
+ if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get(key);
}
@@ -62,6 +101,7 @@ public class SystemProperties
if (key.length() > PROP_NAME_MAX) {
throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
}
+ if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get(key, def);
}
@@ -77,6 +117,7 @@ public class SystemProperties
if (key.length() > PROP_NAME_MAX) {
throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
}
+ if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get_int(key, def);
}
@@ -92,6 +133,7 @@ public class SystemProperties
if (key.length() > PROP_NAME_MAX) {
throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
}
+ if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get_long(key, def);
}
@@ -112,6 +154,7 @@ public class SystemProperties
if (key.length() > PROP_NAME_MAX) {
throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
}
+ if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get_boolean(key, def);
}
@@ -128,6 +171,7 @@ public class SystemProperties
throw new IllegalArgumentException("val.length > " +
PROP_VALUE_MAX);
}
+ if (TRACK_KEY_ACCESS) onKeyAccess(key);
native_set(key, val);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index a4db940d4fdb..ab462e433890 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -42,6 +42,7 @@ import android.telephony.TelephonyManager;
import android.view.WindowManager.LayoutParams;
import com.android.internal.R;
+import com.android.internal.os.RoSystemProperties;
import java.io.IOException;
import java.lang.annotation.Retention;
@@ -761,7 +762,7 @@ public class UserManager {
* a single owner user. see @link {android.os.UserHandle#USER_OWNER}
*/
public static boolean isSplitSystemUser() {
- return SystemProperties.getBoolean("ro.fw.system_user_split", false);
+ return RoSystemProperties.FW_SYSTEM_USER_SPLIT;
}
/**
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 5ac33a1768c2..fa9f394add60 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -352,8 +352,8 @@ public class ZygoteProcess {
if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {
argsForZygote.add("--enable-safemode");
}
- if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {
- argsForZygote.add("--enable-debugger");
+ if ((debugFlags & Zygote.DEBUG_ENABLE_JDWP) != 0) {
+ argsForZygote.add("--enable-jdwp");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
argsForZygote.add("--enable-checkjni");
@@ -367,6 +367,9 @@ public class ZygoteProcess {
if ((debugFlags & Zygote.DEBUG_NATIVE_DEBUGGABLE) != 0) {
argsForZygote.add("--native-debuggable");
}
+ if ((debugFlags & Zygote.DEBUG_JAVA_DEBUGGABLE) != 0) {
+ argsForZygote.add("--java-debuggable");
+ }
if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
argsForZygote.add("--enable-assert");
}
@@ -379,9 +382,6 @@ public class ZygoteProcess {
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
- //TODO optionally enable debuger
- //argsForZygote.add("--enable-debugger");
-
// --setgroups is a comma-separated list
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 925288764562..63b6db0eebe2 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -44,6 +44,7 @@ import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import com.android.internal.os.RoSystemProperties;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.Preconditions;
@@ -1167,8 +1168,7 @@ public class StorageManager {
* false not encrypted and not encryptable
*/
public static boolean isEncryptable() {
- final String state = SystemProperties.get("ro.crypto.state", "unsupported");
- return !"unsupported".equalsIgnoreCase(state);
+ return RoSystemProperties.CRYPTO_ENCRYPTABLE;
}
/** {@hide}
@@ -1177,8 +1177,7 @@ public class StorageManager {
* false not encrypted
*/
public static boolean isEncrypted() {
- final String state = SystemProperties.get("ro.crypto.state", "");
- return "encrypted".equalsIgnoreCase(state);
+ return RoSystemProperties.CRYPTO_ENCRYPTED;
}
/** {@hide}
@@ -1190,9 +1189,7 @@ public class StorageManager {
if (!isEncrypted()) {
return false;
}
-
- final String status = SystemProperties.get("ro.crypto.type", "");
- return "file".equalsIgnoreCase(status);
+ return RoSystemProperties.CRYPTO_FILE_ENCRYPTED;
}
/** {@hide}
@@ -1204,8 +1201,7 @@ public class StorageManager {
if (!isEncrypted()) {
return false;
}
- final String status = SystemProperties.get("ro.crypto.type", "");
- return "block".equalsIgnoreCase(status);
+ return RoSystemProperties.CRYPTO_BLOCK_ENCRYPTED;
}
/** {@hide}
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 1ec00db22903..f1d59e2ca699 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -348,8 +348,8 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
if (msg.what == UPDATE_SLIDER) {
if (mSeekBar != null) {
mLastProgress = msg.arg1;
- mLastAudibleStreamVolume = Math.abs(msg.arg2);
- final boolean muted = msg.arg2 < 0;
+ mLastAudibleStreamVolume = msg.arg2;
+ final boolean muted = ((Boolean)msg.obj).booleanValue();
if (muted != mMuted) {
mMuted = muted;
if (mCallback != null) {
@@ -362,8 +362,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
}
public void postUpdateSlider(int volume, int lastAudibleVolume, boolean mute) {
- final int arg2 = lastAudibleVolume * (mute ? -1 : 1);
- obtainMessage(UPDATE_SLIDER, volume, arg2).sendToTarget();
+ obtainMessage(UPDATE_SLIDER, volume, lastAudibleVolume, new Boolean(mute)).sendToTarget();
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b1dcb812f531..38ad68d1e7b9 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6416,6 +6416,12 @@ public final class Settings {
public static final String DEVICE_PAIRED = "device_paired";
/**
+ * Specifies additional package name for broadcasting the CMAS messages.
+ * @hide
+ */
+ public static final String CMAS_ADDITIONAL_BROADCAST_PKG = "cmas_additional_broadcast_pkg";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -7692,6 +7698,16 @@ public final class Settings {
public static final String NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS =
"network_recommendation_request_timeout_ms";
+ /**
+ * The expiration time in milliseconds for the {@link android.net.WifiKey} request cache in
+ * {@link com.android.server.wifi.RecommendedNetworkEvaluator}.
+ *
+ * Type: long
+ * @hide
+ */
+ public static final String RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS =
+ "recommended_network_evaluator_cache_expiry_ms";
+
/**
* Settings to allow BLE scans to be enabled even when Bluetooth is turned off for
* connectivity.
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 887f4b6577b9..1781c2ac0d78 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -130,6 +130,11 @@ public class TileService extends Service {
*/
public static final String EXTRA_COMPONENT = "android.service.quicksettings.extra.COMPONENT";
+ /**
+ * @hide
+ */
+ public static final String EXTRA_STATE = "state";
+
private final H mHandler = new H(Looper.getMainLooper());
private boolean mListening = false;
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index 356804ea64bd..80ec03e70cb7 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -189,7 +189,9 @@ public class Hyphenator {
// TODO: replace this with a discovery-based method that looks into /system/usr/hyphen-data
String[] availableLanguages = {
"as",
+ "bg",
"bn",
+ "cu",
"cy",
"da",
"de-1901", "de-1996", "de-CH-1901",
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index c7b1d03b120b..1c458ab31db0 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -34,7 +34,6 @@ import android.view.accessibility.AccessibilityNodeProvider;
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
import com.android.internal.os.SomeArgs;
-import com.android.internal.util.Predicate;
import java.util.ArrayList;
import java.util.HashMap;
@@ -43,6 +42,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
+import java.util.function.Predicate;
/**
* Class for managing accessibility interactions initiated from the system
@@ -1233,7 +1233,7 @@ final class AccessibilityInteractionController {
}
@Override
- public boolean apply(View view) {
+ public boolean test(View view) {
if (view.getId() == mViewId && isShown(view)) {
mInfos.add(view.createAccessibilityNodeInfo());
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d13f6d6d6ae0..f65ec945e20d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -103,7 +103,6 @@ import static android.os.Build.VERSION_CODES.*;
import static java.lang.Math.max;
import com.android.internal.R;
-import com.android.internal.util.Predicate;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.widget.ScrollBarUtils;
import com.google.android.collect.Lists;
@@ -126,6 +125,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Predicate;
/**
* <p>
@@ -8778,7 +8778,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
final int id = mID;
return root.findViewByPredicateInsideOut(this, new Predicate<View>() {
@Override
- public boolean apply(View t) {
+ public boolean test(View t) {
return t.mNextFocusForwardId == id;
}
});
@@ -19349,7 +19349,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The first view that matches the predicate or null.
*/
protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
- if (predicate.apply(this)) {
+ if (predicate.test(this)) {
return this;
}
return null;
@@ -23639,20 +23639,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
- private class MatchIdPredicate implements Predicate<View> {
+ private static class MatchIdPredicate implements Predicate<View> {
public int mId;
@Override
- public boolean apply(View view) {
+ public boolean test(View view) {
return (view.mID == mId);
}
}
- private class MatchLabelForPredicate implements Predicate<View> {
+ private static class MatchLabelForPredicate implements Predicate<View> {
private int mLabeledId;
@Override
- public boolean apply(View view) {
+ public boolean test(View view) {
return (view.mLabelForId == mLabeledId);
}
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d4b7d3bdd76a..776f119a79fb 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -52,13 +52,13 @@ import android.view.animation.LayoutAnimationController;
import android.view.animation.Transformation;
import com.android.internal.R;
-import com.android.internal.util.Predicate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.function.Predicate;
import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
@@ -3994,7 +3994,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
@Override
protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
- if (predicate.apply(this)) {
+ if (predicate.test(this)) {
return this;
}
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index 2d6f44352ba7..f9d733201e59 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -176,7 +176,7 @@ public class WebViewZygote {
// paths and pass them to the zygote as strings.
final List<String> zipPaths = new ArrayList<>(10);
final List<String> libPaths = new ArrayList<>(10);
- LoadedApk.makePaths(null, sPackage.applicationInfo, zipPaths, libPaths);
+ LoadedApk.makePaths(null, false, sPackage.applicationInfo, zipPaths, libPaths);
final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
TextUtils.join(File.pathSeparator, zipPaths);
diff --git a/core/java/android/widget/DayPickerViewPager.java b/core/java/android/widget/DayPickerViewPager.java
index 5f0ae29bb96d..07b3c9507cd2 100644
--- a/core/java/android/widget/DayPickerViewPager.java
+++ b/core/java/android/widget/DayPickerViewPager.java
@@ -25,11 +25,11 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
-import com.android.internal.util.Predicate;
import com.android.internal.widget.PagerAdapter;
import com.android.internal.widget.ViewPager;
import java.util.ArrayList;
+import java.util.function.Predicate;
/**
* This displays a list of months in a calendar format with selectable days.
@@ -143,7 +143,7 @@ class DayPickerViewPager extends ViewPager {
@Override
protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
- if (predicate.apply(this)) {
+ if (predicate.test(this)) {
return this;
}
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index b0f19d7a0b49..2e7f0fd22d3a 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -19,7 +19,6 @@ package android.widget;
import com.google.android.collect.Lists;
import com.android.internal.R;
-import com.android.internal.util.Predicate;
import android.annotation.IdRes;
import android.annotation.NonNull;
@@ -55,6 +54,7 @@ import android.widget.RemoteViews.RemoteView;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Predicate;
/*
* Implementation Notes:
diff --git a/core/java/com/android/internal/os/RoSystemProperties.java b/core/java/com/android/internal/os/RoSystemProperties.java
new file mode 100644
index 000000000000..80c55fb57186
--- /dev/null
+++ b/core/java/com/android/internal/os/RoSystemProperties.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.os.SystemProperties;
+
+/**
+ * This is a cache of various ro.* properties so that they can be read just once
+ * at class init time.
+ */
+public class RoSystemProperties {
+ public static final boolean DEBUGGABLE =
+ SystemProperties.getInt("ro.debuggable", 0) == 1;
+ public static final int FACTORYTEST =
+ SystemProperties.getInt("ro.factorytest", 0);
+
+ // ------ ro.config.* -------- //
+ public static final boolean CONFIG_LOW_RAM =
+ SystemProperties.getBoolean("ro.config.low_ram", false);
+
+ // ------ ro.fw.* ------------ //
+ public static final boolean FW_SYSTEM_USER_SPLIT =
+ SystemProperties.getBoolean("ro.fw.system_user_split", false);
+
+ // ------ ro.crypto.* -------- //
+ public static final String CRYPTO_STATE = SystemProperties.get("ro.crypto.state");
+ public static final String CRYPTO_TYPE = SystemProperties.get("ro.crypto.type");
+ // These are pseudo-properties
+ public static final boolean CRYPTO_ENCRYPTABLE =
+ !CRYPTO_STATE.isEmpty() && !"unsupported".equals(CRYPTO_STATE);
+ public static final boolean CRYPTO_ENCRYPTED =
+ "encrypted".equalsIgnoreCase(CRYPTO_STATE);
+ public static final boolean CRYPTO_FILE_ENCRYPTED =
+ "file".equalsIgnoreCase(CRYPTO_TYPE);
+ public static final boolean CRYPTO_BLOCK_ENCRYPTED =
+ "block".equalsIgnoreCase(CRYPTO_TYPE);
+}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index c851e4ec959a..674fdead01d8 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -43,8 +43,8 @@ import org.apache.harmony.luni.internal.util.TimezoneGetter;
* @hide
*/
public class RuntimeInit {
- private final static String TAG = "AndroidRuntime";
- private final static boolean DEBUG = false;
+ final static String TAG = "AndroidRuntime";
+ final static boolean DEBUG = false;
/** true if commonInit() has been called */
private static boolean initialized;
@@ -53,7 +53,6 @@ public class RuntimeInit {
private static volatile boolean mCrashing = false;
- private static final native void nativeZygoteInit();
private static final native void nativeFinishInit();
private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
@@ -133,7 +132,7 @@ public class RuntimeInit {
}
}
- private static final void commonInit() {
+ protected static final void commonInit() {
if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
/*
@@ -287,50 +286,7 @@ public class RuntimeInit {
if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
}
- /**
- * The main function called when started through the zygote process. This
- * could be unified with main(), if the native code in nativeFinishInit()
- * were rationalized with Zygote startup.<p>
- *
- * Current recognized args:
- * <ul>
- * <li> <code> [--] &lt;start class name&gt; &lt;args&gt;
- * </ul>
- *
- * @param targetSdkVersion target SDK version
- * @param argv arg strings
- */
- public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
- throws Zygote.MethodAndArgsCaller {
- if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
-
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
- redirectLogStreams();
-
- commonInit();
- nativeZygoteInit();
- applicationInit(targetSdkVersion, argv, classLoader);
- }
-
- /**
- * The main function called when an application is started through a
- * wrapper process.
- *
- * When the wrapper starts, the runtime starts {@link RuntimeInit#main}
- * which calls {@link WrapperInit#main} which then calls this method.
- * So we don't need to call commonInit() here.
- *
- * @param targetSdkVersion target SDK version
- * @param argv arg strings
- */
- public static void wrapperInit(int targetSdkVersion, String[] argv)
- throws Zygote.MethodAndArgsCaller {
- if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from wrapper");
-
- applicationInit(targetSdkVersion, argv, null);
- }
-
- private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
+ protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws Zygote.MethodAndArgsCaller {
// If the application calls System.exit(), terminate the process
// immediately without running any shutdown hooks. It is not possible to
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 594b6ab72ef3..dbbebbe7f758 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -18,7 +18,7 @@ package com.android.internal.os;
import android.os.Process;
import android.util.Slog;
-
+import com.android.internal.os.Zygote.MethodAndArgsCaller;
import dalvik.system.VMRuntime;
import java.io.DataOutputStream;
import java.io.FileDescriptor;
@@ -80,7 +80,7 @@ public class WrapperInit {
// Launch the application.
String[] runtimeArgs = new String[args.length - 2];
System.arraycopy(args, 2, runtimeArgs, 0, runtimeArgs.length);
- RuntimeInit.wrapperInit(targetSdkVersion, runtimeArgs);
+ WrapperInit.wrapperInit(targetSdkVersion, runtimeArgs);
} catch (Zygote.MethodAndArgsCaller caller) {
caller.run();
}
@@ -121,4 +121,24 @@ public class WrapperInit {
Zygote.appendQuotedShellArgs(command, args);
Zygote.execShell(command.toString());
}
+
+ /**
+ * The main function called when an application is started through a
+ * wrapper process.
+ *
+ * When the wrapper starts, the runtime starts {@link RuntimeInit#main}
+ * which calls {@link main} which then calls this method.
+ * So we don't need to call commonInit() here.
+ *
+ * @param targetSdkVersion target SDK version
+ * @param argv arg strings
+ */
+ private static void wrapperInit(int targetSdkVersion, String[] argv)
+ throws Zygote.MethodAndArgsCaller {
+ if (RuntimeInit.DEBUG) {
+ Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from wrapper");
+ }
+
+ RuntimeInit.applicationInit(targetSdkVersion, argv, null);
+ }
}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index e1e0a21eb7f5..59416dd06cdc 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -33,7 +33,7 @@ public final class Zygote {
*/
/** enable debugging over JDWP */
- public static final int DEBUG_ENABLE_DEBUGGER = 1;
+ public static final int DEBUG_ENABLE_JDWP = 1;
/** enable JNI checks */
public static final int DEBUG_ENABLE_CHECKJNI = 1 << 1;
/** enable Java programming language "assert" statements */
@@ -46,8 +46,10 @@ public final class Zygote {
public static final int DEBUG_GENERATE_DEBUG_INFO = 1 << 5;
/** Always use JIT-ed code. */
public static final int DEBUG_ALWAYS_JIT = 1 << 6;
- /** Make the code debuggable with turning off some optimizations. */
+ /** Make the code native debuggable by turning off some optimizations. */
public static final int DEBUG_NATIVE_DEBUGGABLE = 1 << 7;
+ /** Make the code Java debuggable by turning off some optimizations. */
+ public static final int DEBUG_JAVA_DEBUGGABLE = 1 << 8;
/** No external storage should be mounted. */
public static final int MOUNT_EXTERNAL_NONE = 0;
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index ec80303f714a..527582be3c02 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -24,6 +24,7 @@ import static android.system.OsConstants.STDOUT_FILENO;
import android.net.Credentials;
import android.net.LocalSocket;
+import android.os.FactoryTest;
import android.os.Process;
import android.os.SELinux;
import android.os.SystemProperties;
@@ -335,8 +336,9 @@ class ZygoteConnection {
int[] gids;
/**
- * From --enable-debugger, --enable-checkjni, --enable-assert,
- * --enable-safemode, --generate-debug-info and --enable-jni-logging.
+ * From --enable-jdwp, --enable-checkjni, --enable-assert,
+ * --enable-safemode, --generate-debug-info, --enable-jni-logging,
+ * --java-debuggable, and --native-debuggable.
*/
int debugFlags;
@@ -446,8 +448,8 @@ class ZygoteConnection {
targetSdkVersionSpecified = true;
targetSdkVersion = Integer.parseInt(
arg.substring(arg.indexOf('=') + 1));
- } else if (arg.equals("--enable-debugger")) {
- debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
+ } else if (arg.equals("--enable-jdwp")) {
+ debugFlags |= Zygote.DEBUG_ENABLE_JDWP;
} else if (arg.equals("--enable-safemode")) {
debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
} else if (arg.equals("--enable-checkjni")) {
@@ -458,6 +460,8 @@ class ZygoteConnection {
debugFlags |= Zygote.DEBUG_ALWAYS_JIT;
} else if (arg.equals("--native-debuggable")) {
debugFlags |= Zygote.DEBUG_NATIVE_DEBUGGABLE;
+ } else if (arg.equals("--java-debuggable")) {
+ debugFlags |= Zygote.DEBUG_JAVA_DEBUGGABLE;
} else if (arg.equals("--enable-jni-logging")) {
debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
} else if (arg.equals("--enable-assert")) {
@@ -642,13 +646,10 @@ class ZygoteConnection {
throws ZygoteSecurityException {
if (peer.getUid() == Process.SYSTEM_UID) {
- String factoryTest = SystemProperties.get("ro.factorytest");
- boolean uidRestricted;
-
/* In normal operation, SYSTEM_UID can only specify a restricted
* set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
*/
- uidRestricted = !(factoryTest.equals("1") || factoryTest.equals("2"));
+ boolean uidRestricted = FactoryTest.getMode() == FactoryTest.FACTORY_TEST_OFF;
if (uidRestricted && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) {
throw new ZygoteSecurityException(
@@ -672,14 +673,14 @@ class ZygoteConnection {
* Applies debugger system properties to the zygote arguments.
*
* If "ro.debuggable" is "1", all apps are debuggable. Otherwise,
- * the debugger state is specified via the "--enable-debugger" flag
+ * the debugger state is specified via the "--enable-jdwp" flag
* in the spawn request.
*
* @param args non-null; zygote spawner args
*/
public static void applyDebuggerSystemProperty(Arguments args) {
- if ("1".equals(SystemProperties.get("ro.debuggable"))) {
- args.debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
+ if (RoSystemProperties.DEBUGGABLE) {
+ args.debugFlags |= Zygote.DEBUG_ENABLE_JDWP;
}
}
@@ -701,7 +702,7 @@ class ZygoteConnection {
int peerUid = peer.getUid();
if (args.invokeWith != null && peerUid != 0 &&
- (args.debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) == 0) {
+ (args.debugFlags & Zygote.DEBUG_ENABLE_JDWP) == 0) {
throw new ZygoteSecurityException("Peer is permitted to specify an"
+ "explicit invoke-with wrapper command only for debuggable"
+ "applications.");
@@ -782,7 +783,7 @@ class ZygoteConnection {
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs);
} else {
- RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
+ ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index ef5231cb6ff3..1e0a9980a66f 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -29,6 +29,7 @@ import android.opengl.EGL14;
import android.os.IInstalld;
import android.os.Process;
import android.os.RemoteException;
+import android.os.Seccomp;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.os.SystemClock;
@@ -43,10 +44,9 @@ import android.system.OsConstants;
import android.text.Hyphenator;
import android.util.EventLog;
import android.util.Log;
+import android.util.Slog;
import android.webkit.WebViewFactory;
import android.widget.TextView;
-
-
import dalvik.system.DexFile;
import dalvik.system.PathClassLoader;
import dalvik.system.VMRuntime;
@@ -467,7 +467,7 @@ public class ZygoteInit {
/*
* Pass the remaining arguments to SystemServer.
*/
- RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
+ ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}
/* should never reach here */
@@ -692,6 +692,9 @@ public class ZygoteInit {
// Zygote process unmounts root storage spaces.
Zygote.nativeUnmountStorageOnInit();
+ // Set seccomp policy
+ Seccomp.setPolicy();
+
ZygoteHooks.stopZygoteNoThreadCreation();
if (startSystemServer) {
@@ -747,4 +750,33 @@ public class ZygoteInit {
*/
private ZygoteInit() {
}
+
+ /**
+ * The main function called when started through the zygote process. This
+ * could be unified with main(), if the native code in nativeFinishInit()
+ * were rationalized with Zygote startup.<p>
+ *
+ * Current recognized args:
+ * <ul>
+ * <li> <code> [--] &lt;start class name&gt; &lt;args&gt;
+ * </ul>
+ *
+ * @param targetSdkVersion target SDK version
+ * @param argv arg strings
+ */
+ public static final void zygoteInit(int targetSdkVersion, String[] argv,
+ ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
+ if (RuntimeInit.DEBUG) {
+ Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
+ }
+
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
+ RuntimeInit.redirectLogStreams();
+
+ RuntimeInit.commonInit();
+ ZygoteInit.nativeZygoteInit();
+ RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
+ }
+
+ private static final native void nativeZygoteInit();
}
diff --git a/core/java/com/android/internal/util/MessageUtils.java b/core/java/com/android/internal/util/MessageUtils.java
index 184245ef538d..e733c30ae84a 100644
--- a/core/java/com/android/internal/util/MessageUtils.java
+++ b/core/java/com/android/internal/util/MessageUtils.java
@@ -42,10 +42,11 @@ public class MessageUtils {
/**
* Finds the names of integer constants. Searches the specified {@code classes}, looking for
- * accessible static integer fields whose names begin with one of the specified {@prefixes}.
+ * accessible static integer fields whose names begin with one of the specified
+ * {@code prefixes}.
*
* @param classes the classes to examine.
- * @prefixes only consider fields names starting with one of these prefixes.
+ * @param prefixes only consider fields names starting with one of these prefixes.
* @return a {@link SparseArray} mapping integer constants to their names.
*/
public static SparseArray<String> findMessageNames(Class[] classes, String[] prefixes) {
@@ -122,7 +123,6 @@ public class MessageUtils {
* accessible static integer values whose names begin with {@link #DEFAULT_PREFIXES}.
*
* @param classNames the classes to examine.
- * @prefixes only consider fields names starting with one of these prefixes.
* @return a {@link SparseArray} mapping integer constants to their names.
*/
public static SparseArray<String> findMessageNames(Class[] classNames) {
diff --git a/core/java/com/android/internal/util/Predicate.java b/core/java/com/android/internal/util/Predicate.java
index bc6d6b31dd28..1b5eaff67b87 100644
--- a/core/java/com/android/internal/util/Predicate.java
+++ b/core/java/com/android/internal/util/Predicate.java
@@ -25,7 +25,10 @@ package com.android.internal.util;
* <p/>
* Implementors of Predicate which may cause side effects upon evaluation are
* strongly encouraged to state this fact clearly in their API documentation.
+ *
+ * @deprecated Use {@code java.util.function.Predicate} instead.
*/
+@Deprecated
public interface Predicate<T> {
boolean apply(T t);
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index be10608df2a3..d67cef3f0dda 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -23,6 +23,8 @@ import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -1495,7 +1497,7 @@ public class StateMachine {
}
/**
- * @return number of log records
+ * @return the number of log records currently readable
*/
public final int getLogRecSize() {
// mSmHandler can be null if the state machine has quit.
@@ -1505,6 +1507,17 @@ public class StateMachine {
}
/**
+ * @return the number of log records we can store
+ */
+ @VisibleForTesting
+ public final int getLogRecMaxSize() {
+ // mSmHandler can be null if the state machine has quit.
+ SmHandler smh = mSmHandler;
+ if (smh == null) return 0;
+ return smh.mLogRecords.mMaxSize;
+ }
+
+ /**
* @return the total number of records processed
*/
public final int getLogRecCount() {
diff --git a/core/java/com/android/internal/widget/WatchHeaderListView.java b/core/java/com/android/internal/widget/WatchHeaderListView.java
index 4fd19c37bf47..7e915374ca4f 100644
--- a/core/java/com/android/internal/widget/WatchHeaderListView.java
+++ b/core/java/com/android/internal/widget/WatchHeaderListView.java
@@ -26,8 +26,7 @@ import android.widget.ListView;
import android.widget.HeaderViewListAdapter;
import java.util.ArrayList;
-
-import com.android.internal.util.Predicate;
+import java.util.function.Predicate;
public class WatchHeaderListView extends ListView {
private View mTopPanel;
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 24c8bfb43c6e..a9ca12b26d0b 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -84,6 +84,7 @@ LOCAL_SRC_FILES:= \
android_os_MessageQueue.cpp \
android_os_Parcel.cpp \
android_os_SELinux.cpp \
+ android_os_seccomp.cpp \
android_os_SystemClock.cpp \
android_os_SystemProperties.cpp \
android_os_Trace.cpp \
@@ -215,6 +216,9 @@ LOCAL_C_INCLUDES += \
external/freetype/include
# TODO: clean up Minikin so it doesn't need the freetype include
+LOCAL_STATIC_LIBRARIES := \
+ libseccomp_policy \
+
LOCAL_SHARED_LIBRARIES := \
libmemtrack \
libandroidfw \
@@ -269,6 +273,7 @@ LOCAL_SHARED_LIBRARIES := \
libhidlbase \
libhidltransport \
libhwbinder \
+ libvintf \
LOCAL_SHARED_LIBRARIES += \
libhwui \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 07392c4055d3..00d9a96d86fc 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -163,6 +163,7 @@ extern int register_android_os_HwRemoteBinder(JNIEnv *env);
extern int register_android_os_MessageQueue(JNIEnv* env);
extern int register_android_os_Parcel(JNIEnv* env);
extern int register_android_os_SELinux(JNIEnv* env);
+extern int register_android_os_seccomp(JNIEnv* env);
extern int register_android_os_SystemProperties(JNIEnv *env);
extern int register_android_os_SystemClock(JNIEnv* env);
extern int register_android_os_Trace(JNIEnv* env);
@@ -218,7 +219,7 @@ static void com_android_internal_os_RuntimeInit_nativeFinishInit(JNIEnv* env, jo
gCurRuntime->onStarted();
}
-static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
+static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onZygoteInit();
}
@@ -232,19 +233,27 @@ static void com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup(JNIE
/*
* JNI registration.
*/
-static const JNINativeMethod gMethods[] = {
- { "nativeFinishInit", "()V",
- (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
- { "nativeZygoteInit", "()V",
- (void*) com_android_internal_os_RuntimeInit_nativeZygoteInit },
- { "nativeSetExitWithoutCleanup", "(Z)V",
- (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
-};
int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
{
+ const JNINativeMethod methods[] = {
+ { "nativeFinishInit", "()V",
+ (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
+ { "nativeSetExitWithoutCleanup", "(Z)V",
+ (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
+ };
return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
- gMethods, NELEM(gMethods));
+ methods, NELEM(methods));
+}
+
+int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
+{
+ const JNINativeMethod methods[] = {
+ { "nativeZygoteInit", "()V",
+ (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
+ };
+ return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
+ methods, NELEM(methods));
}
// ----------------------------------------------------------------------
@@ -1273,6 +1282,7 @@ static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env
static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_RuntimeInit),
+ REG_JNI(register_com_android_internal_os_ZygoteInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
@@ -1366,6 +1376,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_os_FileObserver),
REG_JNI(register_android_os_MessageQueue),
REG_JNI(register_android_os_SELinux),
+ REG_JNI(register_android_os_seccomp),
REG_JNI(register_android_os_Trace),
REG_JNI(register_android_os_UEventObserver),
REG_JNI(register_android_net_LocalSocketImpl),
diff --git a/core/jni/android_hardware_Radio.cpp b/core/jni/android_hardware_Radio.cpp
index ec6471e3dc83..d2ac2cc40a32 100644
--- a/core/jni/android_hardware_Radio.cpp
+++ b/core/jni/android_hardware_Radio.cpp
@@ -23,7 +23,7 @@
#include "JNIHelp.h"
#include "core_jni_helpers.h"
#include <system/radio.h>
-#include <system/radio_metadata.h>
+#include <system/RadioMetadataWrapper.h>
#include <radio/RadioCallback.h>
#include <radio/Radio.h>
#include <utils/RefBase.h>
@@ -749,7 +749,7 @@ android_hardware_Radio_getProgramInformation(JNIEnv *env, jobject thiz, jobjectA
}
struct radio_program_info nInfo;
- radio_metadata_allocate(&nInfo.metadata, 0, 0);
+ RadioMetadataWrapper metadataWrapper(&nInfo.metadata);
jobject jInfo = NULL;
int jStatus;
@@ -767,7 +767,6 @@ exit:
if (jInfo != NULL) {
env->DeleteLocalRef(jInfo);
}
- radio_metadata_deallocate(nInfo.metadata);
return jStatus;
}
diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp
index 793d1325ab6f..0c7f5a116561 100644
--- a/core/jni/android_hardware_SoundTrigger.cpp
+++ b/core/jni/android_hardware_SoundTrigger.cpp
@@ -509,7 +509,7 @@ android_hardware_SoundTrigger_loadSoundModel(JNIEnv *env, jobject thiz,
sp<MemoryDealer> memoryDealer;
sp<IMemory> memory;
size_t size;
- sound_model_handle_t handle;
+ sound_model_handle_t handle = 0;
jobject jUuid;
jstring jUuidString;
const char *nUuidString;
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index cbe2bbae80da..a75848973b06 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -1012,9 +1012,8 @@ static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject clazz,
ALOGD("Native heap dump complete.\n");
}
-
-static void android_os_Debug_dumpNativeBacktraceToFile(JNIEnv* env, jobject clazz,
- jint pid, jstring fileName)
+static void android_os_Debug_dumpNativeBacktraceToFileTimeout(JNIEnv* env, jobject clazz,
+ jint pid, jstring fileName, jint timeoutSecs)
{
if (fileName == NULL) {
jniThrowNullPointerException(env, "file == null");
@@ -1028,17 +1027,13 @@ static void android_os_Debug_dumpNativeBacktraceToFile(JNIEnv* env, jobject claz
env->ReleaseStringCritical(fileName, str);
}
- int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW, 0666); /* -rw-rw-rw- */
+ int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW | O_CLOEXEC | O_APPEND, 0666);
if (fd < 0) {
fprintf(stderr, "Can't open %s: %s\n", fileName8.string(), strerror(errno));
return;
}
- if (lseek(fd, 0, SEEK_END) < 0) {
- fprintf(stderr, "lseek: %s\n", strerror(errno));
- } else {
- dump_backtrace_to_file(pid, fd);
- }
+ dump_backtrace_to_file_timeout(pid, fd, timeoutSecs);
close(fd);
}
@@ -1083,8 +1078,8 @@ static const JNINativeMethod gMethods[] = {
(void*)android_os_Debug_getProxyObjectCount },
{ "getBinderDeathObjectCount", "()I",
(void*)android_os_Debug_getDeathObjectCount },
- { "dumpNativeBacktraceToFile", "(ILjava/lang/String;)V",
- (void*)android_os_Debug_dumpNativeBacktraceToFile },
+ { "dumpNativeBacktraceToFileTimeout", "(ILjava/lang/String;I)V",
+ (void*)android_os_Debug_dumpNativeBacktraceToFileTimeout },
{ "getUnreachableMemory", "(IZ)Ljava/lang/String;",
(void*)android_os_Debug_getUnreachableMemory },
};
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index e65390047c55..c1d42513963d 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -33,6 +33,7 @@
#include <hidl/HidlTransportSupport.h>
#include <hwbinder/ProcessState.h>
#include <nativehelper/ScopedLocalRef.h>
+#include <vintf/parse_string.h>
#include "core_jni_helpers.h"
@@ -127,18 +128,23 @@ status_t JHwBinder::onTransact(
uint32_t flags,
TransactCallback callback) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
+ bool isOneway = (flags & TF_ONE_WAY) != 0;
+ ScopedLocalRef<jobject> replyObj(env, nullptr);
+ sp<JHwParcel> replyContext = nullptr;
ScopedLocalRef<jobject> requestObj(env, JHwParcel::NewObject(env));
JHwParcel::GetNativeContext(env, requestObj.get())->setParcel(
const_cast<hardware::Parcel *>(&data), false /* assumeOwnership */);
- ScopedLocalRef<jobject> replyObj(env, JHwParcel::NewObject(env));
- sp<JHwParcel> replyContext =
- JHwParcel::GetNativeContext(env, replyObj.get());
+ if (!isOneway) {
+ replyObj.reset(JHwParcel::NewObject(env));
- replyContext->setParcel(reply, false /* assumeOwnership */);
- replyContext->setTransactCallback(callback);
+ replyContext = JHwParcel::GetNativeContext(env, replyObj.get());
+
+ replyContext->setParcel(reply, false /* assumeOwnership */);
+ replyContext->setTransactCallback(callback);
+ }
env->CallVoidMethod(
mObject,
@@ -166,25 +172,27 @@ status_t JHwBinder::onTransact(
status_t err = OK;
- if (!replyContext->wasSent()) {
- // The implementation never finished the transaction.
- err = UNKNOWN_ERROR; // XXX special error code instead?
+ if (!isOneway) {
+ if (!replyContext->wasSent()) {
+ // The implementation never finished the transaction.
+ err = UNKNOWN_ERROR; // XXX special error code instead?
- reply->setDataPosition(0 /* pos */);
- }
+ reply->setDataPosition(0 /* pos */);
+ }
- // Release all temporary storage now that scatter-gather data
- // has been consolidated, either by calling the TransactCallback,
- // if wasSent() == true or clearing the reply parcel (setDataOffset above).
- replyContext->getStorage()->release(env);
+ // Release all temporary storage now that scatter-gather data
+ // has been consolidated, either by calling the TransactCallback,
+ // if wasSent() == true or clearing the reply parcel (setDataOffset above).
+ replyContext->getStorage()->release(env);
- // We cannot permanently pass ownership of "data" and "reply" over to their
- // Java object wrappers (we don't own them ourselves).
+ // We cannot permanently pass ownership of "data" and "reply" over to their
+ // Java object wrappers (we don't own them ourselves).
+ replyContext->setParcel(
+ NULL /* parcel */, false /* assumeOwnership */);
- JHwParcel::GetNativeContext(env, requestObj.get())->setParcel(
- NULL /* parcel */, false /* assumeOwnership */);
+ }
- replyContext->setParcel(
+ JHwParcel::GetNativeContext(env, requestObj.get())->setParcel(
NULL /* parcel */, false /* assumeOwnership */);
return err;
@@ -293,6 +301,8 @@ static jobject JHwBinder_native_getService(
jstring ifaceNameObj,
jstring serviceNameObj) {
+ using ::android::vintf::operator<<;
+
if (ifaceNameObj == NULL) {
jniThrowException(env, "java/lang/NullPointerException", NULL);
return NULL;
@@ -302,20 +312,6 @@ static jobject JHwBinder_native_getService(
return NULL;
}
- const char *ifaceName = env->GetStringUTFChars(ifaceNameObj, NULL);
- if (ifaceName == NULL) {
- return NULL; // XXX exception already pending?
- }
- const char *serviceName = env->GetStringUTFChars(serviceNameObj, NULL);
- if (serviceName == NULL) {
- env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
- return NULL; // XXX exception already pending?
- }
-
- LOG(INFO) << "looking for service '"
- << serviceName
- << "'";
-
auto manager = hardware::defaultServiceManager();
if (manager == nullptr) {
@@ -324,20 +320,50 @@ static jobject JHwBinder_native_getService(
return NULL;
}
- Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceName, serviceName);
+ const char *ifaceNameCStr = env->GetStringUTFChars(ifaceNameObj, NULL);
+ if (ifaceNameCStr == NULL) {
+ return NULL; // XXX exception already pending?
+ }
+ std::string ifaceName(ifaceNameCStr);
+ env->ReleaseStringUTFChars(ifaceNameObj, ifaceNameCStr);
+ ::android::hardware::hidl_string ifaceNameHStr;
+ ifaceNameHStr.setToExternal(ifaceName.c_str(), ifaceName.size());
+
+ const char *serviceNameCStr = env->GetStringUTFChars(serviceNameObj, NULL);
+ if (serviceNameCStr == NULL) {
+ return NULL; // XXX exception already pending?
+ }
+ std::string serviceName(serviceNameCStr);
+ env->ReleaseStringUTFChars(serviceNameObj, serviceNameCStr);
+ ::android::hardware::hidl_string serviceNameHStr;
+ serviceNameHStr.setToExternal(serviceName.c_str(), serviceName.size());
+
+ LOG(INFO) << "Looking for service "
+ << ifaceName
+ << "/"
+ << serviceName;
+
+ ::android::vintf::Transport transport =
+ ::android::hardware::getTransport(ifaceName);
+ if ( transport != ::android::vintf::Transport::EMPTY
+ && transport != ::android::vintf::Transport::HWBINDER) {
+ LOG(ERROR) << "service " << ifaceName << " declares transport method "
+ << transport << " but framework expects "
+ << ::android::vintf::Transport::HWBINDER;
+ signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
+ return NULL;
+ }
+
+ Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceNameHStr, serviceNameHStr);
if (!ret.isOk()) {
signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
+ return NULL;
}
sp<hardware::IBinder> service = hardware::toBinder<
hidl::base::V1_0::IBase, hidl::base::V1_0::BpHwBase>(ret);
- env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
- ifaceName = NULL;
- env->ReleaseStringUTFChars(serviceNameObj, serviceName);
- serviceName = NULL;
-
if (service == NULL) {
signalExceptionForError(env, NAME_NOT_FOUND);
return NULL;
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
index b2dee0689ee0..8590ecf3bb19 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -382,7 +382,7 @@ static void JHwBlob_native_putString(
s = nullptr;
hidl_string tmp;
- tmp.setToExternal(static_cast<const char *>(subBlob->data()), size);
+ tmp.setToExternal(static_cast<const char *>(subBlob->data()), size - 1);
sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
blob->write(offset, &tmp, sizeof(tmp));
diff --git a/core/jni/android_os_seccomp.cpp b/core/jni/android_os_seccomp.cpp
new file mode 100644
index 000000000000..dd5622d80e45
--- /dev/null
+++ b/core/jni/android_os_seccomp.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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 "core_jni_helpers.h"
+#include "JniConstants.h"
+#include "utils/Log.h"
+#include "seccomp_policy.h"
+
+static void Seccomp_setPolicy(JNIEnv* /*env*/) {
+ if (!set_seccomp_filter()) {
+ ALOGE("Failed to set seccomp policy - killing");
+ exit(1);
+ }
+}
+
+static const JNINativeMethod method_table[] = {
+ NATIVE_METHOD(Seccomp, setPolicy, "()V"),
+};
+
+namespace android {
+
+int register_android_os_seccomp(JNIEnv* env) {
+ return android::RegisterMethodsOrDie(env, "android/os/Seccomp",
+ method_table, NELEM(method_table));
+}
+
+}
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index b57f2362a284..a03d3c503e1c 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -252,25 +252,26 @@ void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jin
if (t_pri >= ANDROID_PRIORITY_BACKGROUND) {
// This task wants to stay at background
// update its cpuset so it doesn't only run on bg core(s)
-#ifdef ENABLE_CPUSETS
- int err = set_cpuset_policy(t_pid, sp);
- if (err != NO_ERROR) {
- signalExceptionForGroupError(env, -err, t_pid);
- break;
+ if (cpusets_enabled()) {
+ int err = set_cpuset_policy(t_pid, sp);
+ if (err != NO_ERROR) {
+ signalExceptionForGroupError(env, -err, t_pid);
+ break;
+ }
}
-#endif
continue;
}
}
int err;
-#ifdef ENABLE_CPUSETS
- // set both cpuset and cgroup for general threads
- err = set_cpuset_policy(t_pid, sp);
- if (err != NO_ERROR) {
- signalExceptionForGroupError(env, -err, t_pid);
- break;
+
+ if (cpusets_enabled()) {
+ // set both cpuset and cgroup for general threads
+ err = set_cpuset_policy(t_pid, sp);
+ if (err != NO_ERROR) {
+ signalExceptionForGroupError(env, -err, t_pid);
+ break;
+ }
}
-#endif
err = set_sched_policy(t_pid, sp);
if (err != NO_ERROR) {
@@ -291,7 +292,6 @@ jint android_os_Process_getProcessGroup(JNIEnv* env, jobject clazz, jint pid)
return (int) sp;
}
-#ifdef ENABLE_CPUSETS
/** Sample CPUset list format:
* 0-3,4,6-8
*/
@@ -367,7 +367,6 @@ static void get_cpuset_cores_for_policy(SchedPolicy policy, cpu_set_t *cpu_set)
}
return;
}
-#endif
/**
@@ -376,22 +375,21 @@ static void get_cpuset_cores_for_policy(SchedPolicy policy, cpu_set_t *cpu_set)
* them in the passed in cpu_set_t
*/
void get_exclusive_cpuset_cores(SchedPolicy policy, cpu_set_t *cpu_set) {
-#ifdef ENABLE_CPUSETS
- int i;
- cpu_set_t tmp_set;
- get_cpuset_cores_for_policy(policy, cpu_set);
- for (i = 0; i < SP_CNT; i++) {
- if ((SchedPolicy) i == policy) continue;
- get_cpuset_cores_for_policy((SchedPolicy)i, &tmp_set);
- // First get cores exclusive to one set or the other
- CPU_XOR(&tmp_set, cpu_set, &tmp_set);
- // Then get the ones only in cpu_set
- CPU_AND(cpu_set, cpu_set, &tmp_set);
+ if (cpusets_enabled()) {
+ int i;
+ cpu_set_t tmp_set;
+ get_cpuset_cores_for_policy(policy, cpu_set);
+ for (i = 0; i < SP_CNT; i++) {
+ if ((SchedPolicy) i == policy) continue;
+ get_cpuset_cores_for_policy((SchedPolicy)i, &tmp_set);
+ // First get cores exclusive to one set or the other
+ CPU_XOR(&tmp_set, cpu_set, &tmp_set);
+ // Then get the ones only in cpu_set
+ CPU_AND(cpu_set, cpu_set, &tmp_set);
+ }
+ } else {
+ CPU_ZERO(cpu_set);
}
-#else
- (void) policy;
- CPU_ZERO(cpu_set);
-#endif
return;
}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index a32dbad7838f..3498108991fa 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -253,13 +253,36 @@ static void DropCapabilitiesBoundingSet(JNIEnv* env) {
ALOGE("prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify "
"your kernel is compiled with file capabilities support");
} else {
+ ALOGE("prctl(PR_CAPBSET_DROP, %d) failed: %s", i, strerror(errno));
RuntimeAbort(env, __LINE__, "prctl(PR_CAPBSET_DROP) failed");
}
}
}
}
-static void SetCapabilities(JNIEnv* env, int64_t permitted, int64_t effective) {
+static void SetInheritable(JNIEnv* env, uint64_t inheritable) {
+ __user_cap_header_struct capheader;
+ memset(&capheader, 0, sizeof(capheader));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ capheader.pid = 0;
+
+ __user_cap_data_struct capdata[2];
+ if (capget(&capheader, &capdata[0]) == -1) {
+ ALOGE("capget failed: %s", strerror(errno));
+ RuntimeAbort(env, __LINE__, "capget failed");
+ }
+
+ capdata[0].inheritable = inheritable;
+ capdata[1].inheritable = inheritable >> 32;
+
+ if (capset(&capheader, &capdata[0]) == -1) {
+ ALOGE("capset(inh=%" PRIx64 ") failed: %s", inheritable, strerror(errno));
+ RuntimeAbort(env, __LINE__, "capset failed");
+ }
+}
+
+static void SetCapabilities(JNIEnv* env, uint64_t permitted, uint64_t effective,
+ uint64_t inheritable) {
__user_cap_header_struct capheader;
memset(&capheader, 0, sizeof(capheader));
capheader.version = _LINUX_CAPABILITY_VERSION_3;
@@ -271,9 +294,12 @@ static void SetCapabilities(JNIEnv* env, int64_t permitted, int64_t effective) {
capdata[1].effective = effective >> 32;
capdata[0].permitted = permitted;
capdata[1].permitted = permitted >> 32;
+ capdata[0].inheritable = inheritable;
+ capdata[1].inheritable = inheritable >> 32;
if (capset(&capheader, &capdata[0]) == -1) {
- ALOGE("capset(%" PRId64 ", %" PRId64 ") failed", permitted, effective);
+ ALOGE("capset(perm=%" PRIx64 ", eff=%" PRIx64 ", inh=%" PRIx64 ") failed: %s", permitted,
+ effective, inheritable, strerror(errno));
RuntimeAbort(env, __LINE__, "capset failed");
}
}
@@ -508,6 +534,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
EnableKeepCapabilities(env);
}
+ SetInheritable(env, permittedCapabilities);
DropCapabilitiesBoundingSet(env);
bool use_native_bridge = !is_system_server && (instructionSet != NULL)
@@ -580,7 +607,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
}
}
- SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
+ SetCapabilities(env, permittedCapabilities, effectiveCapabilities, permittedCapabilities);
SetSchedulerPolicy(env);
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index ad7d744cb693..3e74d1c855b3 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -132,6 +132,7 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o
pointer = _env->CallStaticLongMethod(nioAccessClass,
getBasePointerID, buffer);
if (pointer != 0L) {
+ *offset = 0;
*array = NULL;
return reinterpret_cast<void *>(pointer);
}
@@ -139,6 +140,7 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
if (*array == NULL) {
+ *offset = 0;
return (void*) NULL;
}
*offset = _env->CallStaticIntMethod(nioAccessClass,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 790b0f6e817f..7d4f99db56c8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1576,6 +1576,16 @@
<permission android:name="android.permission.RECEIVE_STK_COMMANDS"
android:protectionLevel="signature|privileged" />
+ <!-- Must be required by an ImsService to ensure that only the
+ system can bind to it.
+ <p>Protection level: signature|privileged
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_IMS_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
+
<!-- ================================== -->
<!-- Permissions for sdcard interaction -->
<!-- ================================== -->
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index c4e8e9cb63bf..40c994196137 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -45,7 +45,7 @@
android:textColor="?attr/colorAccent"
android:gravity="center_vertical"
android:layout_alignParentTop="true"
- android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:singleLine="true" />
<TextView
@@ -59,7 +59,7 @@
android:paddingEnd="?attr/dialogPreferredPadding"
android:paddingTop="8dp"
android:layout_below="@id/profile_button"
- android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:paddingBottom="8dp" />
</RelativeLayout>
diff --git a/core/res/res/values-mcc208-mnc10/config.xml b/core/res/res/values-mcc208-mnc10/config.xml
index d3640e5c4153..3ed78181ffe6 100644
--- a/core/res/res/values-mcc208-mnc10/config.xml
+++ b/core/res/res/values-mcc208-mnc10/config.xml
@@ -31,28 +31,4 @@
<item>[ApnSettingV3]INTERNET NRJ,internetnrj,,,,,,,,,208,10,,DUN,,,true,0,,,,,,,gid,4E</item>
</string-array>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-
</resources>
diff --git a/core/res/res/values-mcc214-mnc01/config.xml b/core/res/res/values-mcc214-mnc01/config.xml
index 895b770d771c..24150a782d22 100644
--- a/core/res/res/values-mcc214-mnc01/config.xml
+++ b/core/res/res/values-mcc214-mnc01/config.xml
@@ -40,27 +40,4 @@
<item>INTERNET,airtelnet.es,,,vodafone,vodafone,,,,,214,01,1,DUN</item>
</string-array>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-
</resources>
diff --git a/core/res/res/values-mcc334-mnc050/config.xml b/core/res/res/values-mcc334-mnc050/config.xml
index f6777d0391df..616a8e8fa283 100644
--- a/core/res/res/values-mcc334-mnc050/config.xml
+++ b/core/res/res/values-mcc334-mnc050/config.xml
@@ -40,4 +40,8 @@
<item>Modem,modem.iusacellgsm.mx,,,iusacellgsm,iusacellgsm,,,,,334,050,1,DUN</item>
</string-array>
+ <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
+ <string-array translatable="false" name="config_twoDigitNumberPattern">
+ <item>"#9"</item>
+ </string-array>
</resources>
diff --git a/core/res/res/values-mcc334-mnc090/config.xml b/core/res/res/values-mcc334-mnc090/config.xml
new file mode 100644
index 000000000000..1632a4239923
--- /dev/null
+++ b/core/res/res/values-mcc334-mnc090/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
+
+ <string-array translatable="false" name="config_twoDigitNumberPattern">
+ <item>"#9"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc704-mnc01/config.xml b/core/res/res/values-mcc704-mnc01/config.xml
new file mode 100644
index 000000000000..10b647044c73
--- /dev/null
+++ b/core/res/res/values-mcc704-mnc01/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources>
+ <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
+ <string-array name="config_twoDigitNumberPattern">
+ <item>"*1"</item>
+ <item>"*5"</item>
+ <item>"*9"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc708-mnc001/config.xml b/core/res/res/values-mcc708-mnc001/config.xml
new file mode 100755
index 000000000000..7b7c48d46b14
--- /dev/null
+++ b/core/res/res/values-mcc708-mnc001/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources>
+ <string-array translatable="false" name="config_twoDigitNumberPattern">
+ <item>"*1"</item>
+ <item>"*5"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index dbc4324ec92a..09bf39c2cd9f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2267,6 +2267,13 @@
<!-- Whether to use voip audio mode for ims call -->
<bool name="config_use_voip_mode_for_ims">false</bool>
+ <!-- ImsService package name to bind to by default. If none is specified in an overlay, an
+ empty string is passed in -->
+ <string name="config_ims_package"/>
+
+ <!-- Flag specifying whether or not IMS will use the dynamic ImsResolver -->
+ <bool name="config_dynamic_bind_ims">false</bool>
+
<bool name="config_networkSamplingWakesDevice">true</bool>
<string-array translatable="false" name="config_cdma_home_system" />
@@ -2676,6 +2683,6 @@
<!-- An array of packages for which notifications cannot be blocked. -->
<string-array translatable="false" name="config_nonBlockableNotificationPackages" />
- <!-- Component name of the default cell broadcast receiver -->
- <string name="config_defaultCellBroadcastReceiverComponent" translatable="false">com.android.cellbroadcastreceiver/.PrivilegedCellBroadcastReceiver</string>
+ <!-- Package name of the default cell broadcast receiver -->
+ <string name="config_defaultCellBroadcastReceiverPkg" translatable="false">com.android.cellbroadcastreceiver</string>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 426d2ebecab0..42316980aa2d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -101,6 +101,8 @@
<!-- Displayed when the user dialed an MMI code whose function
could not be performed because FDN is enabled. This will be displayed in a toast. -->
<string name="mmiFdnError">Operation is restricted to fixed dialing numbers only.</string>
+ <!-- Displayed when a carrier does not support call forwarding queries when roaming. -->
+ <string name="mmiErrorWhileRoaming">Can not change call forwarding settings from your phone while you are roaming.</string>
<!-- Displayed when a phone feature such as call barring was activated. -->
<string name="serviceEnabled">Service was enabled.</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9db131b373a5..dbeda0b14879 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -252,6 +252,8 @@
<java-symbol type="bool" name="config_enableBurnInProtection" />
<java-symbol type="bool" name="config_hotswapCapable" />
<java-symbol type="bool" name="config_mms_content_disposition_support" />
+ <java-symbol type="string" name="config_ims_package" />
+ <java-symbol type="bool" name="config_dynamic_bind_ims" />
<java-symbol type="bool" name="config_networkSamplingWakesDevice" />
<java-symbol type="bool" name="config_showMenuShortcutsWhenKeyboardPresent" />
<java-symbol type="bool" name="config_sip_wifi_only" />
@@ -723,6 +725,7 @@
<java-symbol type="string" name="mmiComplete" />
<java-symbol type="string" name="mmiError" />
<java-symbol type="string" name="mmiFdnError" />
+ <java-symbol type="string" name="mmiErrorWhileRoaming" />
<java-symbol type="string" name="month_day_year" />
<java-symbol type="string" name="more_item_label" />
<java-symbol type="string" name="needPuk" />
@@ -2738,5 +2741,5 @@
<!-- Network Recommendation -->
<java-symbol type="array" name="config_networkRecommendationPackageNames" />
- <java-symbol type="string" name="config_defaultCellBroadcastReceiverComponent" />
+ <java-symbol type="string" name="config_defaultCellBroadcastReceiverPkg" />
</resources>
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 33a9265278de..8ac52522f2a3 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -21,6 +21,7 @@ LOCAL_SRC_FILES := \
$(call all-java-files-under, DisabledTestApp/src) \
$(call all-java-files-under, EnabledTestApp/src)
+LOCAL_DX_FLAGS := --core-library
LOCAL_AAPT_FLAGS = -0 dat -0 gld -c fa
LOCAL_STATIC_JAVA_LIBRARIES := \
core-tests-support \
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
index 836ede61bba6..14b032e37f4c 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
@@ -31,9 +31,28 @@ LOCAL_DEX_PREOPT := false
LOCAL_JAVACFLAGS := -nowarn
+mainDexList:= \
+ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
-D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+ $(hide) mkdir -p $(dir $@)
+ $(MAINDEXCLASSES) $< 1>$@
+ echo "com/android/multidexlegacyandexception/Test.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
index 2915914033f7..208eceb6273d 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
@@ -29,13 +29,32 @@ LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp
LOCAL_DEX_PREOPT := false
+mainDexList:= \
+ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
-D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
include $(BUILD_PACKAGE)
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+ $(hide) mkdir -p $(dir $@)
+ $(MAINDEXCLASSES) $< 1>$@
+ echo "com/android/multidexlegacytestapp/Test.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+endif
+
## The application with a full main dex
include $(CLEAR_VARS)
@@ -51,9 +70,28 @@ LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp2
LOCAL_DEX_PREOPT := false
+mainDexList2:= \
+ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList2)
LOCAL_JACK_FLAGS := -D jack.dex.output.policy=multidex -D jack.preprocessor=true\
-D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList2): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+ $(hide) mkdir -p $(dir $@)
+ $(MAINDEXCLASSES) $< 1>$@
+ echo "com/android/multidexlegacytestapp/Test.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList2)
+endif \ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
index 2732372263a8..99bcd6c62b56 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
@@ -26,8 +26,20 @@ LOCAL_PACKAGE_NAME := MultiDexLegacyTestServices
LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
+mainDexList:= \
+ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.dex.output.multidex.legacy=true
LOCAL_DEX_PREOPT := false
include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+ $(hide) mkdir -p $(dir $@)
+ $(MAINDEXCLASSES) $< 1>$@
+
+$(built_dex_intermediate): $(mainDexList)
+endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
index b4a666f352fa..1c7d80790120 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
@@ -28,9 +28,28 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
LOCAL_DEX_PREOPT := false
+mainDexList:= \
+ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
-D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+ $(hide) mkdir -p $(dir $@)
+ $(MAINDEXCLASSES) $< 1>$@
+ echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+endif \ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
index f38bd4f2321b..b77cf31edc62 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
@@ -28,9 +28,28 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
LOCAL_DEX_PREOPT := false
+mainDexList:= \
+ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
-D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+ $(hide) mkdir -p $(dir $@)
+ $(MAINDEXCLASSES) $< 1>$@
+ echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
index 5bc2c95e623d..3631626f6b31 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
@@ -26,11 +26,31 @@ LOCAL_PACKAGE_NAME := MultiDexLegacyVersionedTestApp_v3
LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
+mainDexList:= \
+ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
LOCAL_DEX_PREOPT := false
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
-D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+ $(hide) mkdir -p $(dir $@)
+ $(MAINDEXCLASSES) $< 1>$@
+ echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+endif
+
diff --git a/core/tests/systemproperties/Android.mk b/core/tests/systemproperties/Android.mk
index e16c3678dee7..4c2e2247a113 100644
--- a/core/tests/systemproperties/Android.mk
+++ b/core/tests/systemproperties/Android.mk
@@ -8,6 +8,7 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
$(call all-java-files-under, src)
+LOCAL_DX_FLAGS := --core-library
LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksCoreSystemPropertiesTests
diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk
index 0a814f39b637..05fec5ee603f 100644
--- a/legacy-test/Android.mk
+++ b/legacy-test/Android.mk
@@ -50,5 +50,5 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := src/android/test/PerformanceTestCase.java
LOCAL_MODULE := legacy-performance-test-hostdex
-include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)
+include $(BUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY)
endif # HOST_OS == linux
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index a7cbf5e562d1..bf9423ce5c02 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -167,7 +167,7 @@ hwui_c_includes += \
ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
hwui_cflags += -DANDROID_ENABLE_RENDERSCRIPT
hwui_c_includes += \
- $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,) \
+ $(call intermediates-dir-for,STATIC_LIBRARIES,TARGET,) \
frameworks/rs/cpp \
frameworks/rs
endif
diff --git a/libs/hwui/hwui_static_deps.mk b/libs/hwui/hwui_static_deps.mk
index dca78b38e942..8dae27386118 100644
--- a/libs/hwui/hwui_static_deps.mk
+++ b/libs/hwui/hwui_static_deps.mk
@@ -28,5 +28,5 @@ LOCAL_SHARED_LIBRARIES += \
libandroidfw
ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
- LOCAL_SHARED_LIBRARIES += libRS libRScpp
+ LOCAL_SHARED_LIBRARIES += libRScpp
endif
diff --git a/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
new file mode 100644
index 000000000000..a438afd5c889
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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 "TestSceneBase.h"
+
+class ShadowShaderAnimation;
+
+static TestScene::Registrar _ShadowShader(TestScene::Info{
+ "shadowshader",
+ "A set of overlapping shadowed areas with simple tessellation useful for"
+ " benchmarking shadow shader performance.",
+ TestScene::simpleCreateScene<ShadowShaderAnimation>
+});
+
+class ShadowShaderAnimation : public TestScene {
+public:
+ std::vector< sp<RenderNode> > cards;
+ void createContent(int width, int height, TestCanvas& canvas) override {
+ canvas.drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+ canvas.insertReorderBarrier(true);
+
+ int outset = 50;
+ for (int i = 0; i < 10; i++) {
+ sp<RenderNode> card = createCard(outset, outset,
+ width - (outset * 2), height - (outset * 2));
+ canvas.drawRenderNode(card.get());
+ cards.push_back(card);
+ }
+
+ canvas.insertReorderBarrier(false);
+ }
+ void doFrame(int frameNr) override {
+ int curFrame = frameNr % 10;
+ for (size_t ci = 0; ci < cards.size(); ci++) {
+ cards[ci]->mutateStagingProperties().setTranslationX(curFrame);
+ cards[ci]->mutateStagingProperties().setTranslationY(curFrame);
+ cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+ }
+ }
+private:
+ sp<RenderNode> createCard(int x, int y, int width, int height) {
+ return TestUtils::createNode(x, y, x + width, y + height,
+ [width, height](RenderProperties& props, TestCanvas& canvas) {
+ props.setElevation(1000);
+
+ // Set 0 radius, no clipping, so shadow is easy to compute. Slightly transparent outline
+ // to signal contents aren't opaque (not necessary though, as elevation is so high, no
+ // inner content to cut out)
+ props.mutableOutline().setRoundRect(0, 0, width, height, 0, 0.99f);
+ props.mutableOutline().setShouldClip(false);
+
+ // don't draw anything to card's canvas - we just want the shadow
+ });
+ }
+};
diff --git a/native/android/Android.mk b/native/android/Android.mk
index da4e4bac6dbc..1f69df1ae21d 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -1,6 +1,8 @@
BASE_PATH := $(call my-dir)
LOCAL_PATH:= $(call my-dir)
+common_cflags := -Wall -Werror -Wunused -Wunreachable-code
+
include $(CLEAR_VARS)
# our source files
@@ -42,6 +44,23 @@ LOCAL_C_INCLUDES += \
LOCAL_MODULE := libandroid
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+LOCAL_CFLAGS += $(common_cflags)
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Network library.
+include $(CLEAR_VARS)
+LOCAL_MODULE := libandroid_net
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_SRC_FILES:= \
+ net.c \
+
+LOCAL_SHARED_LIBRARIES := \
+ libnetd_client \
+
+LOCAL_C_INCLUDES += \
+ frameworks/base/native/include \
+ bionic/libc/dns/include \
+ system/netd/include \
include $(BUILD_SHARED_LIBRARY)
diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java
index acee5ddd5f8f..3831cf7285da 100644
--- a/obex/javax/obex/ServerSession.java
+++ b/obex/javax/obex/ServerSession.java
@@ -658,6 +658,11 @@ public final class ServerSession extends ObexSession implements Runnable {
*/
byte[] sendData = new byte[totalLength];
int maxRxLength = ObexHelper.getMaxRxPacketSize(mTransport);
+ if (maxRxLength > mMaxPacketLength) {
+ if(V) Log.v(TAG,"Set maxRxLength to min of maxRxServrLen:" + maxRxLength +
+ " and MaxNegotiated from Client: " + mMaxPacketLength);
+ maxRxLength = mMaxPacketLength;
+ }
sendData[0] = (byte)code;
sendData[1] = length[2];
sendData[2] = length[3];
diff --git a/packages/CarrierDefaultApp/AndroidManifest.xml b/packages/CarrierDefaultApp/AndroidManifest.xml
index e2080b08c4df..d9109202f916 100644
--- a/packages/CarrierDefaultApp/AndroidManifest.xml
+++ b/packages/CarrierDefaultApp/AndroidManifest.xml
@@ -31,7 +31,7 @@
<application android:label="@string/app_name" >
<receiver android:name="com.android.carrierdefaultapp.CarrierDefaultBroadcastReceiver">
<intent-filter>
- <action android:name="android.intent.action.CARRIER_SIGNAL_REDIRECTED" />
+ <action android:name="com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED" />
</intent-filter>
</receiver>
<activity android:name="com.android.carrierdefaultapp.CaptivePortalLaunchActivity"
diff --git a/packages/DocumentsUI/Android.mk b/packages/DocumentsUI/Android.mk
index 9d44a6deb0c8..29035ab9bbba 100644
--- a/packages/DocumentsUI/Android.mk
+++ b/packages/DocumentsUI/Android.mk
@@ -12,6 +12,7 @@ LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-appcompat
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v13
# Supplies material design components, e.g. Snackbar.
LOCAL_STATIC_JAVA_LIBRARIES += android-support-design
+LOCAL_STATIC_JAVA_LIBRARIES += android-support-transition
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-recyclerview
LOCAL_STATIC_JAVA_LIBRARIES += guava
@@ -22,6 +23,7 @@ LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_RESOURCE_DIR += \
frameworks/support/v7/appcompat/res \
frameworks/support/design/res \
+ frameworks/support/transition/res \
frameworks/support/v7/recyclerview/res
# Again, required to pull in appcompat resources. See abovementioned demo code.
@@ -29,6 +31,7 @@ LOCAL_AAPT_FLAGS := \
--auto-add-overlay \
--extra-packages android.support.v7.appcompat \
--extra-packages android.support.design \
+ --extra-packages android.support.transition \
--extra-packages android.support.v7.recyclerview
LOCAL_JACK_FLAGS := \
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
index 859763b833f0..08b82d0d2d4c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
@@ -20,33 +20,14 @@ import android.annotation.Nullable;
import android.provider.DocumentsContract.Document;
import com.android.documentsui.model.DocumentInfo;
-import com.android.internal.util.Predicate;
-public class MimePredicate implements Predicate<DocumentInfo> {
- private final String[] mFilters;
-
- private static final String APK_TYPE = "application/vnd.android.package-archive";
+public class MimePredicate {
/**
* MIME types that are visual in nature. For example, they should always be
* shown as thumbnails in list mode.
*/
public static final String[] VISUAL_MIMES = new String[] { "image/*", "video/*" };
- public MimePredicate(String[] filters) {
- mFilters = filters;
- }
-
- @Override
- public boolean apply(DocumentInfo doc) {
- if (doc.isDirectory()) {
- return true;
- }
- if (mimeMatches(mFilters, doc.mimeType)) {
- return true;
- }
- return false;
- }
-
public static boolean mimeMatches(String[] filters, String[] tests) {
if (tests == null) {
return false;
@@ -97,10 +78,6 @@ public class MimePredicate implements Predicate<DocumentInfo> {
}
}
- public static boolean isApkType(@Nullable String mimeType) {
- return APK_TYPE.equals(mimeType);
- }
-
public static boolean isDirectoryType(@Nullable String mimeType) {
return Document.MIME_TYPE_DIR.equals(mimeType);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index 6ef9154451a2..6bf8cccbfa21 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -39,7 +39,6 @@ import android.util.Log;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
-import com.android.internal.util.Predicate;
import com.google.android.collect.Sets;
@@ -47,6 +46,7 @@ import libcore.io.IoUtils;
import java.io.IOException;
import java.util.Set;
+import java.util.function.Predicate;
public class RecentsProvider extends ContentProvider {
private static final String TAG = "RecentsProvider";
@@ -269,7 +269,7 @@ public class RecentsProvider extends ContentProvider {
purgeByAuthority(new Predicate<String>() {
@Override
- public boolean apply(String authority) {
+ public boolean test(String authority) {
// Purge unknown authorities
return !knownAuth.contains(authority);
}
@@ -290,7 +290,7 @@ public class RecentsProvider extends ContentProvider {
if (!packageAuth.isEmpty()) {
purgeByAuthority(new Predicate<String>() {
@Override
- public boolean apply(String authority) {
+ public boolean test(String authority) {
// Purge authority matches
return packageAuth.contains(authority);
}
@@ -320,7 +320,7 @@ public class RecentsProvider extends ContentProvider {
cursor.getColumnIndex(RecentColumns.STACK));
DurableUtils.readFromArray(rawStack, stack);
- if (stack.root != null && predicate.apply(stack.root.authority)) {
+ if (stack.root != null && predicate.test(stack.root.authority)) {
final String key = getCursorString(cursor, RecentColumns.KEY);
db.delete(TABLE_RECENT, RecentColumns.KEY + "=?", new String[] { key });
}
@@ -336,7 +336,7 @@ public class RecentsProvider extends ContentProvider {
try {
while (cursor.moveToNext()) {
final String authority = getCursorString(cursor, StateColumns.AUTHORITY);
- if (predicate.apply(authority)) {
+ if (predicate.test(authority)) {
db.delete(TABLE_STATE, StateColumns.AUTHORITY + "=?", new String[] {
authority });
if (DEBUG) Log.d(TAG, "Purged state for " + authority);
@@ -354,7 +354,7 @@ public class RecentsProvider extends ContentProvider {
cursor.getColumnIndex(ResumeColumns.STACK));
DurableUtils.readFromArray(rawStack, stack);
- if (stack.root != null && predicate.apply(stack.root.authority)) {
+ if (stack.root != null && predicate.test(stack.root.authority)) {
final String packageName = getCursorString(
cursor, ResumeColumns.PACKAGE_NAME);
db.delete(TABLE_RESUME, ResumeColumns.PACKAGE_NAME + "=?",
diff --git a/packages/ExternalStorageProvider/Android.mk b/packages/ExternalStorageProvider/Android.mk
index ec6af2f0b338..fbf3782c979d 100644
--- a/packages/ExternalStorageProvider/Android.mk
+++ b/packages/ExternalStorageProvider/Android.mk
@@ -5,7 +5,10 @@ LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-documents-archive
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-documents-archive \
+ android-support-annotations
+
LOCAL_PACKAGE_NAME := ExternalStorageProvider
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/PrintSpooler/res/layout/no_print_services_message.xml b/packages/PrintSpooler/res/layout/no_print_services_message.xml
new file mode 100644
index 000000000000..78726584f574
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/no_print_services_message.xml
@@ -0,0 +1,42 @@
+<?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="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeightSmall"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:orientation="horizontal"
+ android:gravity="start|center_vertical">
+
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="32dip">
+ <HorizontalScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:text="@string/print_no_print_services"
+ android:scrollHorizontally="true"
+ android:singleLine="true" />
+ </HorizontalScrollView>
+ </RelativeLayout>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
index c06e8496a7d5..72004efc07a7 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
@@ -26,6 +26,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
+import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.DataSetObserver;
import android.net.Uri;
@@ -95,20 +96,39 @@ public class AddPrinterActivity extends ListActivity implements AdapterView.OnIt
*/
private RecommendedServicesAdapter mRecommendedServicesAdapter;
+ private static final String PKG_NAME_VENDING = "com.android.vending";
+ private boolean mHasVending;
+ private NoPrintServiceMessageAdapter mNoPrintServiceMessageAdapter;
+
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.add_printer_activity);
+ try {
+ getPackageManager().getPackageInfo(PKG_NAME_VENDING, 0);
+ mHasVending = true;
+ } catch (PackageManager.NameNotFoundException e) {
+ mHasVending = false;
+ }
mEnabledServicesAdapter = new EnabledServicesAdapter();
mDisabledServicesAdapter = new DisabledServicesAdapter();
- mRecommendedServicesAdapter = new RecommendedServicesAdapter();
+ if (mHasVending) {
+ mRecommendedServicesAdapter = new RecommendedServicesAdapter();
+ } else {
+ mNoPrintServiceMessageAdapter = new NoPrintServiceMessageAdapter();
+ }
ArrayList<ActionAdapter> adapterList = new ArrayList<>(3);
adapterList.add(mEnabledServicesAdapter);
- adapterList.add(mRecommendedServicesAdapter);
+ if (mHasVending) {
+ adapterList.add(mRecommendedServicesAdapter);
+ }
adapterList.add(mDisabledServicesAdapter);
+ if (!mHasVending) {
+ adapterList.add(mNoPrintServiceMessageAdapter);
+ }
setListAdapter(new CombinedAdapter(adapterList));
@@ -119,8 +139,10 @@ public class AddPrinterActivity extends ListActivity implements AdapterView.OnIt
getLoaderManager().initLoader(LOADER_ID_ENABLED_SERVICES, null, printServiceLoaderCallbacks);
getLoaderManager().initLoader(LOADER_ID_DISABLED_SERVICES, null, printServiceLoaderCallbacks);
- getLoaderManager().initLoader(LOADER_ID_RECOMMENDED_SERVICES, null,
- new PrintServicePrintServiceRecommendationLoaderCallbacks());
+ if (mHasVending) {
+ getLoaderManager().initLoader(LOADER_ID_RECOMMENDED_SERVICES, null,
+ new PrintServicePrintServiceRecommendationLoaderCallbacks());
+ }
getLoaderManager().initLoader(LOADER_ID_ALL_SERVICES, null, printServiceLoaderCallbacks);
}
@@ -162,7 +184,11 @@ public class AddPrinterActivity extends ListActivity implements AdapterView.OnIt
mDisabledServicesAdapter.updateData(data);
break;
case LOADER_ID_ALL_SERVICES:
- mRecommendedServicesAdapter.updateInstalledServices(data);
+ if (mHasVending) {
+ mRecommendedServicesAdapter.updateInstalledServices(data);
+ } else {
+ mNoPrintServiceMessageAdapter.updateInstalledServices(data);
+ }
default:
// not reached
}
@@ -179,7 +205,11 @@ public class AddPrinterActivity extends ListActivity implements AdapterView.OnIt
mDisabledServicesAdapter.updateData(null);
break;
case LOADER_ID_ALL_SERVICES:
- mRecommendedServicesAdapter.updateInstalledServices(null);
+ if (mHasVending) {
+ mRecommendedServicesAdapter.updateInstalledServices(null);
+ } else {
+ mNoPrintServiceMessageAdapter.updateInstalledServices(null);
+ }
break;
default:
// not reached
@@ -788,4 +818,61 @@ public class AddPrinterActivity extends ListActivity implements AdapterView.OnIt
filterRecommendations();
}
}
+
+ private class NoPrintServiceMessageAdapter extends ActionAdapter {
+ private boolean mHasPrintService;
+
+ void updateInstalledServices(@Nullable List<PrintServiceInfo> services) {
+ if (services == null || services.isEmpty()) {
+ mHasPrintService = false;
+ } else {
+ mHasPrintService = true;
+ }
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getCount() {
+ return mHasPrintService ? 0 : 1;
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return 1;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return 0;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return null;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(R.layout.no_print_services_message,
+ parent, false);
+ }
+ return convertView;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return position != 0;
+ }
+
+ @Override
+ public void performAction(@IntRange(from = 0) int position) {
+ return;
+ }
+ }
}
diff --git a/packages/SettingsLib/common.mk b/packages/SettingsLib/common.mk
index cf0ba6c6fd62..081553493cf9 100644
--- a/packages/SettingsLib/common.mk
+++ b/packages/SettingsLib/common.mk
@@ -24,5 +24,9 @@ LOCAL_AAPT_FLAGS += --auto-add-overlay --extra-packages com.android.settingslib
LOCAL_STATIC_JAVA_LIBRARIES += \
android-support-annotations \
android-support-v4 \
+ android-support-v7-appcompat \
+ android-support-v7-preference \
+ android-support-v7-recyclerview \
+ android-support-v14-preference \
SettingsLib
endif
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 5369f9f9eead..1f432de600da 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -103,10 +103,11 @@
<!-- Bluetooth settings -->
- <!-- Titles for Bluetooth Audio Codec selection preference. [CHAR LIMIT=40] -->
+ <!-- Titles for Bluetooth Audio Codec selection preference. [CHAR LIMIT=50] -->
<string-array name="bluetooth_a2dp_codec_titles">
<item>Use System Selection (Default)</item>
<item>SBC</item>
+ <item>AAC</item>
<item>aptX</item>
<item>aptX HD</item>
<item>LDAC</item>
@@ -119,18 +120,20 @@
<item>1</item>
<item>2</item>
<item>3</item>
+ <item>4</item>
</string-array>
- <!-- Summaries for Bluetooth Audio Codec selection preference. [CHAR LIMIT=40]-->
+ <!-- Summaries for Bluetooth Audio Codec selection preference. [CHAR LIMIT=50]-->
<string-array name="bluetooth_a2dp_codec_summaries" >
<item>Use System Selection (Default)</item>
<item>SBC</item>
+ <item>AAC</item>
<item>aptX</item>
<item>aptX HD</item>
<item>LDAC</item>
</string-array>
- <!-- Titles for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=40] -->
+ <!-- Titles for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=50] -->
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item>Use System Selection (Default)</item>
<item>44.1 kHz</item>
@@ -148,7 +151,7 @@
<item>8</item>
</string-array>
- <!-- Summaries for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=40]-->
+ <!-- Summaries for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=50]-->
<string-array name="bluetooth_a2dp_codec_sample_rate_summaries" >
<item>Use System Selection (Default)</item>
<item>44.1 kHz</item>
@@ -157,7 +160,7 @@
<item>96.0 kHz</item>
</string-array>
- <!-- Titles for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=40] -->
+ <!-- Titles for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=50] -->
<string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
<item>Use System Selection (Default)</item>
<item>16 bits/sample</item>
@@ -173,7 +176,7 @@
<item>4</item>
</string-array>
- <!-- Summaries for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=40]-->
+ <!-- Summaries for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=50]-->
<string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries" >
<item>Use System Selection (Default)</item>
<item>16 bits/sample</item>
@@ -181,7 +184,7 @@
<item>32 bits/sample</item>
</string-array>
- <!-- Titles for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=40] -->
+ <!-- Titles for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=50] -->
<string-array name="bluetooth_a2dp_codec_channel_mode_titles">
<item>Use System Selection (Default)</item>
<item>Mono</item>
@@ -195,7 +198,7 @@
<item>2</item>
</string-array>
- <!-- Summaries for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=40]-->
+ <!-- Summaries for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=50]-->
<string-array name="bluetooth_a2dp_codec_channel_mode_summaries" >
<item>Use System Selection (Default)</item>
<item>Mono</item>
@@ -204,9 +207,9 @@
<!-- Titles for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=70] -->
<string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
- <item>Optimize for Audio Quality (990kbps/909kbps)</item>
+ <item>Optimized for Audio Quality (990kbps/909kbps)</item>
<item>Balanced Audio And Connection Quality (660kbps/606kbps)</item>
- <item>Optimize for Connection Quality (330kbps/303kbps)</item>
+ <item>Optimized for Connection Quality (330kbps/303kbps)</item>
</string-array>
<!-- Values for Bluetooth Audio Codec LDAC Playback Quaility selection preference. -->
@@ -218,9 +221,9 @@
<!-- Summaries for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=70]-->
<string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries" >
- <item>Optimize for Audio Quality</item>
+ <item>Optimized for Audio Quality</item>
<item>Balanced Audio And Connection Quality</item>
- <item>Optimize for Connection Quality</item>
+ <item>Optimized for Connection Quality</item>
</string-array>
<!-- Titles for logd limit size selection preference. [CHAR LIMIT=14] -->
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 3627c29e3cae..064059baa7d2 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -57,6 +57,8 @@
<string name="wifi_disabled_generic">Disabled</string>
<!-- Status for networked disabled from a DNS or DHCP failure -->
<string name="wifi_disabled_network_failure">IP Configuration Failure</string>
+ <!-- Status for networks disabled by the network recommendation provider -->
+ <string name="wifi_disabled_by_recommendation_provider">Not connected due to low quality network</string>
<!-- Status for networked disabled from a wifi association failure -->
<string name="wifi_disabled_wifi_failure">WiFi Connection Failure</string>
<!-- Status for networks disabled from authentication failure (wrong password
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
index 26836099c9de..c4437c220c5c 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
@@ -135,6 +135,10 @@ public final class LocalBluetoothAdapter {
mAdapter.setDiscoverableTimeout(timeout);
}
+ public long getDiscoveryEndMillis() {
+ return mAdapter.getDiscoveryEndMillis();
+ }
+
public void setName(String name) {
mAdapter.setName(name);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 252aaab1522a..6166cd80cef9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -422,7 +422,8 @@ public class AccessPoint implements Comparable<AccessPoint> {
// This is the active connection on non-passpoint network
summary.append(getSummary(mContext, getDetailedState(),
mInfo != null && mInfo.isEphemeral()));
- } else if (config != null && config.isPasspoint()) {
+ } else if (config != null && config.isPasspoint()
+ && config.getNetworkSelectionStatus().isNetworkEnabled()) {
String format = mContext.getString(R.string.available_via_passpoint);
summary.append(String.format(format, config.providerFriendlyName));
} else if (config != null && config.hasNoInternetAccess()) {
@@ -445,6 +446,8 @@ public class AccessPoint implements Comparable<AccessPoint> {
summary.append(mContext.getString(R.string.wifi_disabled_generic));
break;
}
+ } else if (config != null && config.getNetworkSelectionStatus().isNotRecommended()) {
+ summary.append(mContext.getString(R.string.wifi_disabled_by_recommendation_provider));
} else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range
summary.append(mContext.getString(R.string.wifi_not_in_range));
} else { // In range, not disabled.
@@ -682,11 +685,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
}
void loadConfig(WifiConfiguration config) {
- if (config.isPasspoint())
- ssid = config.providerFriendlyName;
- else
- ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
-
+ ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
bssid = config.BSSID;
security = getSecurity(config);
networkId = config.networkId;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 7d279eb1aac6..3435d1d9629d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -344,29 +344,22 @@ public class WifiTracker {
}
AccessPoint accessPoint = getCachedOrCreate(config, cachedAccessPoints);
if (mLastInfo != null && mLastNetworkInfo != null) {
- if (config.isPasspoint() == false) {
- accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
- }
+ accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
}
if (mIncludeSaved) {
- if (!config.isPasspoint() || mIncludePasspoints) {
- // If saved network not present in scan result then set its Rssi to MAX_VALUE
- boolean apFound = false;
- for (ScanResult result : results) {
- if (result.SSID.equals(accessPoint.getSsidStr())) {
- apFound = true;
- break;
- }
+ // If saved network not present in scan result then set its Rssi to MAX_VALUE
+ boolean apFound = false;
+ for (ScanResult result : results) {
+ if (result.SSID.equals(accessPoint.getSsidStr())) {
+ apFound = true;
+ break;
}
- if (!apFound) {
- accessPoint.setRssi(Integer.MAX_VALUE);
- }
- accessPoints.add(accessPoint);
}
-
- if (config.isPasspoint() == false) {
- apMap.put(accessPoint.getSsidStr(), accessPoint);
+ if (!apFound) {
+ accessPoint.setRssi(Integer.MAX_VALUE);
}
+ accessPoints.add(accessPoint);
+ apMap.put(accessPoint.getSsidStr(), accessPoint);
} else {
// If we aren't using saved networks, drop them into the cache so that
// we have access to their saved info.
@@ -397,20 +390,16 @@ public class WifiTracker {
}
if (result.isPasspointNetwork()) {
+ // Retrieve a WifiConfiguration for a Passpoint provider that matches
+ // the given ScanResult. This is used for showing that a given AP
+ // (ScanResult) is available via a Passpoint provider (provider friendly
+ // name).
WifiConfiguration config = mWifiManager.getMatchingWifiConfig(result);
if (config != null) {
accessPoint.update(config);
}
}
- if (mLastInfo != null && mLastInfo.getBSSID() != null
- && mLastInfo.getBSSID().equals(result.BSSID)
- && connectionConfig != null && connectionConfig.isPasspoint()) {
- /* This network is connected via this passpoint config */
- /* SSID match is not going to work for it; so update explicitly */
- accessPoint.update(connectionConfig);
- }
-
accessPoints.add(accessPoint);
apMap.put(accessPoint.getSsidStr(), accessPoint);
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 227d0e944e6e..4f7a826e8fee 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -41,6 +41,7 @@
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
+ <uses-permission android:name="android.permission.MANAGE_USB" />
<!-- System tool permissions granted to the shell. -->
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_in.xml b/packages/SystemUI/res/drawable/stat_sys_signal_in.xml
new file mode 100644
index 000000000000..7e6e09b9c846
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_in.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="in"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M8.7,12.2l-2.0,3.5l-2.0,-3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml b/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml
new file mode 100644
index 000000000000..b7b6f0f56749
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="in"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M8.7,12.2l-2.0,3.5l-2.0,-3.5z" />
+ <path
+ android:name="out"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M0.5,15.7l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_out.xml b/packages/SystemUI/res/drawable/stat_sys_signal_out.xml
new file mode 100644
index 000000000000..910c0355f5a9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_out.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="out"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M0.5,15.7l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml
new file mode 100644
index 000000000000..666127be8dda
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="18.41dp"
+ android:height="17dp"
+ android:viewportWidth="26.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="in"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M8.7,18.3l-2.0,3.5l-2.0,-3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml
new file mode 100644
index 000000000000..eeba0304a0f2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="18.41dp"
+ android:height="17dp"
+ android:viewportWidth="26.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="in"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M8.7,18.3l-2.0,3.5l-2.0,-3.5z" />
+ <path
+ android:name="out"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M0.5,21.8l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml
new file mode 100644
index 000000000000..d577d1a48704
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="18.41dp"
+ android:height="17dp"
+ android:viewportWidth="26.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="out"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M0.5,21.8l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index a20ec8e7623d..f597785d98ba 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -43,4 +43,10 @@
android:layout_height="wrap_content"
android:layout_width="wrap_content"
/>
+ <ImageView
+ android:id="@+id/mobile_inout"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:visibility="gone"
+ />
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index d17601c1c054..f0bfb9272d60 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -70,6 +70,11 @@
android:layout_width="wrap_content"
android:alpha="0.0"
/>
+ <ImageView
+ android:id="@+id/wifi_inout"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ />
</FrameLayout>
<View
android:id="@+id/wifi_signal_spacer"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 484e008b3714..2fd62f1ebf26 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -232,6 +232,8 @@ public class CustomTile extends QSTile<QSTile.State> implements TileChangeListen
i.setPackage(mComponent.getPackageName());
i = resolveIntent(i);
if (i != null) {
+ i.putExtra(TileService.EXTRA_COMPONENT, mComponent);
+ i.putExtra(TileService.EXTRA_STATE, mTile.getState());
return i;
}
return new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 016c4b70f485..4b8d7b9e4e8e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -37,6 +38,9 @@ import com.android.systemui.statusbar.policy.HotspotController;
/** Quick settings tile: Hotspot **/
public class HotspotTile extends QSTile<QSTile.AirplaneBooleanState> {
+ static final Intent TETHER_SETTINGS = new Intent().setComponent(new ComponentName(
+ "com.android.settings", "com.android.settings.TetherSettings"));
+
private final AnimationIcon mEnable =
new AnimationIcon(R.drawable.ic_hotspot_enable_animation,
R.drawable.ic_hotspot_disable);
@@ -94,7 +98,7 @@ public class HotspotTile extends QSTile<QSTile.AirplaneBooleanState> {
@Override
public Intent getLongClickIntent() {
- return new Intent(Settings.ACTION_WIRELESS_SETTINGS);
+ return new Intent(TETHER_SETTINGS);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 74caa5326f83..d36f572a38cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -75,6 +75,8 @@ public class SignalClusterView
private boolean mWifiVisible = false;
private int mWifiStrengthId = 0;
private int mLastWifiStrengthId = -1;
+ private int mWifiActivityId = 0;
+ private int mLastWifiActivityId = -1;
private boolean mIsAirplaneMode = false;
private int mAirplaneIconId = 0;
private int mLastAirplaneIconId = -1;
@@ -89,6 +91,7 @@ public class SignalClusterView
ViewGroup mEthernetGroup, mWifiGroup;
View mNoSimsCombo;
ImageView mVpn, mEthernet, mWifi, mAirplane, mNoSims, mEthernetDark, mWifiDark, mNoSimsDark;
+ ImageView mWifiActivity;
View mWifiAirplaneSpacer;
View mWifiSignalSpacer;
LinearLayout mMobileSignalGroup;
@@ -180,6 +183,7 @@ public class SignalClusterView
mWifiGroup = (ViewGroup) findViewById(R.id.wifi_combo);
mWifi = (ImageView) findViewById(R.id.wifi_signal);
mWifiDark = (ImageView) findViewById(R.id.wifi_signal_dark);
+ mWifiActivity = (ImageView) findViewById(R.id.wifi_inout);
mAirplane = (ImageView) findViewById(R.id.airplane);
mNoSims = (ImageView) findViewById(R.id.no_sims);
mNoSimsDark = (ImageView) findViewById(R.id.no_sims_dark);
@@ -264,6 +268,10 @@ public class SignalClusterView
mWifiVisible = statusIcon.visible && !mBlockWifi;
mWifiStrengthId = statusIcon.icon;
mWifiDescription = statusIcon.contentDescription;
+ mWifiActivityId = activityIn && activityOut ? R.drawable.stat_sys_wifi_inout
+ : activityIn ? R.drawable.stat_sys_wifi_in
+ : activityOut ? R.drawable.stat_sys_wifi_out
+ : 0;
apply();
}
@@ -282,6 +290,10 @@ public class SignalClusterView
state.mMobileDescription = statusIcon.contentDescription;
state.mMobileTypeDescription = typeContentDescription;
state.mIsMobileTypeIconWide = statusType != 0 && isWide;
+ state.mMobileActivityId = activityIn && activityOut ? R.drawable.stat_sys_signal_inout
+ : activityIn ? R.drawable.stat_sys_signal_in
+ : activityOut ? R.drawable.stat_sys_signal_out
+ : 0;
apply();
}
@@ -404,6 +416,10 @@ public class SignalClusterView
mWifiDark.setImageDrawable(null);
mLastWifiStrengthId = -1;
}
+ if (mWifiActivity != null) {
+ mWifiActivity.setImageDrawable(null);
+ mLastWifiActivityId = -1;
+ }
for (PhoneState state : mPhoneStates) {
if (state.mMobile != null) {
@@ -420,6 +436,10 @@ public class SignalClusterView
state.mMobileType.setImageDrawable(null);
state.mLastMobileTypeId = -1;
}
+ if (state.mMobileActivity != null) {
+ state.mMobileActivity.setImageDrawable(null);
+ state.mLastMobileActivityId = -1;
+ }
}
if (mAirplane != null) {
@@ -473,6 +493,12 @@ public class SignalClusterView
setIconForView(mWifiDark, mWifiStrengthId);
mLastWifiStrengthId = mWifiStrengthId;
}
+ if (mWifiActivityId != mLastWifiActivityId) {
+ if (mWifiActivityId != 0) {
+ setIconForView(mWifiActivity, mWifiActivityId);
+ }
+ mLastWifiActivityId = mWifiActivityId;
+ }
mWifiGroup.setContentDescription(mWifiDescription);
mWifiGroup.setVisibility(View.VISIBLE);
} else {
@@ -484,6 +510,8 @@ public class SignalClusterView
(mWifiVisible ? "VISIBLE" : "GONE"),
mWifiStrengthId));
+ mWifiActivity.setVisibility(mWifiActivityId != 0 ? View.VISIBLE : View.GONE);
+
boolean anyMobileVisible = false;
int firstMobileTypeId = 0;
for (PhoneState state : mPhoneStates) {
@@ -560,6 +588,8 @@ public class SignalClusterView
applyDarkIntensity(
StatusBarIconController.getDarkIntensity(mTintArea, mWifi, mDarkIntensity),
mWifi, mWifiDark);
+ setTint(mWifiActivity,
+ StatusBarIconController.getTint(mTintArea, mWifiActivity, mIconTint));
applyDarkIntensity(
StatusBarIconController.getDarkIntensity(mTintArea, mEthernet, mDarkIntensity),
mEthernet, mEthernetDark);
@@ -584,14 +614,16 @@ public class SignalClusterView
private class PhoneState {
private final int mSubId;
private boolean mMobileVisible = false;
- private int mMobileStrengthId = 0, mMobileTypeId = 0;
+ private int mMobileStrengthId = 0, mMobileTypeId = 0, mMobileActivityId = 0;
private int mLastMobileStrengthId = -1;
private int mLastMobileTypeId = -1;
+ private int mLastMobileActivityId = -1;
private boolean mIsMobileTypeIconWide;
private String mMobileDescription, mMobileTypeDescription;
private ViewGroup mMobileGroup;
private ImageView mMobile, mMobileDark, mMobileType;
+ private ImageView mMobileActivity;
public PhoneState(int subId, Context context) {
ViewGroup root = (ViewGroup) LayoutInflater.from(context)
@@ -605,6 +637,7 @@ public class SignalClusterView
mMobile = (ImageView) root.findViewById(R.id.mobile_signal);
mMobileDark = (ImageView) root.findViewById(R.id.mobile_signal_dark);
mMobileType = (ImageView) root.findViewById(R.id.mobile_type);
+ mMobileActivity = (ImageView) root.findViewById(R.id.mobile_inout);
}
public boolean apply(boolean isSecondaryIcon) {
@@ -619,6 +652,11 @@ public class SignalClusterView
mMobileType.setImageResource(mMobileTypeId);
mLastMobileTypeId = mMobileTypeId;
}
+
+ if (mLastMobileActivityId != mMobileActivityId) {
+ mMobileActivity.setImageResource(mMobileActivityId);
+ mLastMobileActivityId = mMobileActivityId;
+ }
mMobileGroup.setContentDescription(mMobileTypeDescription
+ " " + mMobileDescription);
mMobileGroup.setVisibility(View.VISIBLE);
@@ -640,6 +678,7 @@ public class SignalClusterView
(mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId));
mMobileType.setVisibility(mMobileTypeId != 0 ? View.VISIBLE : View.GONE);
+ mMobileActivity.setVisibility(mMobileActivityId != 0 ? View.VISIBLE : View.GONE);
return mMobileVisible;
}
@@ -699,6 +738,8 @@ public class SignalClusterView
StatusBarIconController.getDarkIntensity(tintArea, mMobile, darkIntensity),
mMobile, mMobileDark);
setTint(mMobileType, StatusBarIconController.getTint(tintArea, mMobileType, tint));
+ setTint(mMobileActivity,
+ StatusBarIconController.getTint(tintArea, mMobileActivity, tint));
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 37e6a2ab8ead..9380c45e62cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -690,6 +690,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
mDemoMode = true;
mDemoInetCondition = mInetCondition;
mDemoWifiState = mWifiSignalController.getState();
+ mDemoWifiState.ssid = "DemoMode";
} else if (mDemoMode && command.equals(COMMAND_EXIT)) {
if (DEBUG) Log.d(TAG, "Exiting demo mode");
mDemoMode = false;
@@ -735,6 +736,25 @@ public class NetworkControllerImpl extends BroadcastReceiver
: Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
mDemoWifiState.connected = mDemoWifiState.level >= 0;
}
+ String activity = args.getString("activity");
+ if (activity != null) {
+ switch (activity) {
+ case "inout":
+ mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_INOUT);
+ break;
+ case "in":
+ mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_IN);
+ break;
+ case "out":
+ mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_OUT);
+ break;
+ default:
+ mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_NONE);
+ break;
+ }
+ } else {
+ mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_NONE);
+ }
mDemoWifiState.enabled = show;
mWifiSignalController.notifyListeners();
}
@@ -797,6 +817,26 @@ public class NetworkControllerImpl extends BroadcastReceiver
: Math.min(Integer.parseInt(level), icons[0].length - 1);
controller.getState().connected = controller.getState().level >= 0;
}
+ String activity = args.getString("activity");
+ if (activity != null) {
+ controller.getState().dataConnected = true;
+ switch (activity) {
+ case "inout":
+ controller.setActivity(TelephonyManager.DATA_ACTIVITY_INOUT);
+ break;
+ case "in":
+ controller.setActivity(TelephonyManager.DATA_ACTIVITY_IN);
+ break;
+ case "out":
+ controller.setActivity(TelephonyManager.DATA_ACTIVITY_OUT);
+ break;
+ default:
+ controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE);
+ break;
+ }
+ } else {
+ controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE);
+ }
controller.getState().enabled = show;
controller.notifyListeners();
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
index 0a3197c039cf..1b520b4cbb27 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
@@ -163,7 +163,7 @@ public class DemoModeFragment extends PreferenceFragment implements OnPreference
intent.putExtra("sims", "1");
intent.putExtra("nosim", "false");
intent.putExtra("level", "4");
- intent.putExtra("datatypel", "");
+ intent.putExtra("datatype", "lte");
getContext().sendBroadcast(intent);
// Need to send this after so that the sim controller already exists.
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index bf4d88cb2a42..51c7e5598510 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -18,6 +18,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_JACK_FLAGS := --multi-dex native
+LOCAL_DX_FLAGS := --multi-dex
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/..
diff --git a/packages/WallpaperCropper/Android.mk b/packages/WallpaperCropper/Android.mk
index d8fb7a4d3a2a..09b41fdd1262 100644
--- a/packages/WallpaperCropper/Android.mk
+++ b/packages/WallpaperCropper/Android.mk
@@ -6,7 +6,7 @@ LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_JAVA_LIBRARIES := telephony-common
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 junit
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
LOCAL_PACKAGE_NAME := WallpaperCropper
LOCAL_CERTIFICATE := platform
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java
index 100b0b3b9c1f..f8b01cb428c4 100644
--- a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java
@@ -18,7 +18,7 @@ package com.android.gallery3d.glrenderer;
import android.graphics.Bitmap;
-import junit.framework.Assert;
+import com.android.gallery3d.common.Utils;
// BitmapTexture is a texture whose content is specified by a fixed Bitmap.
//
@@ -34,7 +34,7 @@ public class BitmapTexture extends UploadedTexture {
public BitmapTexture(Bitmap bitmap, boolean hasBorder) {
super(hasBorder);
- Assert.assertTrue(bitmap != null && !bitmap.isRecycled());
+ Utils.assertTrue(bitmap != null && !bitmap.isRecycled());
mContentBitmap = bitmap;
}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java
index 16b220690ef4..b26e9ab29447 100644
--- a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java
@@ -16,7 +16,7 @@
package com.android.gallery3d.glrenderer;
-import junit.framework.Assert;
+import com.android.gallery3d.common.Utils;
public class GLPaint {
private float mLineWidth = 1f;
@@ -31,7 +31,7 @@ public class GLPaint {
}
public void setLineWidth(float width) {
- Assert.assertTrue(width >= 0);
+ Utils.assertTrue(width >= 0);
mLineWidth = width;
}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java
index f41a979b7ddd..417102a386b6 100644
--- a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java
@@ -20,7 +20,7 @@ import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.opengl.GLUtils;
-import junit.framework.Assert;
+import com.android.gallery3d.common.Utils;
import java.util.HashMap;
@@ -144,7 +144,7 @@ public abstract class UploadedTexture extends BasicTexture {
}
private void freeBitmap() {
- Assert.assertTrue(mBitmap != null);
+ Utils.assertTrue(mBitmap != null);
onFreeBitmap(mBitmap);
mBitmap = null;
}
@@ -219,7 +219,7 @@ public abstract class UploadedTexture extends BasicTexture {
int texWidth = getTextureWidth();
int texHeight = getTextureHeight();
- Assert.assertTrue(bWidth <= texWidth && bHeight <= texHeight);
+ Utils.assertTrue(bWidth <= texWidth && bHeight <= texHeight);
// Upload the bitmap to a new texture.
mId = canvas.getGLId().generateTexture();
diff --git a/preloaded-classes b/preloaded-classes
index 805a1c91c4f7..42f290e22b3f 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -2542,6 +2542,7 @@ com.android.internal.os.RuntimeInit$1
com.android.internal.os.RuntimeInit$Arguments
com.android.internal.os.RuntimeInit$KillApplicationHandler
com.android.internal.os.RuntimeInit$LoggingHandler
+com.android.internal.os.RoSystemProperties
com.android.internal.os.SamplingProfilerIntegration
com.android.internal.os.SomeArgs
com.android.internal.os.Zygote
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 735afce21cdb..d3ed525c1595 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2218,6 +2218,30 @@ message MetricsEvent {
// CATEGORY: QUICK_SETTINGS
QS_NFC = 497;
+ // ---- End N-MR2 Constants, all N-MR1 constants go above this line ----
+
+ // ACTION: A captive portal was detected during network validation
+ // CATEGORY: NOTIFICATION
+ // OS: N-MR2
+ NOTIFICATION_NETWORK_SIGN_IN = 740;
+
+ // ACTION: An unvalidated network without Internet was selected by the user
+ // CATEGORY: NOTIFICATION
+ // OS: N-MR2
+ NOTIFICATION_NETWORK_NO_INTERNET = 741;
+
+ // ACTION: A validated network failed revalidation and lost Internet access
+ // CATEGORY: NOTIFICATION
+ // OS: N-MR2
+ NOTIFICATION_NETWORK_LOST_INTERNET = 742;
+
+ // ACTION: The system default network switched to a different network
+ // CATEGORY: NOTIFICATION
+ // OS: N-MR2
+ NOTIFICATION_NETWORK_SWITCH = 743;
+
+ // ---- End O Constants, all O constants go above this line ----
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
new file mode 100644
index 000000000000..9aa6490fe7c0
--- /dev/null
+++ b/proto/src/wifi.proto
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package clearcut.connectivity;
+
+option java_package = "com.android.server.wifi";
+option java_outer_classname = "WifiMetricsProto";
+
+// The information about the Wifi events.
+message WifiLog {
+
+ // Session information that gets logged for every Wifi connection.
+ repeated ConnectionEvent connection_event = 1;
+
+ // Number of saved networks in the user profile.
+ optional int32 num_saved_networks = 2;
+
+ // Number of open networks in the saved networks.
+ optional int32 num_open_networks = 3;
+
+ // Number of personal networks.
+ optional int32 num_personal_networks = 4;
+
+ // Number of enterprise networks.
+ optional int32 num_enterprise_networks = 5;
+
+ // Does the user have location setting enabled.
+ optional bool is_location_enabled = 6;
+
+ // Does the user have scanning enabled.
+ optional bool is_scanning_always_enabled = 7;
+
+ // Number of times user toggled wifi using the settings menu.
+ optional int32 num_wifi_toggled_via_settings = 8;
+
+ // Number of times user toggled wifi using the airplane menu.
+ optional int32 num_wifi_toggled_via_airplane = 9;
+
+ // Number of networks added by the user.
+ optional int32 num_networks_added_by_user = 10;
+
+ // Number of networks added by applications.
+ optional int32 num_networks_added_by_apps = 11;
+
+ // Number scans that returned empty results.
+ optional int32 num_empty_scan_results = 12;
+
+ // Number scans that returned at least one result.
+ optional int32 num_non_empty_scan_results = 13;
+
+ // Number of scans that were one time.
+ optional int32 num_oneshot_scans = 14;
+
+ // Number of repeated background scans that were scheduled to the chip.
+ optional int32 num_background_scans = 15;
+
+ // Error codes that a scan can result in.
+ enum ScanReturnCode {
+
+ // Return Code is unknown.
+ SCAN_UNKNOWN = 0;
+
+ // Scan was successful.
+ SCAN_SUCCESS = 1;
+
+ // Scan was successfully started, but was interrupted.
+ SCAN_FAILURE_INTERRUPTED = 2;
+
+ // Scan failed to start because of invalid configuration
+ // (bad channel, etc).
+ SCAN_FAILURE_INVALID_CONFIGURATION = 3;
+
+ // Could not start a scan because wifi is disabled.
+ FAILURE_WIFI_DISABLED = 4;
+
+ }
+
+ // Mapping of error codes to the number of times that scans resulted
+ // in that error.
+ repeated ScanReturnEntry scan_return_entries = 16;
+
+ message ScanReturnEntry {
+
+ // Return code of the scan.
+ optional ScanReturnCode scan_return_code = 1;
+
+ // Number of entries that were found in the scan.
+ optional int32 scan_results_count = 2;
+ }
+
+ // State of the Wifi.
+ enum WifiState {
+
+ // State is unknown.
+ WIFI_UNKNOWN = 0;
+
+ // Wifi is disabled.
+ WIFI_DISABLED = 1;
+
+ // Wifi is enabled.
+ WIFI_DISCONNECTED = 2;
+
+ // Wifi is enabled and associated with an AP.
+ WIFI_ASSOCIATED = 3;
+ }
+
+ // Mapping of system state to the number of times that scans were requested in
+ // that state
+ repeated WifiSystemStateEntry wifi_system_state_entries = 17;
+
+ message WifiSystemStateEntry {
+
+ // Current WiFi state.
+ optional WifiState wifi_state = 1;
+
+ // Count of scans in state.
+ optional int32 wifi_state_count = 2;
+
+ // Is screen on.
+ optional bool is_screen_on = 3;
+ }
+
+ // Mapping of Error/Success codes to the number of background scans that resulted in it
+ repeated ScanReturnEntry background_scan_return_entries = 18;
+
+ // Mapping of system state to the number of times that Background scans were requested in that
+ // state
+ repeated WifiSystemStateEntry background_scan_request_state = 19;
+
+ // Total number of times the Watchdog of Last Resort triggered, resetting the wifi stack
+ optional int32 num_last_resort_watchdog_triggers = 20;
+
+ // Total number of networks over bad association threshold when watchdog triggered
+ optional int32 num_last_resort_watchdog_bad_association_networks_total = 21;
+
+ // Total number of networks over bad authentication threshold when watchdog triggered
+ optional int32 num_last_resort_watchdog_bad_authentication_networks_total = 22;
+
+ // Total number of networks over bad dhcp threshold when watchdog triggered
+ optional int32 num_last_resort_watchdog_bad_dhcp_networks_total = 23;
+
+ // Total number of networks over bad other threshold when watchdog triggered
+ optional int32 num_last_resort_watchdog_bad_other_networks_total = 24;
+
+ // Total count of networks seen when watchdog triggered
+ optional int32 num_last_resort_watchdog_available_networks_total = 25;
+
+ // Total count of triggers with atleast one bad association network
+ optional int32 num_last_resort_watchdog_triggers_with_bad_association = 26;
+
+ // Total count of triggers with atleast one bad authentication network
+ optional int32 num_last_resort_watchdog_triggers_with_bad_authentication = 27;
+
+ // Total count of triggers with atleast one bad dhcp network
+ optional int32 num_last_resort_watchdog_triggers_with_bad_dhcp = 28;
+
+ // Total count of triggers with atleast one bad other network
+ optional int32 num_last_resort_watchdog_triggers_with_bad_other = 29;
+
+ // Count of times connectivity watchdog confirmed pno is working
+ optional int32 num_connectivity_watchdog_pno_good = 30;
+
+ // Count of times connectivity watchdog found pno not working
+ optional int32 num_connectivity_watchdog_pno_bad = 31;
+
+ // Count of times connectivity watchdog confirmed background scan is working
+ optional int32 num_connectivity_watchdog_background_good = 32;
+
+ // Count of times connectivity watchdog found background scan not working
+ optional int32 num_connectivity_watchdog_background_bad = 33;
+
+ // The time duration represented by this wifi log, from start to end of capture
+ optional int32 record_duration_sec = 34;
+
+ // Counts the occurrences of each individual RSSI poll level
+ repeated RssiPollCount rssi_poll_rssi_count = 35;
+
+ // Total number of times WiFi connected immediately after a Last Resort Watchdog trigger,
+ // without new networks becoming available.
+ optional int32 num_last_resort_watchdog_successes = 36;
+
+ // Total number of saved hidden networks
+ optional int32 num_hidden_networks = 37;
+
+ // Total number of saved passpoint / hotspot 2.0 networks
+ optional int32 num_passpoint_networks = 38;
+
+ // Total number of scan results
+ optional int32 num_total_scan_results = 39;
+
+ // Total number of scan results for open networks
+ optional int32 num_open_network_scan_results = 40;
+
+ // Total number of scan results for personal networks
+ optional int32 num_personal_network_scan_results = 41;
+
+ // Total number of scan results for enterprise networks
+ optional int32 num_enterprise_network_scan_results = 42;
+
+ // Total number of scan results for hidden networks
+ optional int32 num_hidden_network_scan_results = 43;
+
+ // Total number of scan results for hotspot 2.0 r1 networks
+ optional int32 num_hotspot2_r1_network_scan_results = 44;
+
+ // Total number of scan results for hotspot 2.0 r2 networks
+ optional int32 num_hotspot2_r2_network_scan_results = 45;
+
+ // Total number of scans handled by framework (oneshot or otherwise)
+ optional int32 num_scans = 46;
+
+ // Counts the occurrences of each alert reason.
+ repeated AlertReasonCount alert_reason_count = 47;
+
+ // Counts the occurrences of each Wifi score
+ repeated WifiScoreCount wifi_score_count = 48;
+
+ // Histogram of Soft AP Durations
+ repeated SoftApDurationBucket soft_ap_duration = 49;
+
+ // Histogram of Soft AP ReturnCode
+ repeated SoftApReturnCodeCount soft_ap_return_code = 50;
+
+ // Histogram of the delta between scan result RSSI and RSSI polls
+ repeated RssiPollCount rssi_poll_delta_count = 51;
+}
+
+// Information that gets logged for every WiFi connection.
+message RouterFingerPrint {
+
+ enum RoamType {
+
+ // Type is unknown.
+ ROAM_TYPE_UNKNOWN = 0;
+
+ // No roaming - usually happens on a single band (2.4 GHz) router.
+ ROAM_TYPE_NONE = 1;
+
+ // Enterprise router.
+ ROAM_TYPE_ENTERPRISE = 2;
+
+ // DBDC => Dual Band Dual Concurrent essentially a router that
+ // supports both 2.4 GHz and 5 GHz bands.
+ ROAM_TYPE_DBDC = 3;
+ }
+
+ enum Auth {
+
+ // Auth is unknown.
+ AUTH_UNKNOWN = 0;
+
+ // No authentication.
+ AUTH_OPEN = 1;
+
+ // If the router uses a personal authentication.
+ AUTH_PERSONAL = 2;
+
+ // If the router is setup for enterprise authentication.
+ AUTH_ENTERPRISE = 3;
+ }
+
+ enum RouterTechnology {
+
+ // Router is unknown.
+ ROUTER_TECH_UNKNOWN = 0;
+
+ // Router Channel A.
+ ROUTER_TECH_A = 1;
+
+ // Router Channel B.
+ ROUTER_TECH_B = 2;
+
+ // Router Channel G.
+ ROUTER_TECH_G = 3;
+
+ // Router Channel N.
+ ROUTER_TECH_N = 4;
+
+ // Router Channel AC.
+ ROUTER_TECH_AC = 5;
+
+ // When the channel is not one of the above.
+ ROUTER_TECH_OTHER = 6;
+ }
+
+ optional RoamType roam_type = 1;
+
+ // Channel on which the connection takes place.
+ optional int32 channel_info = 2;
+
+ // DTIM setting of the router.
+ optional int32 dtim = 3;
+
+ // Authentication scheme of the router.
+ optional Auth authentication = 4;
+
+ // If the router is hidden.
+ optional bool hidden = 5;
+
+ // Channel information.
+ optional RouterTechnology router_technology = 6;
+
+ // whether ipv6 is supported.
+ optional bool supports_ipv6 = 7;
+
+ // If the router is a passpoint / hotspot 2.0 network
+ optional bool passpoint = 8;
+}
+
+message ConnectionEvent {
+
+ // Roam Type.
+ enum RoamType {
+
+ // Type is unknown.
+ ROAM_UNKNOWN = 0;
+
+ // No roaming.
+ ROAM_NONE = 1;
+
+ // DBDC roaming.
+ ROAM_DBDC = 2;
+
+ // Enterprise roaming.
+ ROAM_ENTERPRISE = 3;
+
+ // User selected roaming.
+ ROAM_USER_SELECTED = 4;
+
+ // Unrelated.
+ ROAM_UNRELATED = 5;
+ }
+
+ // Connectivity Level Failure.
+ enum ConnectivityLevelFailure {
+
+ // Failure is unknown.
+ HLF_UNKNOWN = 0;
+
+ // No failure.
+ HLF_NONE = 1;
+
+ // DHCP failure.
+ HLF_DHCP = 2;
+
+ // No internet connection.
+ HLF_NO_INTERNET = 3;
+
+ // No internet connection.
+ HLF_UNWANTED = 4;
+ }
+
+ // Start time of the connection.
+ optional int64 start_time_millis = 1;// [(datapol.semantic_type) = ST_TIMESTAMP];
+
+ // Duration to connect.
+ optional int32 duration_taken_to_connect_millis = 2;
+
+ // Router information.
+ optional RouterFingerPrint router_fingerprint = 3;
+
+ // RSSI at the start of the connection.
+ optional int32 signal_strength = 4;
+
+ // Roam Type.
+ optional RoamType roam_type = 5;
+
+ // Result of the connection.
+ optional int32 connection_result = 6;
+
+ // Reasons for level 2 failure (needs to be coordinated with wpa-supplicant).
+ optional int32 level_2_failure_code = 7;
+
+ // Failures that happen at the connectivity layer.
+ optional ConnectivityLevelFailure connectivity_level_failure_code = 8;
+
+ // Has bug report been taken.
+ optional bool automatic_bug_report_taken = 9;
+}
+
+// Number of occurrences of a specific RSSI poll rssi value
+message RssiPollCount {
+ // RSSI
+ optional int32 rssi = 1;
+
+ // Number of RSSI polls with 'rssi'
+ optional int32 count = 2;
+}
+
+// Number of occurrences of a specific alert reason value
+message AlertReasonCount {
+ // Alert reason
+ optional int32 reason = 1;
+
+ // Number of alerts with |reason|.
+ optional int32 count = 2;
+}
+
+// Counts the number of instances of a specific Wifi Score calculated by WifiScoreReport
+message WifiScoreCount {
+ // Wifi Score
+ optional int32 score = 1;
+
+ // Number of Wifi score reports with this score
+ optional int32 count = 2;
+}
+
+// Number of occurrences of Soft AP session durations
+message SoftApDurationBucket {
+ // Bucket covers duration : [duration_sec, duration_sec + bucket_size_sec)
+ // The (inclusive) lower bound of Soft AP session duration represented by this bucket
+ optional int32 duration_sec = 1;
+
+ // The size of this bucket
+ optional int32 bucket_size_sec = 2;
+
+ // Number of soft AP session durations that fit into this bucket
+ optional int32 count = 3;
+}
+
+// Number of occurrences of a soft AP session return code
+message SoftApReturnCodeCount {
+
+ enum SoftApStartResult {
+
+ // SoftApManager return code unknown
+ SOFT_AP_RETURN_CODE_UNKNOWN = 0;
+
+ // SoftAp started successfully
+ SOFT_AP_STARTED_SUCCESSFULLY = 1;
+
+ // Catch all for failures with no specific failure reason
+ SOFT_AP_FAILED_GENERAL_ERROR = 2;
+
+ // SoftAp failed to start due to NO_CHANNEL error
+ SOFT_AP_FAILED_NO_CHANNEL = 3;
+ }
+
+ // Historical, no longer used for writing as of 01/2017.
+ optional int32 return_code = 1 [deprecated = true];
+
+ // Occurences of this soft AP return code
+ optional int32 count = 2;
+
+ // Result of attempt to start SoftAp
+ optional SoftApStartResult start_result = 3;
+}
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index bf3681bd303f..447a47d3c56e 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -19,22 +19,17 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_STATIC_LIBRARIES :=
-rs_generated_include_dir := $(call intermediates-dir-for,SHARED_LIBRARIES,libRS,,)
-
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
frameworks/rs \
frameworks/base/core/jni \
- frameworks/base/libs/hwui \
- $(rs_generated_include_dir)
+ frameworks/base/libs/hwui
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-LOCAL_ADDITIONAL_DEPENDENCIES := $(addprefix $(rs_generated_include_dir)/,rsgApiFuncDecl.h)
LOCAL_MODULE:= librs_jni
-LOCAL_ADDITIONAL_DEPENDENCIES += $(rs_generated_source)
LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := libRS libRSDriver
+LOCAL_REQUIRED_MODULES := libRS
include $(BUILD_SHARED_LIBRARY)
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index af370ff2f630..2300da32d355 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -35,8 +35,8 @@
#include "android_runtime/android_util_AssetManager.h"
#include "android/graphics/GraphicsJNI.h"
-#include <rs.h>
#include <rsEnv.h>
+#include <rsApiStubs.h>
#include <gui/Surface.h>
#include <gui/GLConsumer.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
@@ -1134,7 +1134,7 @@ nElementGetNativeData(JNIEnv *_env, jobject _this, jlong con, jlong id, jintArra
// we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements
assert(dataSize == 5);
- uintptr_t elementData[5];
+ uint32_t elementData[5];
rsaElementGetNativeData((RsContext)con, (RsElement)id, elementData, dataSize);
for(jint i = 0; i < dataSize; i ++) {
@@ -1157,7 +1157,7 @@ nElementGetSubElements(JNIEnv *_env, jobject _this, jlong con, jlong id,
uintptr_t *ids = (uintptr_t*)malloc(dataSize * sizeof(uintptr_t));
const char **names = (const char **)malloc(dataSize * sizeof(const char *));
- uint32_t *arraySizes = (uint32_t *)malloc(dataSize * sizeof(uint32_t));
+ size_t *arraySizes = (size_t *)malloc(dataSize * sizeof(size_t));
rsaElementGetSubElements((RsContext)con, (RsElement)id, ids, names, arraySizes,
(uint32_t)dataSize);
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 4f43eac8b3ca..66576b5b8668 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -49,6 +49,7 @@ import android.os.Message;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
@@ -58,6 +59,8 @@ import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.Slog;
+import com.android.server.pm.PackageManagerService;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.concurrent.ConcurrentHashMap;
@@ -163,7 +166,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
public String toString() {
- return android.text.format.DateFormat.format("MM-dd hh:mm:ss ", mTimestamp) +
+ return android.text.format.DateFormat.format("MM-dd HH:mm:ss ", mTimestamp) +
(mEnable ? " Enabled " : " Disabled ") + " by " + mPackageName;
}
@@ -217,6 +220,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
@Override
public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
Bundle prevRestrictions) {
+ if (!newRestrictions.containsKey(UserManager.DISALLOW_BLUETOOTH)
+ && !prevRestrictions.containsKey(UserManager.DISALLOW_BLUETOOTH)) {
+ // The relevant restriction has not changed - do nothing.
+ return;
+ }
final boolean bluetoothDisallowed =
newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH);
if ((mEnable || mEnableExternal) && bluetoothDisallowed) {
@@ -227,6 +235,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
// when from system.
}
}
+ updateOppLauncherComponentState(bluetoothDisallowed);
}
};
@@ -938,7 +947,13 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
UserManagerInternal userManagerInternal =
LocalServices.getService(UserManagerInternal.class);
userManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
- if (isBluetoothDisallowed()) {
+ final boolean isBluetoothDisallowed = isBluetoothDisallowed();
+ PackageManagerService packageManagerService =
+ (PackageManagerService) ServiceManager.getService("package");
+ if (packageManagerService != null && !packageManagerService.isOnlyCoreApps()) {
+ updateOppLauncherComponentState(isBluetoothDisallowed);
+ }
+ if (isBluetoothDisallowed) {
return;
}
if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
@@ -1995,6 +2010,28 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
}
+ /**
+ * Disables BluetoothOppLauncherActivity component, so the Bluetooth sharing option is not
+ * offered to the user if Bluetooth is disallowed. Puts the component to its default state if
+ * Bluetooth is not disallowed.
+ *
+ * @param bluetoothDisallowed whether the {@link UserManager.DISALLOW_BLUETOOTH} user
+ * restriction was set.
+ */
+ private void updateOppLauncherComponentState(boolean bluetoothDisallowed) {
+ final ComponentName oppLauncherComponent = new ComponentName("com.android.bluetooth",
+ "com.android.bluetooth.opp.BluetoothOppLauncherActivity");
+ final int newState = bluetoothDisallowed
+ ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+ : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+ try {
+ mContext.getPackageManager()
+ .setComponentEnabledSetting(oppLauncherComponent, newState, 0);
+ } catch (Exception e) {
+ // The component was not found, do nothing.
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
@@ -2018,21 +2055,32 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
writer.println(" time since enabled: " + onDurationString + "\n");
}
- writer.println("Enable log:");
- for (ActiveLog log : mActiveLogs) {
- writer.println(log);
+ if (mActiveLogs.size() == 0) {
+ writer.println("Bluetooth never enabled!");
+ } else {
+ writer.println("Enable log:");
+ for (ActiveLog log : mActiveLogs) {
+ writer.println(" " + log);
+ }
}
- writer.println("\n" + mBleApps.size() + " BLE Apps registered:");
+ String bleAppString = "No BLE Apps registered.";
+ if (mBleApps.size() == 1) {
+ bleAppString = "1 BLE App registered:";
+ } else if (mBleApps.size() > 1) {
+ bleAppString = mBleApps.size() + " BLE Apps registered:";
+ }
+ writer.println("\n" + bleAppString);
for (ClientDeathRecipient app : mBleApps.values()) {
- writer.println(app.getPackageName());
+ writer.println(" " + app.getPackageName());
}
+ writer.println("");
writer.flush();
if (args.length == 0) {
- // Add arg to produce output
- args = new String[1];
- args[0] = "--print";
+ // Add arg to produce output
+ args = new String[1];
+ args[0] = "--print";
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 8c38ed63e6a3..954a94ea24c0 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -78,7 +78,7 @@ import android.net.Uri;
import android.net.metrics.DefaultNetworkEvent;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
-import android.net.util.AvoidBadWifiTracker;
+import android.net.util.MultinetworkPolicyTracker;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -499,7 +499,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private final IpConnectivityLog mMetricsLog;
@VisibleForTesting
- final AvoidBadWifiTracker mAvoidBadWifiTracker;
+ final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
/**
* Implements support for the legacy "one network per network type" model.
@@ -690,11 +690,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
private LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker();
- @VisibleForTesting
- protected HandlerThread createHandlerThread() {
- return new HandlerThread("ConnectivityServiceThread");
- }
-
public ConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
this(context, netManager, statsService, policyManager, new IpConnectivityLog());
@@ -715,7 +710,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mDefaultMobileDataRequest = createInternetRequestForTransport(
NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST);
- mHandlerThread = createHandlerThread();
+ mHandlerThread = new HandlerThread("ConnectivityServiceThread");
mHandlerThread.start();
mHandler = new InternalHandler(mHandlerThread.getLooper());
mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());
@@ -820,6 +815,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiverAsUser(
mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
+ mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM,
+ new IntentFilter(Intent.ACTION_USER_PRESENT), null, null);
try {
mNetd.registerObserver(mTethering);
@@ -854,9 +851,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS);
mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);
- mAvoidBadWifiTracker = createAvoidBadWifiTracker(
+ mMultinetworkPolicyTracker = createMultinetworkPolicyTracker(
mContext, mHandler, () -> rematchForAvoidBadWifiUpdate());
- mAvoidBadWifiTracker.start();
+ mMultinetworkPolicyTracker.start();
}
private NetworkRequest createInternetRequestForTransport(
@@ -2798,7 +2795,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
public boolean avoidBadWifi() {
- return mAvoidBadWifiTracker.currentValue();
+ return mMultinetworkPolicyTracker.getAvoidBadWifi();
}
private void rematchForAvoidBadWifiUpdate() {
@@ -2811,9 +2808,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
// TODO: Evaluate whether this is of interest to other consumers of
- // AvoidBadWifiTracker and worth moving out of here.
+ // MultinetworkPolicyTracker and worth moving out of here.
private void dumpAvoidBadWifiSettings(IndentingPrintWriter pw) {
- final boolean configRestrict = mAvoidBadWifiTracker.configRestrictsAvoidBadWifi();
+ final boolean configRestrict = mMultinetworkPolicyTracker.configRestrictsAvoidBadWifi();
if (!configRestrict) {
pw.println("Bad Wi-Fi avoidance: unrestricted");
return;
@@ -2823,7 +2820,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
pw.increaseIndent();
pw.println("Config restrict: " + configRestrict);
- final String value = mAvoidBadWifiTracker.getSettingsValue();
+ final String value = mMultinetworkPolicyTracker.getAvoidBadWifiSetting();
String description;
// Can't use a switch statement because strings are legal case labels, but null is not.
if ("0".equals(value)) {
@@ -2891,7 +2888,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (DBG) log("handleNetworkUnvalidated " + nai.name() + " cap=" + nc);
if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
- mAvoidBadWifiTracker.shouldNotifyWifiUnvalidated()) {
+ mMultinetworkPolicyTracker.shouldNotifyWifiUnvalidated()) {
showValidationNotification(nai, NotificationType.LOST_INTERNET);
}
}
@@ -3666,7 +3663,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Tear down existing lockdown if profile was removed
mLockdownEnabled = LockdownVpnTracker.isEnabled();
if (mLockdownEnabled) {
- final String profileName = new String(mKeyStore.get(Credentials.LOCKDOWN_VPN));
+ byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
+ if (profileTag == null) {
+ Slog.e(TAG, "Lockdown VPN configured but cannot be read from keystore");
+ return false;
+ }
+ String profileName = new String(profileTag);
final VpnProfile profile = VpnProfile.decode(
profileName, mKeyStore.get(Credentials.VPN + profileName));
if (profile == null) {
@@ -4005,6 +4007,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
};
+ private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Try creating lockdown tracker, since user present usually means
+ // unlocked keystore.
+ updateLockdownVpn();
+ mContext.unregisterReceiver(this);
+ }
+ };
+
private final HashMap<Messenger, NetworkFactoryInfo> mNetworkFactoryInfos =
new HashMap<Messenger, NetworkFactoryInfo>();
private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests =
@@ -4168,7 +4180,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
ensureRequestableCapabilities(networkCapabilities);
- if (timeoutMs < 0 || timeoutMs > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS) {
+ if (timeoutMs < 0) {
throw new IllegalArgumentException("Bad timeout specified");
}
@@ -5539,8 +5551,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
@VisibleForTesting
- AvoidBadWifiTracker createAvoidBadWifiTracker(Context c, Handler h, Runnable r) {
- return new AvoidBadWifiTracker(c, h, r);
+ MultinetworkPolicyTracker createMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
+ return new MultinetworkPolicyTracker(c, h, r);
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 62f4f19a6028..82e6b427646c 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -16,7 +16,6 @@
package com.android.server;
-import android.Manifest;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
@@ -142,6 +141,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
private ServiceState[] mServiceState;
+ private int[] mVoiceActivationState;
+
+ private int[] mDataActivationState;
+
private SignalStrength[] mSignalStrength;
private boolean[] mMessageWaiting;
@@ -301,6 +304,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
mDataConnectionNetworkType = new int[numPhones];
mCallIncomingNumber = new String[numPhones];
mServiceState = new ServiceState[numPhones];
+ mVoiceActivationState = new int[numPhones];
+ mDataActivationState = new int[numPhones];
mSignalStrength = new SignalStrength[numPhones];
mMessageWaiting = new boolean[numPhones];
mDataConnectionPossible = new boolean[numPhones];
@@ -315,6 +320,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
mDataConnectionState[i] = TelephonyManager.DATA_UNKNOWN;
+ mVoiceActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
+ mDataActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
mCallIncomingNumber[i] = "";
mServiceState[i] = new ServiceState();
mSignalStrength[i] = new SignalStrength();
@@ -644,6 +651,20 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
remove(r.binder);
}
}
+ if ((events & PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) !=0) {
+ try {
+ r.callback.onVoiceActivationStateChanged(mVoiceActivationState[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
+ if ((events & PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) !=0) {
+ try {
+ r.callback.onDataActivationStateChanged(mDataActivationState[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
}
}
} else {
@@ -795,6 +816,67 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
broadcastServiceStateChanged(state, phoneId, subId);
}
+ public void notifySimActivationStateChangedForPhoneId(int phoneId, int subId,
+ int activationType, int activationState) {
+ if (!checkNotifyPermission("notifySimActivationState()")){
+ return;
+ }
+ if (VDBG) {
+ log("notifySimActivationStateForPhoneId: subId=" + subId + " phoneId=" + phoneId
+ + "type=" + activationType + " state=" + activationState);
+ }
+ synchronized (mRecords) {
+ if (validatePhoneId(phoneId)) {
+ switch (activationType) {
+ case PhoneConstants.SIM_ACTIVATION_TYPE_VOICE:
+ mVoiceActivationState[phoneId] = activationState;
+ break;
+ case PhoneConstants.SIM_ACTIVATION_TYPE_DATA:
+ mDataActivationState[phoneId] = activationState;
+ break;
+ default:
+ return;
+ }
+ for (Record r : mRecords) {
+ if (VDBG) {
+ log("notifySimActivationStateForPhoneId: r=" + r + " subId=" + subId
+ + " phoneId=" + phoneId + "type=" + activationType
+ + " state=" + activationState);
+ }
+ try {
+ if ((activationType == PhoneConstants.SIM_ACTIVATION_TYPE_VOICE) &&
+ r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) &&
+ idMatch(r.subId, subId, phoneId)) {
+ if (DBG) {
+ log("notifyVoiceActivationStateForPhoneId: callback.onVASC r=" + r
+ + " subId=" + subId + " phoneId=" + phoneId
+ + " state=" + activationState);
+ }
+ r.callback.onVoiceActivationStateChanged(activationState);
+ }
+ if ((activationType == PhoneConstants.SIM_ACTIVATION_TYPE_DATA) &&
+ r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) &&
+ idMatch(r.subId, subId, phoneId)) {
+ if (DBG) {
+ log("notifyDataActivationStateForPhoneId: callback.onDASC r=" + r
+ + " subId=" + subId + " phoneId=" + phoneId
+ + " state=" + activationState);
+ }
+ r.callback.onDataActivationStateChanged(activationState);
+ }
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ } else {
+ log("notifySimActivationStateForPhoneId: INVALID phoneId=" + phoneId);
+ }
+ handleRemoveListLocked();
+ }
+ }
+
public void notifySignalStrengthForPhoneId(int phoneId, int subId,
SignalStrength signalStrength) {
if (!checkNotifyPermission("notifySignalStrength()")) {
@@ -1324,6 +1406,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
pw.println(" mCallState=" + mCallState[i]);
pw.println(" mCallIncomingNumber=" + mCallIncomingNumber[i]);
pw.println(" mServiceState=" + mServiceState[i]);
+ pw.println(" mVoiceActivationState= " + mVoiceActivationState[i]);
+ pw.println(" mDataActivationState= " + mDataActivationState[i]);
pw.println(" mSignalStrength=" + mSignalStrength[i]);
pw.println(" mMessageWaiting=" + mMessageWaiting[i]);
pw.println(" mCallForwarding=" + mCallForwarding[i]);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bc0390119a1d..1feaa72867d1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1381,6 +1381,7 @@ public final class ActivityManagerService extends ActivityManagerNative
ParcelFileDescriptor mProfileFd;
int mSamplingInterval = 0;
boolean mAutoStopProfiler = false;
+ boolean mStreamingOutput = false;
int mProfileType = 0;
final ProcessMap<Pair<Long, String>> mMemWatchProcesses = new ProcessMap<>();
String mMemWatchDumpProcName;
@@ -3752,7 +3753,8 @@ public final class ActivityManagerService extends ActivityManagerNative
}
int debugFlags = 0;
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
- debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
+ debugFlags |= Zygote.DEBUG_ENABLE_JDWP;
+ debugFlags |= Zygote.DEBUG_JAVA_DEBUGGABLE;
// Also turn on CheckJNI for debuggable apps. It's quite
// awkward to turn on otherwise.
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
@@ -5355,7 +5357,8 @@ public final class ActivityManagerService extends ActivityManagerNative
for (int pid : pids) {
if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for native pid " + pid);
final long sime = SystemClock.elapsedRealtime();
- Debug.dumpNativeBacktraceToFile(pid, tracesPath);
+
+ Debug.dumpNativeBacktraceToFileTimeout(pid, tracesPath, 10);
if (DEBUG_ANR) Slog.d(TAG, "Done with native pid " + pid
+ " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
}
@@ -6571,12 +6574,14 @@ public final class ActivityManagerService extends ActivityManagerNative
ParcelFileDescriptor profileFd = null;
int samplingInterval = 0;
boolean profileAutoStop = false;
+ boolean profileStreamingOutput = false;
if (mProfileApp != null && mProfileApp.equals(processName)) {
mProfileProc = app;
profileFile = mProfileFile;
profileFd = mProfileFd;
samplingInterval = mSamplingInterval;
profileAutoStop = mAutoStopProfiler;
+ profileStreamingOutput = mStreamingOutput;
}
boolean enableTrackAllocation = false;
if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName)) {
@@ -6606,7 +6611,8 @@ public final class ActivityManagerService extends ActivityManagerNative
profileFd = profileFd.dup();
}
ProfilerInfo profilerInfo = profileFile == null ? null
- : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
+ : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop,
+ profileStreamingOutput);
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode,
@@ -12039,6 +12045,7 @@ public final class ActivityManagerService extends ActivityManagerNative
mProfileFd = profilerInfo.profileFd;
mSamplingInterval = profilerInfo.samplingInterval;
mAutoStopProfiler = profilerInfo.autoStopProfiler;
+ mStreamingOutput = profilerInfo.streamingOutput;
mProfileType = 0;
}
}
@@ -14920,7 +14927,7 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.println(" mProfileApp=" + mProfileApp + " mProfileProc=" + mProfileProc);
pw.println(" mProfileFile=" + mProfileFile + " mProfileFd=" + mProfileFd);
pw.println(" mSamplingInterval=" + mSamplingInterval + " mAutoStopProfiler="
- + mAutoStopProfiler);
+ + mAutoStopProfiler + " mStreamingOutput=" + mStreamingOutput);
pw.println(" mProfileType=" + mProfileType);
}
}
@@ -17491,6 +17498,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// Not backing this app up any more; reset its OOM adjustment
final ProcessRecord proc = mBackupTarget.app;
updateOomAdjLocked(proc);
+ proc.inFullBackup = false;
// If the app crashed during backup, 'thread' will be null here
if (proc.thread != null) {
@@ -21438,6 +21446,7 @@ public final class ActivityManagerService extends ActivityManagerNative
mProfileFile = null;
mProfileType = 0;
mAutoStopProfiler = false;
+ mStreamingOutput = false;
mSamplingInterval = 0;
}
@@ -22269,4 +22278,29 @@ public final class ActivityManagerService extends ActivityManagerNative
// before the profile user is unlocked.
return rInfo != null && rInfo.activityInfo != null;
}
+
+ /**
+ * Attach an agent to the specified process (proces name or PID)
+ */
+ public void attachAgent(String process, String path) {
+ try {
+ synchronized (this) {
+ ProcessRecord proc = findProcessLocked(process, UserHandle.USER_SYSTEM, "attachAgent");
+ if (proc == null || proc.thread == null) {
+ throw new IllegalArgumentException("Unknown process: " + process);
+ }
+
+ boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
+ if (!isDebuggable) {
+ if ((proc.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+ throw new SecurityException("Process not debuggable: " + proc);
+ }
+ }
+
+ proc.thread.attachAgent(path);
+ }
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Process disappeared");
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index adf6d3670af3..2d0ccbd305e6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -66,6 +66,8 @@ class ActivityManagerShellCommand extends ShellCommand {
return runLenientBackgroundCheck(pw);
case "get-uid-state":
return getUidState(pw);
+ case "attach-agent":
+ return runAttachAgent(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -183,6 +185,21 @@ class ActivityManagerShellCommand extends ShellCommand {
return 0;
}
+ int runAttachAgent(PrintWriter pw) {
+ // TODO: revisit the permissions required for attaching agents
+ mInternal.enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
+ "attach-agent");
+ String process = getNextArgRequired();
+ String agent = getNextArgRequired();
+ String opt;
+ if ((opt = getNextArg()) != null) {
+ pw.println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ mInternal.attachAgent(process, agent);
+ return 0;
+ }
+
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -241,6 +258,8 @@ class ActivityManagerShellCommand extends ShellCommand {
pw.println(" Optionally controls lenient background check mode, returns current mode.");
pw.println(" get-uid-state <UID>");
pw.println(" Gets the process state of an app given its <UID>.");
+ pw.println(" attach-agent <PROCESS> <FILE>");
+ pw.println(" Attach an agent to the specified <PROCESS>, which may be either a process name or a PID.");
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c6ab9186456d..2262697e3461 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1296,7 +1296,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
profilerInfo = new ProfilerInfo(profileFile, profileFd,
- mService.mSamplingInterval, mService.mAutoStopProfiler);
+ mService.mSamplingInterval, mService.mAutoStopProfiler,
+ mService.mStreamingOutput);
}
}
}
diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
deleted file mode 100644
index 1c9feb2695f6..000000000000
--- a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.SystemService;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.net.ConnectivityMetricsEvent;
-import android.net.ConnectivityMetricsLogger;
-import android.net.IConnectivityMetricsLogger;
-import android.os.Binder;
-import android.os.Parcel;
-import android.text.format.DateUtils;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-
-/** {@hide} */
-public class MetricsLoggerService extends SystemService {
- private static String TAG = "ConnectivityMetricsLoggerService";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- public MetricsLoggerService(Context context) {
- super(context);
- }
-
- @Override
- public void onStart() {
- resetThrottlingCounters(System.currentTimeMillis());
- }
-
- @Override
- public void onBootPhase(int phase) {
- if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
- if (DBG) Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
- publishBinderService(ConnectivityMetricsLogger.CONNECTIVITY_METRICS_LOGGER_SERVICE,
- mBinder);
- }
- }
-
- // TODO: read these constants from system property
- private final int EVENTS_NOTIFICATION_THRESHOLD = 300;
- private final int MAX_NUMBER_OF_EVENTS = 1000;
- private final int THROTTLING_MAX_NUMBER_OF_MESSAGES_PER_COMPONENT = 1000;
- private final long THROTTLING_TIME_INTERVAL_MILLIS = DateUtils.HOUR_IN_MILLIS;
-
- private int mEventCounter = 0;
-
- /**
- * Reference of the last event in the list of cached events.
- *
- * When client of this service retrieves events by calling getEvents, it is passing
- * ConnectivityMetricsEvent.Reference object. After getEvents returns, that object will
- * contain this reference. The client can save it and use next time it calls getEvents.
- * This way only new events will be returned.
- */
- private long mLastEventReference = 0;
-
- private final int mThrottlingCounters[] =
- new int[ConnectivityMetricsLogger.NUMBER_OF_COMPONENTS];
-
- private long mThrottlingIntervalBoundaryMillis;
-
- private final ArrayDeque<ConnectivityMetricsEvent> mEvents = new ArrayDeque<>();
-
- private void enforceConnectivityInternalPermission() {
- getContext().enforceCallingOrSelfPermission(
- android.Manifest.permission.CONNECTIVITY_INTERNAL,
- "MetricsLoggerService");
- }
-
- private void enforceDumpPermission() {
- getContext().enforceCallingOrSelfPermission(
- android.Manifest.permission.DUMP,
- "MetricsLoggerService");
- }
-
- private void resetThrottlingCounters(long currentTimeMillis) {
- synchronized (mThrottlingCounters) {
- for (int i = 0; i < mThrottlingCounters.length; i++) {
- mThrottlingCounters[i] = 0;
- }
- mThrottlingIntervalBoundaryMillis =
- currentTimeMillis + THROTTLING_TIME_INTERVAL_MILLIS;
- }
- }
-
- private void addEvent(ConnectivityMetricsEvent e) {
- if (VDBG) {
- Log.v(TAG, "writeEvent(" + e.toString() + ")");
- }
-
- while (mEvents.size() >= MAX_NUMBER_OF_EVENTS) {
- mEvents.removeFirst();
- }
-
- mEvents.addLast(e);
- }
-
- @VisibleForTesting
- final MetricsLoggerImpl mBinder = new MetricsLoggerImpl();
-
- /**
- * Implementation of the IConnectivityMetricsLogger interface.
- */
- final class MetricsLoggerImpl extends IConnectivityMetricsLogger.Stub {
-
- private final ArrayList<PendingIntent> mPendingIntents = new ArrayList<>();
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump ConnectivityMetricsLoggerService " +
- "from from pid=" + Binder.getCallingPid() + ", uid=" +
- Binder.getCallingUid());
- return;
- }
-
- boolean dumpSerializedSize = false;
- boolean dumpEvents = false;
- boolean dumpDebugInfo = false;
- for (String arg : args) {
- switch (arg) {
- case "--debug":
- dumpDebugInfo = true;
- break;
-
- case "--events":
- dumpEvents = true;
- break;
-
- case "--size":
- dumpSerializedSize = true;
- break;
-
- case "--all":
- dumpDebugInfo = true;
- dumpEvents = true;
- dumpSerializedSize = true;
- break;
- }
- }
-
- synchronized (mEvents) {
- pw.println("Number of events: " + mEvents.size());
- pw.println("Counter: " + mEventCounter);
- if (mEvents.size() > 0) {
- pw.println("Time span: " +
- DateUtils.formatElapsedTime(
- (System.currentTimeMillis() - mEvents.peekFirst().timestamp)
- / 1000));
- }
-
- if (dumpSerializedSize) {
- Parcel p = Parcel.obtain();
- for (ConnectivityMetricsEvent e : mEvents) {
- p.writeParcelable(e, 0);
- }
- pw.println("Serialized data size: " + p.dataSize());
- p.recycle();
- }
-
- if (dumpEvents) {
- pw.println();
- pw.println("Events:");
- for (ConnectivityMetricsEvent e : mEvents) {
- pw.println(e.toString());
- }
- }
- }
-
- if (dumpDebugInfo) {
- synchronized (mThrottlingCounters) {
- pw.println();
- for (int i = 0; i < ConnectivityMetricsLogger.NUMBER_OF_COMPONENTS; i++) {
- if (mThrottlingCounters[i] > 0) {
- pw.println("Throttling Counter #" + i + ": " + mThrottlingCounters[i]);
- }
- }
- pw.println("Throttling Time Remaining: " +
- DateUtils.formatElapsedTime(
- (mThrottlingIntervalBoundaryMillis - System.currentTimeMillis())
- / 1000));
- }
- }
-
- synchronized (mPendingIntents) {
- if (!mPendingIntents.isEmpty()) {
- pw.println();
- pw.println("Pending intents:");
- for (PendingIntent pi : mPendingIntents) {
- pw.println(pi.toString());
- }
- }
- }
- }
-
- public long logEvent(ConnectivityMetricsEvent event) {
- ConnectivityMetricsEvent[] events = new ConnectivityMetricsEvent[]{event};
- return logEvents(events);
- }
-
- /**
- * @param events
- *
- * Note: All events must belong to the same component.
- *
- * @return 0 on success
- * <0 if error happened
- * >0 timestamp after which new events will be accepted
- */
- public long logEvents(ConnectivityMetricsEvent[] events) {
- enforceConnectivityInternalPermission();
-
- if (events == null || events.length == 0) {
- Log.wtf(TAG, "No events passed to logEvents()");
- return -1;
- }
-
- int componentTag = events[0].componentTag;
- if (componentTag < 0 ||
- componentTag >= ConnectivityMetricsLogger.NUMBER_OF_COMPONENTS) {
- Log.wtf(TAG, "Unexpected tag: " + componentTag);
- return -1;
- }
-
- synchronized (mThrottlingCounters) {
- long currentTimeMillis = System.currentTimeMillis();
- if (currentTimeMillis > mThrottlingIntervalBoundaryMillis) {
- resetThrottlingCounters(currentTimeMillis);
- }
-
- mThrottlingCounters[componentTag] += events.length;
-
- if (mThrottlingCounters[componentTag] >
- THROTTLING_MAX_NUMBER_OF_MESSAGES_PER_COMPONENT) {
- Log.w(TAG, "Too many events from #" + componentTag +
- ". Block until " + mThrottlingIntervalBoundaryMillis);
-
- return mThrottlingIntervalBoundaryMillis;
- }
- }
-
- boolean sendPendingIntents = false;
-
- synchronized (mEvents) {
- for (ConnectivityMetricsEvent e : events) {
- if (e.componentTag != componentTag) {
- Log.wtf(TAG, "Unexpected tag: " + e.componentTag);
- return -1;
- }
-
- addEvent(e);
- }
-
- mLastEventReference += events.length;
-
- mEventCounter += events.length;
- if (mEventCounter >= EVENTS_NOTIFICATION_THRESHOLD) {
- mEventCounter = 0;
- sendPendingIntents = true;
- }
- }
-
- if (sendPendingIntents) {
- synchronized (mPendingIntents) {
- for (PendingIntent pi : mPendingIntents) {
- if (VDBG) Log.v(TAG, "Send pending intent");
- try {
- pi.send(getContext(), 0, null, null, null);
- } catch (PendingIntent.CanceledException e) {
- Log.e(TAG, "Pending intent canceled: " + pi);
- mPendingIntents.remove(pi);
- }
- }
- }
- }
-
- return 0;
- }
-
- /**
- * Retrieve events
- *
- * @param reference of the last event previously returned. The function will return
- * events following it.
- * If 0 then all events will be returned.
- * After the function call it will contain reference of the
- * last returned event.
- * @return events
- */
- public ConnectivityMetricsEvent[] getEvents(ConnectivityMetricsEvent.Reference reference) {
- enforceDumpPermission();
- long ref = reference.getValue();
- if (VDBG) Log.v(TAG, "getEvents(" + ref + ")");
-
- ConnectivityMetricsEvent[] result;
- synchronized (mEvents) {
- if (ref > mLastEventReference) {
- Log.e(TAG, "Invalid reference");
- reference.setValue(mLastEventReference);
- return null;
- }
- if (ref < mLastEventReference - mEvents.size()) {
- ref = mLastEventReference - mEvents.size();
- }
-
- int numEventsToSkip =
- mEvents.size() // Total number of events
- - (int)(mLastEventReference - ref); // Number of events to return
-
- result = new ConnectivityMetricsEvent[mEvents.size() - numEventsToSkip];
- int i = 0;
- for (ConnectivityMetricsEvent e : mEvents) {
- if (numEventsToSkip > 0) {
- numEventsToSkip--;
- } else {
- result[i++] = e;
- }
- }
-
- reference.setValue(mLastEventReference);
- }
-
- return result;
- }
-
- public boolean register(PendingIntent newEventsIntent) {
- enforceDumpPermission();
- if (VDBG) Log.v(TAG, "register(" + newEventsIntent + ")");
-
- synchronized (mPendingIntents) {
- if (mPendingIntents.remove(newEventsIntent)) {
- Log.w(TAG, "Replacing registered pending intent");
- }
- mPendingIntents.add(newEventsIntent);
- }
-
- return true;
- }
-
- public void unregister(PendingIntent newEventsIntent) {
- enforceDumpPermission();
- if (VDBG) Log.v(TAG, "unregister(" + newEventsIntent + ")");
-
- synchronized (mPendingIntents) {
- if (!mPendingIntents.remove(newEventsIntent)) {
- Log.e(TAG, "Pending intent is not registered");
- }
- }
- }
- };
-}
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 9ffe2b78a095..c40780e0d588 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -809,19 +809,26 @@ public class NetworkMonitor extends StateMachine {
// portal. If it is considered a captive portal, a different sign-in URL
// is needed (i.e. can't browse a 204). This could be the result of an HTTP
// proxy server.
-
- // Consider 200 response with "Content-length=0" to not be a captive portal.
- // There's no point in considering this a captive portal as the user cannot
- // sign-in to an empty page. Probably the result of a broken transparent proxy.
- // See http://b/9972012.
- if (httpResponseCode == 200 && urlConnection.getContentLength() == 0) {
- validationLog("Empty 200 response interpreted as 204 response.");
- httpResponseCode = 204;
- }
-
- if (httpResponseCode == 200 && probeType == ValidationProbeEvent.PROBE_PAC) {
- validationLog("PAC fetch 200 response interpreted as 204 response.");
- httpResponseCode = 204;
+ if (httpResponseCode == 200) {
+ if (probeType == ValidationProbeEvent.PROBE_PAC) {
+ validationLog("PAC fetch 200 response interpreted as 204 response.");
+ httpResponseCode = 204;
+ } else if (urlConnection.getContentLengthLong() == 0) {
+ // Consider 200 response with "Content-length=0" to not be a captive portal.
+ // There's no point in considering this a captive portal as the user cannot
+ // sign-in to an empty page. Probably the result of a broken transparent proxy.
+ // See http://b/9972012.
+ validationLog(
+ "200 response with Content-length=0 interpreted as 204 response.");
+ httpResponseCode = 204;
+ } else if (urlConnection.getContentLengthLong() == -1) {
+ // When no Content-length (default value == -1), attempt to read a byte from the
+ // response. Do not use available() as it is unreliable. See http://b/33498325.
+ if (urlConnection.getInputStream().read() == -1) {
+ validationLog("Empty 200 response interpreted as 204 response.");
+ httpResponseCode = 204;
+ }
+ }
}
} catch (IOException e) {
validationLog("Probably not a portal: exception " + e);
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index b0e45097aff6..63e66a2c1334 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -1008,10 +1008,9 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
return false;
}
- protected boolean requestUpstreamMobileConnection() {
+ protected void requestUpstreamMobileConnection() {
mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
mUpstreamNetworkMonitor.registerMobileNetworkRequest();
- return true;
}
protected void unrequestUpstreamMobileConnection() {
@@ -1058,9 +1057,13 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
}
protected void chooseUpstreamType(boolean tryCell) {
+ final int upstreamType = findPreferredUpstreamType(tryCell);
+ setUpstreamByType(upstreamType);
+ }
+
+ protected int findPreferredUpstreamType(boolean tryCell) {
final ConnectivityManager cm = getConnectivityManager();
int upType = ConnectivityManager.TYPE_NONE;
- String iface = null;
updateConfiguration(); // TODO - remove?
@@ -1100,7 +1103,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
requestUpstreamMobileConnection();
break;
case ConnectivityManager.TYPE_NONE:
- if (tryCell && requestUpstreamMobileConnection()) {
+ if (tryCell) {
+ requestUpstreamMobileConnection();
// We think mobile should be coming up; don't set a retry.
} else {
sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
@@ -1117,7 +1121,13 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
break;
}
+ return upType;
+ }
+
+ protected void setUpstreamByType(int upType) {
+ final ConnectivityManager cm = getConnectivityManager();
Network network = null;
+ String iface = null;
if (upType != ConnectivityManager.TYPE_NONE) {
LinkProperties linkProperties = cm.getLinkProperties(upType);
if (linkProperties != null) {
@@ -1359,9 +1369,9 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
simChange.startListening();
mUpstreamNetworkMonitor.start();
- mTryCell = true; // better try something first pass or crazy tests cases will fail
- chooseUpstreamType(mTryCell);
- mTryCell = !mTryCell;
+ // Better try something first pass or crazy tests cases will fail.
+ chooseUpstreamType(true);
+ mTryCell = false;
}
@Override
@@ -1412,10 +1422,9 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
break;
}
case CMD_UPSTREAM_CHANGED:
- // need to try DUN immediately if Wifi goes down
- mTryCell = true;
- chooseUpstreamType(mTryCell);
- mTryCell = !mTryCell;
+ // Need to try DUN immediately if Wi-Fi goes down.
+ chooseUpstreamType(true);
+ mTryCell = false;
break;
case CMD_RETRY_UPSTREAM:
chooseUpstreamType(mTryCell);
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 37221a971ad1..5e5157913f20 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -250,31 +250,33 @@ public class TetherInterfaceStateMachine extends StateMachine {
}
private void cleanupUpstream() {
- if (mMyUpstreamIfaceName != null) {
- // note that we don't care about errors here.
- // sometimes interfaces are gone before we get
- // to remove their rules, which generates errors.
- // just do the best we can.
- try {
- // about to tear down NAT; gather remaining statistics
- mStatsService.forceUpdate();
- } catch (Exception e) {
- if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
- }
- try {
- mNMService.stopInterfaceForwarding(mIfaceName, mMyUpstreamIfaceName);
- } catch (Exception e) {
- if (VDBG) Log.e(
- TAG, "Exception in removeInterfaceForward: " + e.toString());
- }
- try {
- mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName);
- } catch (Exception e) {
- if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
- }
- mMyUpstreamIfaceName = null;
+ if (mMyUpstreamIfaceName == null) return;
+
+ cleanupUpstreamInterface(mMyUpstreamIfaceName);
+ mMyUpstreamIfaceName = null;
+ }
+
+ private void cleanupUpstreamInterface(String upstreamIface) {
+ // Note that we don't care about errors here.
+ // Sometimes interfaces are gone before we get
+ // to remove their rules, which generates errors.
+ // Just do the best we can.
+ try {
+ // About to tear down NAT; gather remaining statistics.
+ mStatsService.forceUpdate();
+ } catch (Exception e) {
+ if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
+ }
+ try {
+ mNMService.stopInterfaceForwarding(mIfaceName, upstreamIface);
+ } catch (Exception e) {
+ if (VDBG) Log.e(TAG, "Exception in removeInterfaceForward: " + e.toString());
+ }
+ try {
+ mNMService.disableNat(mIfaceName, upstreamIface);
+ } catch (Exception e) {
+ if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
}
- return;
}
@Override
@@ -306,6 +308,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
newUpstreamIfaceName);
} catch (Exception e) {
Log.e(TAG, "Exception enabling Nat: " + e.toString());
+ cleanupUpstreamInterface(newUpstreamIfaceName);
mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
transitionTo(mInitialState);
return true;
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index 23481dc2dbfd..6106093e4008 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -20,6 +20,8 @@ import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.LinkProperties;
@@ -40,7 +42,9 @@ import java.util.HashMap;
* pertaining to the current and any potential upstream network.
*
* Calling #start() registers two callbacks: one to track the system default
- * network and a second to specifically observe TYPE_MOBILE_DUN networks.
+ * network and a second to observe all networks. The latter is necessary
+ * while the expression of preferred upstreams remains a list of legacy
+ * connectivity types. In future, this can be revisited.
*
* The methods and data members of this class are only to be accessed and
* modified from the tethering master state machine thread. Any other
@@ -48,6 +52,10 @@ import java.util.HashMap;
*
* TODO: Move upstream selection logic here.
*
+ * All callback methods are run on the same thread as the specified target
+ * state machine. This class does not require locking when accessed from this
+ * thread. Access from other threads is not advised.
+ *
* @hide
*/
public class UpstreamNetworkMonitor {
@@ -60,19 +68,26 @@ public class UpstreamNetworkMonitor {
public static final int EVENT_ON_LINKPROPERTIES = 3;
public static final int EVENT_ON_LOST = 4;
+ private static final int CALLBACK_LISTEN_ALL = 1;
+ private static final int CALLBACK_TRACK_DEFAULT = 2;
+ private static final int CALLBACK_MOBILE_REQUEST = 3;
+
private final Context mContext;
private final StateMachine mTarget;
+ private final Handler mHandler;
private final int mWhat;
private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
private ConnectivityManager mCM;
+ private NetworkCallback mListenAllCallback;
private NetworkCallback mDefaultNetworkCallback;
- private NetworkCallback mDunTetheringCallback;
private NetworkCallback mMobileNetworkCallback;
private boolean mDunRequired;
+ private Network mCurrentDefault;
public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what) {
mContext = ctx;
mTarget = tgt;
+ mHandler = mTarget.getHandler();
mWhat = what;
}
@@ -85,16 +100,13 @@ public class UpstreamNetworkMonitor {
public void start() {
stop();
- mDefaultNetworkCallback = new UpstreamNetworkCallback();
- cm().registerDefaultNetworkCallback(mDefaultNetworkCallback);
+ final NetworkRequest listenAllRequest = new NetworkRequest.Builder()
+ .clearCapabilities().build();
+ mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL);
+ cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler);
- final NetworkRequest dunTetheringRequest = new NetworkRequest.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
- .build();
- mDunTetheringCallback = new UpstreamNetworkCallback();
- cm().registerNetworkCallback(dunTetheringRequest, mDunTetheringCallback);
+ mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_TRACK_DEFAULT);
+ cm().registerDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
}
public void stop() {
@@ -103,8 +115,8 @@ public class UpstreamNetworkMonitor {
releaseCallback(mDefaultNetworkCallback);
mDefaultNetworkCallback = null;
- releaseCallback(mDunTetheringCallback);
- mDunTetheringCallback = null;
+ releaseCallback(mListenAllCallback);
+ mListenAllCallback = null;
mNetworkMap.clear();
}
@@ -128,30 +140,25 @@ public class UpstreamNetworkMonitor {
return;
}
- final NetworkRequest.Builder builder = new NetworkRequest.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
- if (mDunRequired) {
- builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
- } else {
- builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
- }
- final NetworkRequest mobileUpstreamRequest = builder.build();
+ // The following use of the legacy type system cannot be removed until
+ // after upstream selection no longer finds networks by legacy type.
+ // See also http://b/34364553 .
+ final int legacyType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI;
+
+ final NetworkRequest mobileUpstreamRequest = new NetworkRequest.Builder()
+ .setCapabilities(ConnectivityManager.networkCapabilitiesForType(legacyType))
+ .build();
// The existing default network and DUN callbacks will be notified.
// Therefore, to avoid duplicate notifications, we only register a no-op.
- mMobileNetworkCallback = new NetworkCallback();
+ mMobileNetworkCallback = new UpstreamNetworkCallback(CALLBACK_MOBILE_REQUEST);
// TODO: Change the timeout from 0 (no onUnavailable callback) to some
// moderate callback timeout. This might be useful for updating some UI.
// Additionally, we log a message to aid in any subsequent debugging.
Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
- // The following use of the legacy type system cannot be removed until
- // after upstream selection no longer finds networks by legacy type.
- // See also b/34364553.
- final int apnType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI;
- cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, apnType);
+ cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType, mHandler);
}
public void releaseMobileNetworkRequest() {
@@ -165,86 +172,142 @@ public class UpstreamNetworkMonitor {
return (network != null) ? mNetworkMap.get(network) : null;
}
- private void handleAvailable(Network network) {
- if (VDBG) {
- Log.d(TAG, "EVENT_ON_AVAILABLE for " + network);
- }
+ private void handleAvailable(int callbackType, Network network) {
+ if (VDBG) Log.d(TAG, "EVENT_ON_AVAILABLE for " + network);
+
if (!mNetworkMap.containsKey(network)) {
mNetworkMap.put(network,
new NetworkState(null, null, null, network, null, null));
}
- final ConnectivityManager cm = cm();
-
- if (mDefaultNetworkCallback != null) {
- cm.requestNetworkCapabilities(mDefaultNetworkCallback);
- cm.requestLinkProperties(mDefaultNetworkCallback);
+ // Always request whatever extra information we can, in case this
+ // was already up when start() was called, in which case we would
+ // not have been notified of any information that had not changed.
+ switch (callbackType) {
+ case CALLBACK_LISTEN_ALL:
+ break;
+ case CALLBACK_TRACK_DEFAULT:
+ if (mDefaultNetworkCallback == null) {
+ // The callback was unregistered in the interval between
+ // ConnectivityService enqueueing onAvailable() and our
+ // handling of it here on the mHandler thread.
+ //
+ // Clean-up of this network entry is deferred to the
+ // handling of onLost() by other callbacks.
+ //
+ // These request*() calls can be deleted post oag/339444.
+ return;
+ }
+
+ cm().requestNetworkCapabilities(mDefaultNetworkCallback);
+ cm().requestLinkProperties(mDefaultNetworkCallback);
+ mCurrentDefault = network;
+ break;
+ case CALLBACK_MOBILE_REQUEST:
+ if (mMobileNetworkCallback == null) {
+ // The callback was unregistered in the interval between
+ // ConnectivityService enqueueing onAvailable() and our
+ // handling of it here on the mHandler thread.
+ //
+ // Clean-up of this network entry is deferred to the
+ // handling of onLost() by other callbacks.
+ //
+ // These request*() calls can be deleted post oag/339444.
+ return;
+ }
+
+ cm().requestNetworkCapabilities(mMobileNetworkCallback);
+ cm().requestLinkProperties(mMobileNetworkCallback);
+ break;
}
- // Requesting updates for mDunTetheringCallback is not
- // necessary. Because it's a listen, it will already have
- // heard all NetworkCapabilities and LinkProperties updates
- // since UpstreamNetworkMonitor was started. Because we
- // start UpstreamNetworkMonitor before chooseUpstreamType()
- // is ever invoked (it can register a DUN request) this is
- // mostly safe. However, if a DUN network is already up for
- // some reason (unlikely, because DUN is restricted and,
- // unless the DUN network is shared with another APN, only
- // the system can request it and this is the only part of
- // the system that requests it) we won't know its
- // LinkProperties or NetworkCapabilities.
-
+ // Requesting updates for mListenAllCallback is not currently possible
+ // because it's a "listen". Two possible solutions to getting updates
+ // about networks without waiting for a change (which might never come)
+ // are:
+ //
+ // [1] extend request{NetworkCapabilities,LinkProperties}() to
+ // take a Network argument and have ConnectivityService do
+ // what's required (if the network satisfies the request)
+ //
+ // [2] explicitly file a NetworkRequest for each connectivity type
+ // listed as a preferred upstream and wait for these callbacks
+ // to be notified (requires tracking many more callbacks).
+ //
+ // Until this is addressed, networks that exist prior to the "listen"
+ // registration and which do not subsequently change will not cause
+ // us to learn their NetworkCapabilities nor their LinkProperties.
+
+ // TODO: If sufficient information is available to select a more
+ // preferable upstream, do so now and notify the target.
notifyTarget(EVENT_ON_AVAILABLE, network);
}
private void handleNetCap(Network network, NetworkCapabilities newNc) {
- if (!mNetworkMap.containsKey(network)) {
- // Ignore updates for networks for which we have not yet
- // received onAvailable() - which should never happen -
- // or for which we have already received onLost().
+ final NetworkState prev = mNetworkMap.get(network);
+ if (prev == null || newNc.equals(prev.networkCapabilities)) {
+ // Ignore notifications about networks for which we have not yet
+ // received onAvailable() (should never happen) and any duplicate
+ // notifications (e.g. matching more than one of our callbacks).
return;
}
+
if (VDBG) {
Log.d(TAG, String.format("EVENT_ON_CAPABILITIES for %s: %s",
network, newNc));
}
- final NetworkState prev = mNetworkMap.get(network);
- mNetworkMap.put(network,
- new NetworkState(null, prev.linkProperties, newNc,
- network, null, null));
+ mNetworkMap.put(network, new NetworkState(
+ null, prev.linkProperties, newNc, network, null, null));
+ // TODO: If sufficient information is available to select a more
+ // preferable upstream, do so now and notify the target.
notifyTarget(EVENT_ON_CAPABILITIES, network);
}
private void handleLinkProp(Network network, LinkProperties newLp) {
- if (!mNetworkMap.containsKey(network)) {
- // Ignore updates for networks for which we have not yet
- // received onAvailable() - which should never happen -
- // or for which we have already received onLost().
+ final NetworkState prev = mNetworkMap.get(network);
+ if (prev == null || newLp.equals(prev.linkProperties)) {
+ // Ignore notifications about networks for which we have not yet
+ // received onAvailable() (should never happen) and any duplicate
+ // notifications (e.g. matching more than one of our callbacks).
return;
}
+
if (VDBG) {
Log.d(TAG, String.format("EVENT_ON_LINKPROPERTIES for %s: %s",
network, newLp));
}
- final NetworkState prev = mNetworkMap.get(network);
- mNetworkMap.put(network,
- new NetworkState(null, newLp, prev.networkCapabilities,
- network, null, null));
+ mNetworkMap.put(network, new NetworkState(
+ null, newLp, prev.networkCapabilities, network, null, null));
+ // TODO: If sufficient information is available to select a more
+ // preferable upstream, do so now and notify the target.
notifyTarget(EVENT_ON_LINKPROPERTIES, network);
}
- private void handleLost(Network network) {
- if (!mNetworkMap.containsKey(network)) {
- // Ignore updates for networks for which we have not yet
- // received onAvailable() - which should never happen -
- // or for which we have already received onLost().
+ private void handleLost(int callbackType, Network network) {
+ if (callbackType == CALLBACK_TRACK_DEFAULT) {
+ mCurrentDefault = null;
+ // Receiving onLost() for a default network does not necessarily
+ // mean the network is gone. We wait for a separate notification
+ // on either the LISTEN_ALL or MOBILE_REQUEST callbacks before
+ // clearing all state.
return;
}
- if (VDBG) {
- Log.d(TAG, "EVENT_ON_LOST for " + network);
+
+ if (!mNetworkMap.containsKey(network)) {
+ // Ignore loss of networks about which we had not previously
+ // learned any information or for which we have already processed
+ // an onLost() notification.
+ return;
}
+
+ if (VDBG) Log.d(TAG, "EVENT_ON_LOST for " + network);
+
+ // TODO: If sufficient information is available to select a more
+ // preferable upstream, do so now and notify the target. Likewise,
+ // if the current upstream network is gone, notify the target of the
+ // fact that we now have no upstream at all.
notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network));
}
@@ -257,28 +320,48 @@ public class UpstreamNetworkMonitor {
}
/**
- * A NetworkCallback class that relays information of interest to the
- * tethering master state machine thread for subsequent processing.
+ * A NetworkCallback class that handles information of interest directly
+ * in the thread on which it is invoked. To avoid locking, this MUST be
+ * run on the same thread as the target state machine's handler.
*/
private class UpstreamNetworkCallback extends NetworkCallback {
+ private final int mCallbackType;
+
+ UpstreamNetworkCallback(int callbackType) {
+ mCallbackType = callbackType;
+ }
+
@Override
public void onAvailable(Network network) {
- mTarget.getHandler().post(() -> handleAvailable(network));
+ checkExpectedThread();
+ handleAvailable(mCallbackType, network);
}
@Override
public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
- mTarget.getHandler().post(() -> handleNetCap(network, newNc));
+ checkExpectedThread();
+ handleNetCap(network, newNc);
}
@Override
public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
- mTarget.getHandler().post(() -> handleLinkProp(network, newLp));
+ checkExpectedThread();
+ handleLinkProp(network, newLp);
}
+ // TODO: Handle onNetworkSuspended();
+ // TODO: Handle onNetworkResumed();
+
@Override
public void onLost(Network network) {
- mTarget.getHandler().post(() -> handleLost(network));
+ checkExpectedThread();
+ handleLost(mCallbackType, network);
+ }
+
+ private void checkExpectedThread() {
+ if (Looper.myLooper() != mHandler.getLooper()) {
+ Log.wtf(TAG, "Handling callback in unexpected thread.");
+ }
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 55917fc5a945..0c7e44eacb97 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -24,7 +24,6 @@ import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.Predicate;
import com.android.server.hdmi.HdmiAnnotations.IoThreadOnly;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiControlService.DevicePollingCallback;
@@ -34,6 +33,7 @@ import libcore.util.EmptyArray;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
+import java.util.function.Predicate;
/**
* Manages HDMI-CEC command and behaviors. It converts user's command into CEC command
@@ -72,7 +72,7 @@ final class HdmiCecController {
// Predicate for whether the given logical address is remote device's one or not.
private final Predicate<Integer> mRemoteDeviceAddressPredicate = new Predicate<Integer>() {
@Override
- public boolean apply(Integer address) {
+ public boolean test(Integer address) {
return !isAllocatedLocalDeviceAddress(address);
}
};
@@ -80,7 +80,7 @@ final class HdmiCecController {
// Predicate whether the given logical address is system audio's one or not
private final Predicate<Integer> mSystemAudioAddressPredicate = new Predicate<Integer>() {
@Override
- public boolean apply(Integer address) {
+ public boolean test(Integer address) {
return HdmiUtils.getTypeFromAddress(address) == Constants.ADDR_AUDIO_SYSTEM;
}
};
@@ -403,7 +403,7 @@ final class HdmiCecController {
switch (iterationStrategy) {
case Constants.POLL_ITERATION_IN_ORDER:
for (int i = Constants.ADDR_TV; i <= Constants.ADDR_SPECIFIC_USE; ++i) {
- if (pickPredicate.apply(i)) {
+ if (pickPredicate.test(i)) {
pollingCandidates.add(i);
}
}
@@ -411,7 +411,7 @@ final class HdmiCecController {
case Constants.POLL_ITERATION_REVERSE_ORDER:
default: // The default is reverse order.
for (int i = Constants.ADDR_SPECIFIC_USE; i >= Constants.ADDR_TV; --i) {
- if (pickPredicate.apply(i)) {
+ if (pickPredicate.test(i)) {
pollingCandidates.add(i);
}
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index ae98077c7c2c..e2e834d2d4a5 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -477,12 +477,6 @@ public class GnssLocationProvider implements LocationProviderInterface {
public void onLost(Network network) {
releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
}
-
- @Override
- public void onUnavailable() {
- // timeout, it was not possible to establish the required connection
- releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
- }
};
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -902,8 +896,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
NetworkRequest request = requestBuilder.build();
mConnMgr.requestNetwork(
request,
- mSuplConnectivityCallback,
- ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS);
+ mSuplConnectivityCallback);
}
private void handleReleaseSuplConnection(int agpsDataConnStatus) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d31c7b54cee5..22c5e853819f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2078,12 +2078,14 @@ public class NotificationManagerService extends SystemService {
Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
return null;
}
- final ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- writePolicyXml(baos, true /*forBackup*/);
- return baos.toByteArray();
- } catch (IOException e) {
- Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
+ synchronized(mPolicyFile) {
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ writePolicyXml(baos, true /*forBackup*/);
+ return baos.toByteArray();
+ } catch (IOException e) {
+ Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
+ }
}
return null;
}
@@ -2101,12 +2103,14 @@ public class NotificationManagerService extends SystemService {
Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
return;
}
- final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
- try {
- readPolicyXml(bais, true /*forRestore*/);
- savePolicyFile();
- } catch (NumberFormatException | XmlPullParserException | IOException e) {
- Slog.w(TAG, "applyRestore: error reading payload", e);
+ synchronized(mPolicyFile) {
+ final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
+ try {
+ readPolicyXml(bais, true /*forRestore*/);
+ savePolicyFile();
+ } catch (NumberFormatException | XmlPullParserException | IOException e) {
+ Slog.w(TAG, "applyRestore: error reading payload", e);
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index a6f9243887df..a0fabdfb138e 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -777,6 +777,23 @@ final class DefaultPermissionGrantPolicy {
}
}
+ public void grantDefaultPermissionsToEnabledImsServicesLPr(String[] packageNames, int userId) {
+ Log.i(TAG, "Granting permissions to enabled ImsServices for user:" + userId);
+ if (packageNames == null) {
+ return;
+ }
+ for (String packageName : packageNames) {
+ PackageParser.Package imsServicePackage = getSystemPackageLPr(packageName);
+ if (imsServicePackage != null
+ && doesPackageSupportRuntimePermissions(imsServicePackage)) {
+ grantRuntimePermissionsLPw(imsServicePackage, PHONE_PERMISSIONS, userId);
+ grantRuntimePermissionsLPw(imsServicePackage, MICROPHONE_PERMISSIONS, userId);
+ grantRuntimePermissionsLPw(imsServicePackage, LOCATION_PERMISSIONS, userId);
+ grantRuntimePermissionsLPw(imsServicePackage, CAMERA_PERMISSIONS, userId);
+ }
+ }
+ }
+
public void grantDefaultPermissionsToDefaultBrowserLPr(String packageName, int userId) {
Log.i(TAG, "Granting permissions to default browser for user:" + userId);
if (packageName == null) {
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 0de0c924db72..49d3c8bccdff 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -287,7 +287,7 @@ public class KeySetManagerService {
for (int i = 0; i < defMapSize; i++) {
String alias = definedMapping.keyAt(i);
ArraySet<PublicKey> pubKeys = definedMapping.valueAt(i);
- if (alias != null && pubKeys != null || pubKeys.size() > 0) {
+ if (alias != null && pubKeys != null && pubKeys.size() > 0) {
KeySetHandle ks = addKeySetLPw(pubKeys);
newKeySetAliases.put(alias, ks.getId());
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 07dbb17b9451..ca0f85d51f3e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -21143,6 +21143,20 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
}
+ @Override
+ public void grantDefaultPermissionsToEnabledImsServices(String[] packageNames, int userId) {
+ enforceSystemOrPhoneCaller("grantDefaultPermissionsToEnabledImsServices");
+ synchronized (mPackages) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mDefaultPermissionPolicy.grantDefaultPermissionsToEnabledImsServicesLPr(
+ packageNames, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
private static void enforceSystemOrPhoneCaller(String tag) {
int callingUid = Binder.getCallingUid();
if (callingUid != Process.PHONE_UID && callingUid != Process.SYSTEM_UID) {
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 0fe15396fad7..522c2e83a9ae 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -69,6 +69,9 @@ public final class SELinuxMMAC {
// Append autoplay to existing seinfo label
private static final String AUTOPLAY_APP_STR = ":autoplayapp";
+ // Append targetSdkVersion=n to existing seinfo label where n is the app's targetSdkVersion
+ private static final String TARGETSDKVERSION_STR = ":targetSdkVersion=";
+
/**
* Load the mac_permissions.xml file containing all seinfo assignments used to
* label apps. The loaded mac_permissions.xml file is determined by the
@@ -290,6 +293,8 @@ public final class SELinuxMMAC {
if (pkg.applicationInfo.isPrivilegedApp())
pkg.applicationInfo.seinfo += PRIVILEGED_APP_STR;
+ pkg.applicationInfo.seinfo += TARGETSDKVERSION_STR + pkg.applicationInfo.targetSdkVersion;
+
if (DEBUG_POLICY_INSTALL) {
Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
"seinfo=" + pkg.applicationInfo.seinfo);
diff --git a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
index b704eb1d991c..3c73c88b4f5c 100644
--- a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
@@ -20,7 +20,7 @@ import android.util.Slog;
import java.io.File;
import java.io.IOException;
-import libcore.tzdata.update2.TimeZoneBundleInstaller;
+import libcore.tzdata.update2.TimeZoneDistroInstaller;
/**
* An install receiver responsible for installing timezone data updates.
@@ -34,14 +34,14 @@ public class TzDataInstallReceiver extends ConfigUpdateInstallReceiver {
private static final String UPDATE_DIR_NAME = TZ_DATA_DIR.getPath() + "/updates/";
private static final String UPDATE_METADATA_DIR_NAME = "metadata/";
private static final String UPDATE_VERSION_FILE_NAME = "version";
- private static final String UPDATE_CONTENT_FILE_NAME = "tzdata_bundle.zip";
+ private static final String UPDATE_CONTENT_FILE_NAME = "tzdata_distro.zip";
- private final TimeZoneBundleInstaller installer;
+ private final TimeZoneDistroInstaller installer;
public TzDataInstallReceiver() {
super(UPDATE_DIR_NAME, UPDATE_CONTENT_FILE_NAME, UPDATE_METADATA_DIR_NAME,
UPDATE_VERSION_FILE_NAME);
- installer = new TimeZoneBundleInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR);
+ installer = new TimeZoneDistroInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR);
}
@Override
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 27d95a4603a6..de4a55bc8d6a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -61,7 +61,6 @@ import com.android.server.audio.AudioService;
import com.android.server.camera.CameraService;
import com.android.server.clipboard.ClipboardService;
import com.android.server.connectivity.IpConnectivityMetrics;
-import com.android.server.connectivity.MetricsLoggerService;
import com.android.server.devicepolicy.DevicePolicyManagerService;
import com.android.server.display.DisplayManagerService;
import com.android.server.display.NightDisplayService;
@@ -662,10 +661,6 @@ public final class SystemServer {
mSystemServiceManager.startService(BluetoothService.class);
}
- traceBeginAndSlog("ConnectivityMetricsLoggerService");
- mSystemServiceManager.startService(MetricsLoggerService.class);
- Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-
traceBeginAndSlog("IpConnectivityMetrics");
mSystemServiceManager.startService(IpConnectivityMetrics.class);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 83001df58023..0a907496ebdd 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -286,7 +286,8 @@ public class ApfFilter {
}
// Returns seconds since device boot.
- private static long curTime() {
+ @VisibleForTesting
+ protected long currentTimeSeconds() {
return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS;
}
@@ -450,7 +451,7 @@ public class ApfFilter {
}
mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
- mLastSeen = curTime();
+ mLastSeen = currentTimeSeconds();
// Sanity check packet in case a packet arrives before we attach RA filter
// to our packet socket. b/29586253
@@ -580,7 +581,7 @@ public class ApfFilter {
// How many seconds does this RA's have to live, taking into account the fact
// that we might have seen it a while ago.
long currentLifetime() {
- return mMinLifetime - (curTime() - mLastSeen);
+ return mMinLifetime - (currentTimeSeconds() - mLastSeen);
}
boolean isExpired() {
@@ -946,7 +947,7 @@ public class ApfFilter {
Log.e(TAG, "Failed to generate APF program.", e);
return;
}
- mLastTimeInstalledProgram = curTime();
+ mLastTimeInstalledProgram = currentTimeSeconds();
mLastInstalledProgramMinLifetime = programMinLifetime;
mLastInstalledProgram = program;
mNumProgramUpdates++;
@@ -965,7 +966,7 @@ public class ApfFilter {
*/
private boolean shouldInstallnewProgram() {
long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime;
- return expiry < curTime() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING;
+ return expiry < currentTimeSeconds() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING;
}
private void hexDump(String msg, byte[] packet, int length) {
@@ -999,7 +1000,7 @@ public class ApfFilter {
if (ra.matches(packet, length)) {
if (VDBG) log("matched RA " + ra);
// Update lifetimes.
- ra.mLastSeen = curTime();
+ ra.mLastSeen = currentTimeSeconds();
ra.mMinLifetime = ra.minLifetime(packet, length);
ra.seenCount++;
@@ -1128,7 +1129,7 @@ public class ApfFilter {
pw.println("Program updates: " + mNumProgramUpdates);
pw.println(String.format(
"Last program length %d, installed %ds ago, lifetime %ds",
- mLastInstalledProgram.length, curTime() - mLastTimeInstalledProgram,
+ mLastInstalledProgram.length, currentTimeSeconds() - mLastTimeInstalledProgram,
mLastInstalledProgramMinLifetime));
pw.println("RA filters:");
@@ -1137,7 +1138,7 @@ public class ApfFilter {
pw.println(ra);
pw.increaseIndent();
pw.println(String.format(
- "Seen: %d, last %ds ago", ra.seenCount, curTime() - ra.mLastSeen));
+ "Seen: %d, last %ds ago", ra.seenCount, currentTimeSeconds() - ra.mLastSeen));
if (DBG) {
pw.println("Last match:");
pw.increaseIndent();
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index abdf6831b06c..76b1c90642ec 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -33,7 +33,7 @@ import android.net.StaticIpConfiguration;
import android.net.dhcp.DhcpClient;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.IpManagerEvent;
-import android.net.util.AvoidBadWifiTracker;
+import android.net.util.MultinetworkPolicyTracker;
import android.os.INetworkManagementService;
import android.os.Message;
import android.os.RemoteException;
@@ -398,7 +398,7 @@ public class IpManager extends StateMachine {
private final NetlinkTracker mNetlinkTracker;
private final WakeupMessage mProvisioningTimeoutAlarm;
private final WakeupMessage mDhcpActionTimeoutAlarm;
- private final AvoidBadWifiTracker mAvoidBadWifiTracker;
+ private final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
private final LocalLog mLocalLog;
private final LocalLog mConnectivityPacketLog;
private final MessageHandlingLogger mMsgStateLogger;
@@ -492,7 +492,7 @@ public class IpManager extends StateMachine {
mLinkProperties = new LinkProperties();
mLinkProperties.setInterfaceName(mInterfaceName);
- mAvoidBadWifiTracker = new AvoidBadWifiTracker(mContext, getHandler(),
+ mMultinetworkPolicyTracker = new MultinetworkPolicyTracker(mContext, getHandler(),
() -> { mLocalLog.log("OBSERVED AvoidBadWifi changed"); });
mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
@@ -527,7 +527,7 @@ public class IpManager extends StateMachine {
Log.e(mTag, "Couldn't register NetlinkTracker: " + e.toString());
}
- mAvoidBadWifiTracker.start();
+ mMultinetworkPolicyTracker.start();
}
@Override
@@ -538,7 +538,7 @@ public class IpManager extends StateMachine {
// Shut down this IpManager instance altogether.
public void shutdown() {
stop();
- mAvoidBadWifiTracker.shutdown();
+ mMultinetworkPolicyTracker.shutdown();
quit();
}
@@ -767,7 +767,7 @@ public class IpManager extends StateMachine {
// Note that we can still be disconnected by IpReachabilityMonitor
// if the IPv6 default gateway (but not the IPv6 DNS servers; see
// accompanying code in IpReachabilityMonitor) is unreachable.
- final boolean ignoreIPv6ProvisioningLoss = !mAvoidBadWifiTracker.currentValue();
+ final boolean ignoreIPv6ProvisioningLoss = !mMultinetworkPolicyTracker.getAvoidBadWifi();
// Additionally:
//
@@ -1045,7 +1045,7 @@ public class IpManager extends StateMachine {
mCallback.onReachabilityLost(logMsg);
}
},
- mAvoidBadWifiTracker);
+ mMultinetworkPolicyTracker);
} catch (IllegalArgumentException iae) {
// Failed to start IpReachabilityMonitor. Log it and call
// onProvisioningFailure() immediately.
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index a883e28e96c6..20eac622d37f 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -34,7 +34,7 @@ import android.net.netlink.RtNetlinkNeighborMessage;
import android.net.netlink.StructNdaCacheInfo;
import android.net.netlink.StructNdMsg;
import android.net.netlink.StructNlMsgHdr;
-import android.net.util.AvoidBadWifiTracker;
+import android.net.util.MultinetworkPolicyTracker;
import android.os.PowerManager;
import android.os.SystemClock;
import android.system.ErrnoException;
@@ -151,7 +151,7 @@ public class IpReachabilityMonitor {
private final String mInterfaceName;
private final int mInterfaceIndex;
private final Callback mCallback;
- private final AvoidBadWifiTracker mAvoidBadWifiTracker;
+ private final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
private final NetlinkSocketObserver mNetlinkSocketObserver;
private final Thread mObserverThread;
private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
@@ -226,7 +226,7 @@ public class IpReachabilityMonitor {
}
public IpReachabilityMonitor(Context context, String ifName, Callback callback,
- AvoidBadWifiTracker tracker) throws IllegalArgumentException {
+ MultinetworkPolicyTracker tracker) throws IllegalArgumentException {
mInterfaceName = ifName;
int ifIndex = -1;
try {
@@ -238,7 +238,7 @@ public class IpReachabilityMonitor {
mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, TAG + "." + mInterfaceName);
mCallback = callback;
- mAvoidBadWifiTracker = tracker;
+ mMultinetworkPolicyTracker = tracker;
mNetlinkSocketObserver = new NetlinkSocketObserver();
mObserverThread = new Thread(mNetlinkSocketObserver);
mObserverThread.start();
@@ -379,7 +379,7 @@ public class IpReachabilityMonitor {
}
private boolean avoidingBadLinks() {
- return (mAvoidBadWifiTracker != null) ? mAvoidBadWifiTracker.currentValue() : true;
+ return (mMultinetworkPolicyTracker == null) || mMultinetworkPolicyTracker.getAvoidBadWifi();
}
public void probeAll() {
diff --git a/services/net/java/android/net/util/AvoidBadWifiTracker.java b/services/net/java/android/net/util/MultinetworkPolicyTracker.java
index 2abaeb1ae35b..ebd131bebb2b 100644
--- a/services/net/java/android/net/util/AvoidBadWifiTracker.java
+++ b/services/net/java/android/net/util/MultinetworkPolicyTracker.java
@@ -42,8 +42,8 @@ import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
* This enables the device to switch to another form of connectivity, like
* mobile, if it's available and working.
*
- * The Runnable |cb|, if given, is called on the supplied Handler's thread
- * whether the computed "avoid bad wifi" value changes.
+ * The Runnable |avoidBadWifiCallback|, if given, is posted to the supplied
+ * Handler' whenever the computed "avoid bad wifi" value changes.
*
* Disabling this reverts the device to a level of networking sophistication
* circa 2012-13 by disabling disparate code paths each of which contribute to
@@ -51,28 +51,30 @@ import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
*
* @hide
*/
-public class AvoidBadWifiTracker {
- private static String TAG = AvoidBadWifiTracker.class.getSimpleName();
+public class MultinetworkPolicyTracker {
+ private static String TAG = MultinetworkPolicyTracker.class.getSimpleName();
private final Context mContext;
private final Handler mHandler;
private final Runnable mReevaluateRunnable;
- private final Uri mUri;
+ private final Uri mAvoidBadWifiUri;
private final ContentResolver mResolver;
private final SettingObserver mSettingObserver;
private final BroadcastReceiver mBroadcastReceiver;
private volatile boolean mAvoidBadWifi = true;
- public AvoidBadWifiTracker(Context ctx, Handler handler) {
+ public MultinetworkPolicyTracker(Context ctx, Handler handler) {
this(ctx, handler, null);
}
- public AvoidBadWifiTracker(Context ctx, Handler handler, Runnable cb) {
+ public MultinetworkPolicyTracker(Context ctx, Handler handler, Runnable avoidBadWifiCallback) {
mContext = ctx;
mHandler = handler;
- mReevaluateRunnable = () -> { if (update() && cb != null) cb.run(); };
- mUri = Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI);
+ mReevaluateRunnable = () -> {
+ if (updateAvoidBadWifi() && avoidBadWifiCallback != null) avoidBadWifiCallback.run();
+ };
+ mAvoidBadWifiUri = Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI);
mResolver = mContext.getContentResolver();
mSettingObserver = new SettingObserver();
mBroadcastReceiver = new BroadcastReceiver() {
@@ -82,11 +84,11 @@ public class AvoidBadWifiTracker {
}
};
- update();
+ updateAvoidBadWifi();
}
public void start() {
- mResolver.registerContentObserver(mUri, false, mSettingObserver);
+ mResolver.registerContentObserver(mAvoidBadWifiUri, false, mSettingObserver);
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
@@ -102,7 +104,7 @@ public class AvoidBadWifiTracker {
mContext.unregisterReceiver(mBroadcastReceiver);
}
- public boolean currentValue() {
+ public boolean getAvoidBadWifi() {
return mAvoidBadWifi;
}
@@ -117,10 +119,10 @@ public class AvoidBadWifiTracker {
* Whether we should display a notification when wifi becomes unvalidated.
*/
public boolean shouldNotifyWifiUnvalidated() {
- return configRestrictsAvoidBadWifi() && getSettingsValue() == null;
+ return configRestrictsAvoidBadWifi() && getAvoidBadWifiSetting() == null;
}
- public String getSettingsValue() {
+ public String getAvoidBadWifiSetting() {
return Settings.Global.getString(mResolver, NETWORK_AVOID_BAD_WIFI);
}
@@ -129,8 +131,8 @@ public class AvoidBadWifiTracker {
mHandler.post(mReevaluateRunnable);
}
- public boolean update() {
- final boolean settingAvoidBadWifi = "1".equals(getSettingsValue());
+ public boolean updateAvoidBadWifi() {
+ final boolean settingAvoidBadWifi = "1".equals(getAvoidBadWifiSetting());
final boolean prev = mAvoidBadWifi;
mAvoidBadWifi = settingAvoidBadWifi || !configRestrictsAvoidBadWifi();
return mAvoidBadWifi != prev;
@@ -148,7 +150,7 @@ public class AvoidBadWifiTracker {
@Override
public void onChange(boolean selfChange, Uri uri) {
- if (!mUri.equals(uri)) return;
+ if (!mAvoidBadWifiUri.equals(uri)) return;
reevaluate();
}
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index b3f5630b8e25..99eb3d26aba7 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -32,6 +32,7 @@ import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
+import android.os.BatteryManager;
import android.os.FileUtils;
import android.os.Handler;
import android.os.Looper;
@@ -111,6 +112,7 @@ public class UsbDeviceManager {
private static final int MSG_USER_SWITCHED = 5;
private static final int MSG_UPDATE_USER_RESTRICTIONS = 6;
private static final int MSG_UPDATE_HOST_STATE = 7;
+ private static final int MSG_UPDATE_CHARGING_STATE = 9;
private static final int AUDIO_MODE_SOURCE = 1;
@@ -150,6 +152,7 @@ public class UsbDeviceManager {
private UsbDebuggingManager mDebuggingManager;
private final UsbAlsaManager mUsbAlsaManager;
private Intent mBroadcastedIntent;
+ private boolean mPendingBootBroadcast;
private class AdbSettingsObserver extends ContentObserver {
public AdbSettingsObserver() {
@@ -191,6 +194,15 @@ public class UsbDeviceManager {
}
};
+ private final BroadcastReceiver mChargingReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+ boolean usbCharging = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
+ mHandler.sendMessage(MSG_UPDATE_CHARGING_STATE, usbCharging);
+ }
+ };
+
public UsbDeviceManager(Context context, UsbAlsaManager alsaManager) {
mContext = context;
mUsbAlsaManager = alsaManager;
@@ -215,6 +227,8 @@ public class UsbDeviceManager {
}
mContext.registerReceiver(mHostReceiver,
new IntentFilter(UsbManager.ACTION_USB_PORT_CHANGED));
+ mContext.registerReceiver(mChargingReceiver,
+ new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
private UsbSettingsManager getCurrentSettings() {
@@ -329,6 +343,7 @@ public class UsbDeviceManager {
private int mUsbNotificationId;
private boolean mAdbNotificationShown;
private int mCurrentUser = UserHandle.USER_NULL;
+ private boolean mUsbCharging;
public UsbHandler(Looper looper) {
super(looper);
@@ -427,7 +442,10 @@ public class UsbDeviceManager {
args.argi2 = sourcePower ? 1 :0;
args.argi3 = sinkPower ? 1 :0;
- obtainMessage(MSG_UPDATE_HOST_STATE, args).sendToTarget();
+ removeMessages(MSG_UPDATE_HOST_STATE);
+ Message msg = obtainMessage(MSG_UPDATE_HOST_STATE, args);
+ // debounce rapid transitions of connect/disconnect on type-c ports
+ sendMessageDelayed(msg, UPDATE_DELAY);
}
private boolean waitForState(String state) {
@@ -740,13 +758,16 @@ public class UsbDeviceManager {
if (UsbManager.containsFunction(mCurrentFunctions,
UsbManager.USB_FUNCTION_ACCESSORY)) {
updateCurrentAccessory();
- } else if (!mConnected) {
- // restore defaults when USB is disconnected
- setEnabledFunctions(null, false, false);
}
if (mBootCompleted) {
+ if (!mConnected) {
+ // restore defaults when USB is disconnected
+ setEnabledFunctions(null, false, false);
+ }
updateUsbStateBroadcastIfNeeded(false);
updateUsbFunctions();
+ } else {
+ mPendingBootBroadcast = true;
}
break;
case MSG_UPDATE_HOST_STATE:
@@ -758,8 +779,14 @@ public class UsbDeviceManager {
updateUsbNotification();
if (mBootCompleted) {
updateUsbStateBroadcastIfNeeded(false);
+ } else {
+ mPendingBootBroadcast = true;
}
break;
+ case MSG_UPDATE_CHARGING_STATE:
+ mUsbCharging = (msg.arg1 == 1);
+ updateUsbNotification();
+ break;
case MSG_ENABLE_ADB:
setAdbEnabled(msg.arg1 == 1);
break;
@@ -777,6 +804,10 @@ public class UsbDeviceManager {
break;
case MSG_BOOT_COMPLETED:
mBootCompleted = true;
+ if (mPendingBootBroadcast) {
+ updateUsbStateBroadcastIfNeeded(false);
+ mPendingBootBroadcast = false;
+ }
setEnabledFunctions(null, false, false);
if (mCurrentAccessory != null) {
getCurrentSettings().accessoryAttached(mCurrentAccessory);
@@ -840,7 +871,7 @@ public class UsbDeviceManager {
}
} else if (mSourcePower) {
id = com.android.internal.R.string.usb_supplying_notification_title;
- } else if (mHostConnected && mSinkPower) {
+ } else if (mHostConnected && mSinkPower && mUsbCharging) {
id = com.android.internal.R.string.usb_charging_notification_title;
}
if (id != mUsbNotificationId) {
@@ -944,6 +975,7 @@ public class UsbDeviceManager {
pw.println(" mHostConnected: " + mHostConnected);
pw.println(" mSourcePower: " + mSourcePower);
pw.println(" mSinkPower: " + mSinkPower);
+ pw.println(" mUsbCharging: " + mUsbCharging);
try {
pw.println(" Kernel state: "
+ FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim());
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 58c500244d3b..150708223386 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -16,12 +16,21 @@
package android.telecom;
+import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
import java.lang.String;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -828,6 +837,143 @@ public final class Call {
* @param extras Extras associated with the connection event.
*/
public void onConnectionEvent(Call call, String event, Bundle extras) {}
+
+ /**
+ * Invoked when the RTT mode changes for this call.
+ * @param call The call whose RTT mode has changed.
+ * @param mode the new RTT mode, one of
+ * {@link RttCall#RTT_MODE_FULL}, {@link RttCall#RTT_MODE_HCO},
+ * or {@link RttCall#RTT_MODE_VCO}
+ */
+ public void onRttModeChanged(Call call, int mode) {}
+
+ /**
+ * Invoked when the call's RTT status changes, either from off to on or from on to off.
+ * @param call The call whose RTT status has changed.
+ * @param enabled whether RTT is now enabled or disabled
+ * @param rttCall the {@link RttCall} object to use for reading and writing if RTT is now
+ * on, null otherwise.
+ */
+ public void onRttStatusChanged(Call call, boolean enabled, RttCall rttCall) {}
+
+ /**
+ * Invoked when the remote end of the connection has requested that an RTT communication
+ * channel be opened. A response to this should be sent via {@link #respondToRttRequest}
+ * with the same ID that this method is invoked with.
+ * @param call The call which the RTT request was placed on
+ * @param id The ID of the request.
+ */
+ public void onRttRequest(Call call, int id) {}
+ }
+
+ /**
+ * A class that holds the state that describes the state of the RTT channel to the remote
+ * party, if it is active.
+ */
+ public static final class RttCall {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({RTT_MODE_INVALID, RTT_MODE_FULL, RTT_MODE_HCO, RTT_MODE_VCO})
+ public @interface RttAudioMode {}
+
+ /**
+ * For metrics use. Default value in the proto.
+ * @hide
+ */
+ public static final int RTT_MODE_INVALID = 0;
+
+ /**
+ * Indicates that there should be a bidirectional audio stream between the two parties
+ * on the call.
+ */
+ public static final int RTT_MODE_FULL = 1;
+
+ /**
+ * Indicates that the local user should be able to hear the audio stream from the remote
+ * user, but not vice versa. Equivalent to muting the microphone.
+ */
+ public static final int RTT_MODE_HCO = 2;
+
+ /**
+ * Indicates that the remote user should be able to hear the audio stream from the local
+ * user, but not vice versa. Equivalent to setting the volume to zero.
+ */
+ public static final int RTT_MODE_VCO = 3;
+
+ private static final int READ_BUFFER_SIZE = 1000;
+
+ private InputStreamReader mReceiveStream;
+ private OutputStreamWriter mTransmitStream;
+ private int mRttMode;
+ private final InCallAdapter mInCallAdapter;
+ private char[] mReadBuffer = new char[READ_BUFFER_SIZE];
+
+ /**
+ * @hide
+ */
+ public RttCall(InputStreamReader receiveStream, OutputStreamWriter transmitStream,
+ int mode, InCallAdapter inCallAdapter) {
+ mReceiveStream = receiveStream;
+ mTransmitStream = transmitStream;
+ mRttMode = mode;
+ mInCallAdapter = inCallAdapter;
+ }
+
+ /**
+ * Returns the current RTT audio mode.
+ * @return Current RTT audio mode. One of {@link #RTT_MODE_FULL}, {@link #RTT_MODE_VCO}, or
+ * {@link #RTT_MODE_HCO}.
+ */
+ public int getRttAudioMode() {
+ return mRttMode;
+ }
+
+ /**
+ * Sets the RTT audio mode. The requested mode change will be communicated through
+ * {@link Callback#onRttModeChanged(Call, int)}.
+ * @param mode The desired RTT audio mode, one of {@link #RTT_MODE_FULL},
+ * {@link #RTT_MODE_VCO}, or {@link #RTT_MODE_HCO}.
+ */
+ public void setRttMode(@RttAudioMode int mode) {
+ mInCallAdapter.setRttMode(mode);
+ }
+
+ /**
+ * Writes the string {@param input} into the outgoing text stream for this RTT call. Since
+ * RTT transmits text in real-time, this method should be called once for each character
+ * the user enters into the device.
+ *
+ * This method is not thread-safe -- calling it from multiple threads simultaneously may
+ * lead to interleaved text.
+ * @param input The message to send to the remote user.
+ */
+ public void write(String input) throws IOException {
+ mTransmitStream.write(input);
+ mTransmitStream.flush();
+ }
+
+ /**
+ * Reads a string from the remote user, blocking if there is no data available. Returns
+ * {@code null} if the RTT conversation has been terminated and there is no further data
+ * to read.
+ *
+ * This method is not thread-safe -- calling it from multiple threads simultaneously may
+ * lead to interleaved text.
+ * @return A string containing text sent by the remote user, or {@code null} if the
+ * conversation has been terminated or if there was an error while reading.
+ */
+ public String read() {
+ try {
+ int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
+ if (numRead < 0) {
+ return null;
+ }
+ return new String(mReadBuffer, 0, numRead);
+ } catch (IOException e) {
+ Log.w(this, "Exception encountered when reading from InputStreamReader: %s", e);
+ return null;
+ }
+ }
}
/**
@@ -853,8 +999,10 @@ public final class Call {
private String mParentId = null;
private int mState;
private List<String> mCannedTextResponses = null;
+ private String mCallingPackage;
private String mRemainingPostDialSequence;
private VideoCallImpl mVideoCallImpl;
+ private RttCall mRttCall;
private Details mDetails;
private Bundle mExtras;
@@ -1053,6 +1201,34 @@ public final class Call {
}
/**
+ * Sends an RTT upgrade request to the remote end of the connection. Success is not
+ * guaranteed, and notification of success will be via the
+ * {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
+ */
+ public void sendRttRequest() {
+ mInCallAdapter.sendRttRequest();
+ }
+
+ /**
+ * Responds to an RTT request received via the {@link Callback#onRttRequest(Call, int)} )}
+ * callback.
+ * The ID used here should be the same as the ID that was received via the callback.
+ * @param id The request ID received via {@link Callback#onRttRequest(Call, int)}
+ * @param accept {@code true} if the RTT request should be accepted, {@code false} otherwise.
+ */
+ public void respondToRttRequest(int id, boolean accept) {
+ mInCallAdapter.respondToRttRequest(id, accept);
+ }
+
+ /**
+ * Terminate the RTT session on this call. The resulting state change will be notified via
+ * the {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
+ */
+ public void stopRtt() {
+ mInCallAdapter.stopRtt();
+ }
+
+ /**
* Adds some extras to this {@link Call}. Existing keys are replaced and new ones are
* added.
* <p>
@@ -1232,6 +1408,23 @@ public final class Call {
}
/**
+ * Returns this call's RttCall object. The {@link RttCall} instance is used to send and
+ * receive RTT text data, as well as to change the RTT mode.
+ * @return A {@link Call.RttCall}. {@code null} if there is no active RTT connection.
+ */
+ public @Nullable RttCall getRttCall() {
+ return mRttCall;
+ }
+
+ /**
+ * Returns whether this call has an active RTT connection.
+ * @return true if there is a connection, false otherwise.
+ */
+ public boolean isRttActive() {
+ return mRttCall != null;
+ }
+
+ /**
* Registers a callback to this {@code Call}.
*
* @param callback A {@code Callback}.
@@ -1340,19 +1533,22 @@ public final class Call {
}
/** {@hide} */
- Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) {
+ Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, String callingPackage) {
mPhone = phone;
mTelecomCallId = telecomCallId;
mInCallAdapter = inCallAdapter;
mState = STATE_NEW;
+ mCallingPackage = callingPackage;
}
/** {@hide} */
- Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state) {
+ Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state,
+ String callingPackage) {
mPhone = phone;
mTelecomCallId = telecomCallId;
mInCallAdapter = inCallAdapter;
mState = state;
+ mCallingPackage = callingPackage;
}
/** {@hide} */
@@ -1362,6 +1558,7 @@ public final class Call {
/** {@hide} */
final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
+
// First, we update the internal state as far as possible before firing any updates.
Details details = Details.createFromParcelableCall(parcelableCall);
boolean detailsChanged = !Objects.equals(mDetails, details);
@@ -1377,7 +1574,7 @@ public final class Call {
cannedTextResponsesChanged = true;
}
- VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl();
+ VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(mCallingPackage);
boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
!Objects.equals(mVideoCallImpl, newVideoCallImpl);
if (videoCallChanged) {
@@ -1421,6 +1618,32 @@ public final class Call {
fireConferenceableCallsChanged();
}
+ boolean isRttChanged = false;
+ boolean rttModeChanged = false;
+ if (parcelableCall.getParcelableRttCall() != null && parcelableCall.getIsRttCallChanged()) {
+ ParcelableRttCall parcelableRttCall = parcelableCall.getParcelableRttCall();
+ InputStreamReader receiveStream = new InputStreamReader(
+ new ParcelFileDescriptor.AutoCloseInputStream(
+ parcelableRttCall.getReceiveStream()),
+ StandardCharsets.UTF_8);
+ OutputStreamWriter transmitStream = new OutputStreamWriter(
+ new ParcelFileDescriptor.AutoCloseOutputStream(
+ parcelableRttCall.getTransmitStream()),
+ StandardCharsets.UTF_8);
+ RttCall newRttCall = new Call.RttCall(
+ receiveStream, transmitStream, parcelableRttCall.getRttMode(), mInCallAdapter);
+ if (mRttCall == null) {
+ isRttChanged = true;
+ } else if (mRttCall.getRttAudioMode() != newRttCall.getRttAudioMode()) {
+ rttModeChanged = true;
+ }
+ mRttCall = newRttCall;
+ } else if (mRttCall != null && parcelableCall.getParcelableRttCall() == null
+ && parcelableCall.getIsRttCallChanged()) {
+ isRttChanged = true;
+ mRttCall = null;
+ }
+
// Now we fire updates, ensuring that any client who listens to any of these notifications
// gets the most up-to-date state.
@@ -1442,6 +1665,12 @@ public final class Call {
if (childrenChanged) {
fireChildrenChanged(getChildren());
}
+ if (isRttChanged) {
+ fireOnIsRttChanged(mRttCall != null, mRttCall);
+ }
+ if (rttModeChanged) {
+ fireOnRttModeChanged(mRttCall.getRttAudioMode());
+ }
// If we have transitioned to DISCONNECTED, that means we need to notify clients and
// remove ourselves from the Phone. Note that we do this after completing all state updates
@@ -1472,6 +1701,15 @@ public final class Call {
fireOnConnectionEvent(event, extras);
}
+ /** {@hide} */
+ final void internalOnRttUpgradeRequest(final int requestId) {
+ for (CallbackRecord<Callback> record : mCallbackRecords) {
+ final Call call = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(() -> callback.onRttRequest(call, requestId));
+ }
+ }
+
private void fireStateChanged(final int newState) {
for (CallbackRecord<Callback> record : mCallbackRecords) {
final Call call = this;
@@ -1640,6 +1878,32 @@ public final class Call {
}
/**
+ * Notifies listeners of an RTT on/off change
+ *
+ * @param enabled True if RTT is now enabled, false otherwise
+ */
+ private void fireOnIsRttChanged(final boolean enabled, final RttCall rttCall) {
+ for (CallbackRecord<Callback> record : mCallbackRecords) {
+ final Call call = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(() -> callback.onRttStatusChanged(call, enabled, rttCall));
+ }
+ }
+
+ /**
+ * Notifies listeners of a RTT mode change
+ *
+ * @param mode The new RTT mode
+ */
+ private void fireOnRttModeChanged(final int mode) {
+ for (CallbackRecord<Callback> record : mCallbackRecords) {
+ final Call call = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(() -> callback.onRttModeChanged(call, mode));
+ }
+ }
+
+ /**
* Determines if two bundles are equal.
*
* @param bundle The original bundle.
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 560b616f6ca6..3e690b997b29 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -25,15 +25,20 @@ import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.hardware.camera2.CameraManager;
import android.net.Uri;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.ArraySet;
import android.view.Surface;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -384,8 +389,14 @@ public abstract class Connection extends Conferenceable {
*/
public static final int PROPERTY_SELF_MANAGED = 1<<7;
+ /**
+ * When set, indicates that a connection has an active RTT session associated with it.
+ * @hide
+ */
+ public static final int PROPERTY_IS_RTT = 1 << 8;
+
//**********************************************************************************************
- // Next PROPERTY value: 1<<8
+ // Next PROPERTY value: 1<<9
//**********************************************************************************************
/**
@@ -428,6 +439,31 @@ public abstract class Connection extends Conferenceable {
"android.telecom.extra.DISABLE_ADD_CALL";
/**
+ * String connection extra key on a {@link Connection} or {@link Conference} which contains the
+ * original Connection ID associated with the connection. Used in
+ * {@link RemoteConnectionService} to track the Connection ID which was originally assigned to a
+ * connection/conference added via
+ * {@link ConnectionService#addExistingConnection(PhoneAccountHandle, Connection)} and
+ * {@link ConnectionService#addConference(Conference)} APIs. This is important to pass to
+ * Telecom for when it deals with RemoteConnections. When the ConnectionManager wraps the
+ * {@link RemoteConnection} and {@link RemoteConference} and adds it to Telecom, there needs to
+ * be a way to ensure that we don't add the connection again as a duplicate.
+ * <p>
+ * For example, the TelephonyCS calls addExistingConnection for a Connection with ID
+ * {@code TelephonyCS@1}. The ConnectionManager learns of this via
+ * {@link ConnectionService#onRemoteExistingConnectionAdded(RemoteConnection)}, and wraps this
+ * in a new {@link Connection} which it adds to Telecom via
+ * {@link ConnectionService#addExistingConnection(PhoneAccountHandle, Connection)}. As part of
+ * this process, the wrapped RemoteConnection gets assigned a new ID (e.g. {@code ConnMan@1}).
+ * The TelephonyCS will ALSO try to add the existing connection to Telecom, except with the
+ * ID it originally referred to the connection as. Thus Telecom needs to know that the
+ * Connection with ID {@code ConnMan@1} is really the same as {@code TelephonyCS@1}.
+ * @hide
+ */
+ public static final String EXTRA_ORIGINAL_CONNECTION_ID =
+ "android.telecom.extra.ORIGINAL_CONNECTION_ID";
+
+ /**
* Connection event used to inform Telecom that it should play the on hold tone. This is used
* to play a tone when the peer puts the current call on hold. Sent to Telecom via
* {@link #sendConnectionEvent(String, Bundle)}.
@@ -731,6 +767,65 @@ public abstract class Connection extends Conferenceable {
}
/**
+ * Provides methods to read and write RTT data to/from the in-call app.
+ * @hide
+ */
+ public static final class RttTextStream {
+ private static final int READ_BUFFER_SIZE = 1000;
+ private final InputStreamReader mPipeFromInCall;
+ private final OutputStreamWriter mPipeToInCall;
+ private char[] mReadBuffer = new char[READ_BUFFER_SIZE];
+
+ /**
+ * @hide
+ */
+ public RttTextStream(ParcelFileDescriptor toInCall, ParcelFileDescriptor fromInCall) {
+ mPipeFromInCall = new InputStreamReader(
+ new ParcelFileDescriptor.AutoCloseInputStream(fromInCall));
+ mPipeToInCall = new OutputStreamWriter(
+ new ParcelFileDescriptor.AutoCloseOutputStream(toInCall));
+ }
+
+ /**
+ * Writes the string {@param input} into the text stream to the UI for this RTT call. Since
+ * RTT transmits text in real-time, this method should be called as often as text snippets
+ * are received from the remote user, even if it is only one character.
+ *
+ * This method is not thread-safe -- calling it from multiple threads simultaneously may
+ * lead to interleaved text.
+ * @param input The message to send to the in-call app.
+ */
+ public void write(String input) throws IOException {
+ mPipeToInCall.write(input);
+ mPipeToInCall.flush();
+ }
+
+
+ /**
+ * Reads a string from the in-call app, blocking if there is no data available. Returns
+ * {@code null} if the RTT conversation has been terminated and there is no further data
+ * to read.
+ *
+ * This method is not thread-safe -- calling it from multiple threads simultaneously may
+ * lead to interleaved text.
+ * @return A string containing text entered by the user, or {@code null} if the
+ * conversation has been terminated or if there was an error while reading.
+ */
+ public String read() {
+ try {
+ int numRead = mPipeFromInCall.read(mReadBuffer, 0, READ_BUFFER_SIZE);
+ if (numRead < 0) {
+ return null;
+ }
+ return new String(mReadBuffer, 0, numRead);
+ } catch (IOException e) {
+ Log.w(this, "Exception encountered when reading from InputStreamReader: %s", e);
+ return null;
+ }
+ }
+ }
+
+ /**
* Provides a means of controlling the video session associated with a {@link Connection}.
* <p>
* Implementations create a custom subclass of {@link VideoProvider} and the
@@ -774,7 +869,7 @@ public abstract class Connection extends Conferenceable {
public static final int SESSION_EVENT_TX_STOP = 4;
/**
- * A camera failure has occurred for the selected camera. The {@link InCallService} can use
+ * A camera failure has occurred for the selected camera. The {@link VideoProvider} can use
* this as a cue to inform the user the camera is not available.
* @see #handleCallSessionEvent(int)
*/
@@ -782,13 +877,21 @@ public abstract class Connection extends Conferenceable {
/**
* Issued after {@link #SESSION_EVENT_CAMERA_FAILURE} when the camera is once again ready
- * for operation. The {@link InCallService} can use this as a cue to inform the user that
+ * for operation. The {@link VideoProvider} can use this as a cue to inform the user that
* the camera has become available again.
* @see #handleCallSessionEvent(int)
*/
public static final int SESSION_EVENT_CAMERA_READY = 6;
/**
+ * Session event raised by Telecom when
+ * {@link android.telecom.InCallService.VideoCall#setCamera(String)} is called and the
+ * caller does not have the necessary {@link android.Manifest.permission#CAMERA} permission.
+ * @see #handleCallSessionEvent(int)
+ */
+ public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7;
+
+ /**
* Session modify request was successful.
* @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
*/
@@ -837,6 +940,8 @@ public abstract class Connection extends Conferenceable {
private static final String SESSION_EVENT_TX_STOP_STR = "TX_STOP";
private static final String SESSION_EVENT_CAMERA_FAILURE_STR = "CAMERA_FAIL";
private static final String SESSION_EVENT_CAMERA_READY_STR = "CAMERA_READY";
+ private static final String SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR =
+ "CAMERA_PERMISSION_ERROR";
private static final String SESSION_EVENT_UNKNOWN_STR = "UNKNOWN";
private VideoProvider.VideoProviderHandler mMessageHandler;
@@ -895,8 +1000,17 @@ public abstract class Connection extends Conferenceable {
break;
}
case MSG_SET_CAMERA:
- onSetCamera((String) msg.obj);
- break;
+ {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ onSetCamera((String) args.arg1);
+ onSetCamera((String) args.arg1, (String) args.arg2, args.argi1,
+ args.argi2);
+ } finally {
+ args.recycle();
+ }
+ }
+ break;
case MSG_SET_PREVIEW_SURFACE:
onSetPreviewSurface((Surface) msg.obj);
break;
@@ -951,8 +1065,19 @@ public abstract class Connection extends Conferenceable {
MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
}
- public void setCamera(String cameraId) {
- mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget();
+ public void setCamera(String cameraId, String callingPackageName) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = cameraId;
+ // Propagate the calling package; originally determined in
+ // android.telecom.InCallService.VideoCall#setCamera(String) from the calling
+ // process.
+ args.arg2 = callingPackageName;
+ // Pass along the uid and pid of the calling app; this gets lost when we put the
+ // message onto the handler. These are required for Telecom to perform a permission
+ // check to see if the calling app is able to use the camera.
+ args.argi1 = Binder.getCallingUid();
+ args.argi2 = Binder.getCallingPid();
+ mMessageHandler.obtainMessage(MSG_SET_CAMERA, args).sendToTarget();
}
public void setPreviewSurface(Surface surface) {
@@ -1037,6 +1162,29 @@ public abstract class Connection extends Conferenceable {
public abstract void onSetCamera(String cameraId);
/**
+ * Sets the camera to be used for the outgoing video.
+ * <p>
+ * The {@link VideoProvider} should respond by communicating the capabilities of the chosen
+ * camera via
+ * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}.
+ * <p>
+ * This prototype is used internally to ensure that the calling package name, UID and PID
+ * are sent to Telecom so that can perform a camera permission check on the caller.
+ * <p>
+ * Sent from the {@link InCallService} via
+ * {@link InCallService.VideoCall#setCamera(String)}.
+ *
+ * @param cameraId The id of the camera (use ids as reported by
+ * {@link CameraManager#getCameraIdList()}).
+ * @param callingPackageName The AppOpps package name of the caller.
+ * @param callingUid The UID of the caller.
+ * @param callingPid The PID of the caller.
+ * @hide
+ */
+ public void onSetCamera(String cameraId, String callingPackageName, int callingUid,
+ int callingPid) {}
+
+ /**
* Sets the surface to be used for displaying a preview of what the user's camera is
* currently capturing. When video transmission is enabled, this is the video signal which
* is sent to the remote device.
@@ -1222,7 +1370,8 @@ public abstract class Connection extends Conferenceable {
* {@link VideoProvider#SESSION_EVENT_TX_START},
* {@link VideoProvider#SESSION_EVENT_TX_STOP},
* {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE},
- * {@link VideoProvider#SESSION_EVENT_CAMERA_READY}.
+ * {@link VideoProvider#SESSION_EVENT_CAMERA_READY},
+ * {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE}.
*/
public void handleCallSessionEvent(int event) {
if (mVideoCallbacks != null) {
@@ -1371,6 +1520,8 @@ public abstract class Connection extends Conferenceable {
return SESSION_EVENT_TX_START_STR;
case SESSION_EVENT_TX_STOP:
return SESSION_EVENT_TX_STOP_STR;
+ case SESSION_EVENT_CAMERA_PERMISSION_ERROR:
+ return SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR;
default:
return SESSION_EVENT_UNKNOWN_STR + " " + event;
}
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index 23434624bf87..054de4c56138 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -19,6 +19,7 @@ package android.telecom;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
/**
@@ -27,13 +28,121 @@ import android.os.Parcelable;
*/
public final class ConnectionRequest implements Parcelable {
- // TODO: Token to limit recursive invocations
+ /**
+ * Builder class for {@link ConnectionRequest}
+ * @hide
+ */
+ public static final class Builder {
+ private PhoneAccountHandle mAccountHandle;
+ private Uri mAddress;
+ private Bundle mExtras;
+ private int mVideoState = VideoProfile.STATE_AUDIO_ONLY;
+ private String mTelecomCallId;
+ private boolean mShouldShowIncomingCallUi = false;
+ private ParcelFileDescriptor mRttPipeToInCall;
+ private ParcelFileDescriptor mRttPipeFromInCall;
+
+ public Builder() { }
+
+ /**
+ * Sets the phone account handle for the resulting {@link ConnectionRequest}
+ * @param accountHandle The accountHandle which should be used to place the call.
+ */
+ public Builder setAccountHandle(PhoneAccountHandle accountHandle) {
+ this.mAccountHandle = accountHandle;
+ return this;
+ }
+
+ /**
+ * Sets the address for the resulting {@link ConnectionRequest}
+ * @param address The address(e.g., phone number) to which the {@link Connection} is to
+ * connect.
+ */
+ public Builder setAddress(Uri address) {
+ this.mAddress = address;
+ return this;
+ }
+
+ /**
+ * Sets the extras bundle for the resulting {@link ConnectionRequest}
+ * @param extras Application-specific extra data.
+ */
+ public Builder setExtras(Bundle extras) {
+ this.mExtras = extras;
+ return this;
+ }
+
+ /**
+ * Sets the video state for the resulting {@link ConnectionRequest}
+ * @param videoState Determines the video state for the connection.
+ */
+ public Builder setVideoState(int videoState) {
+ this.mVideoState = videoState;
+ return this;
+ }
+
+ /**
+ * Sets the Telecom call ID for the resulting {@link ConnectionRequest}
+ * @param telecomCallId The telecom call ID.
+ */
+ public Builder setTelecomCallId(String telecomCallId) {
+ this.mTelecomCallId = telecomCallId;
+ return this;
+ }
+
+ /**
+ * Sets shouldShowIncomingUi for the resulting {@link ConnectionRequest}
+ * @param shouldShowIncomingCallUi For a self-managed {@link ConnectionService}, will be
+ * {@code true} if the {@link ConnectionService} should show
+ * its own incoming call UI for an incoming call. When
+ * {@code false}, Telecom shows the incoming call UI.
+ */
+ public Builder setShouldShowIncomingCallUi(boolean shouldShowIncomingCallUi) {
+ this.mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
+ return this;
+ }
+
+ /**
+ * Sets the RTT pipe for transferring text into the {@link ConnectionService} for the
+ * resulting {@link ConnectionRequest}
+ * @param rttPipeFromInCall The data pipe to read from.
+ */
+ public Builder setRttPipeFromInCall(ParcelFileDescriptor rttPipeFromInCall) {
+ this.mRttPipeFromInCall = rttPipeFromInCall;
+ return this;
+ }
+
+ /**
+ * Sets the RTT pipe for transferring text out of {@link ConnectionService} for the
+ * resulting {@link ConnectionRequest}
+ * @param rttPipeToInCall The data pipe to write to.
+ */
+ public Builder setRttPipeToInCall(ParcelFileDescriptor rttPipeToInCall) {
+ this.mRttPipeToInCall = rttPipeToInCall;
+ return this;
+ }
+
+ public ConnectionRequest build() {
+ return new ConnectionRequest(
+ mAccountHandle,
+ mAddress,
+ mExtras,
+ mVideoState,
+ mTelecomCallId,
+ mShouldShowIncomingCallUi,
+ mRttPipeFromInCall,
+ mRttPipeToInCall);
+ }
+ }
+
private final PhoneAccountHandle mAccountHandle;
private final Uri mAddress;
private final Bundle mExtras;
private final int mVideoState;
private final String mTelecomCallId;
private final boolean mShouldShowIncomingCallUi;
+ private final ParcelFileDescriptor mRttPipeToInCall;
+ private final ParcelFileDescriptor mRttPipeFromInCall;
/**
* @param accountHandle The accountHandle which should be used to place the call.
@@ -44,7 +153,7 @@ public final class ConnectionRequest implements Parcelable {
PhoneAccountHandle accountHandle,
Uri handle,
Bundle extras) {
- this(accountHandle, handle, extras, VideoProfile.STATE_AUDIO_ONLY, null, false);
+ this(accountHandle, handle, extras, VideoProfile.STATE_AUDIO_ONLY, null, false, null, null);
}
/**
@@ -58,7 +167,7 @@ public final class ConnectionRequest implements Parcelable {
Uri handle,
Bundle extras,
int videoState) {
- this(accountHandle, handle, extras, videoState, null, false);
+ this(accountHandle, handle, extras, videoState, null, false, null, null);
}
/**
@@ -80,12 +189,27 @@ public final class ConnectionRequest implements Parcelable {
int videoState,
String telecomCallId,
boolean shouldShowIncomingCallUi) {
+ this(accountHandle, handle, extras, videoState, telecomCallId,
+ shouldShowIncomingCallUi, null, null);
+ }
+
+ private ConnectionRequest(
+ PhoneAccountHandle accountHandle,
+ Uri handle,
+ Bundle extras,
+ int videoState,
+ String telecomCallId,
+ boolean shouldShowIncomingCallUi,
+ ParcelFileDescriptor rttPipeFromInCall,
+ ParcelFileDescriptor rttPipeToInCall) {
mAccountHandle = accountHandle;
mAddress = handle;
mExtras = extras;
mVideoState = videoState;
mTelecomCallId = telecomCallId;
mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
+ mRttPipeFromInCall = rttPipeFromInCall;
+ mRttPipeToInCall = rttPipeToInCall;
}
private ConnectionRequest(Parcel in) {
@@ -95,6 +219,8 @@ public final class ConnectionRequest implements Parcelable {
mVideoState = in.readInt();
mTelecomCallId = in.readString();
mShouldShowIncomingCallUi = in.readInt() == 1;
+ mRttPipeFromInCall = in.readParcelable(getClass().getClassLoader());
+ mRttPipeToInCall = in.readParcelable(getClass().getClassLoader());
}
/**
@@ -149,6 +275,59 @@ public final class ConnectionRequest implements Parcelable {
return mShouldShowIncomingCallUi;
}
+ /**
+ * Gets the {@link ParcelFileDescriptor} that is used to send RTT text from the connection
+ * service to the in-call UI. In order to obtain an
+ * {@link java.io.InputStream} from this {@link ParcelFileDescriptor}, use
+ * {@link android.os.ParcelFileDescriptor.AutoCloseInputStream}.
+ * Only text data encoded using UTF-8 should be written into this {@link ParcelFileDescriptor}.
+ * @return The {@link ParcelFileDescriptor} that should be used for communication.
+ * Do not un-hide -- only for use by Telephony
+ * @hide
+ */
+ public ParcelFileDescriptor getRttPipeToInCall() {
+ return mRttPipeToInCall;
+ }
+
+ /**
+ * Gets the {@link ParcelFileDescriptor} that is used to send RTT text from the in-call UI to
+ * the connection service. In order to obtain an
+ * {@link java.io.OutputStream} from this {@link ParcelFileDescriptor}, use
+ * {@link android.os.ParcelFileDescriptor.AutoCloseOutputStream}.
+ * The contents of this {@link ParcelFileDescriptor} will consist solely of text encoded in
+ * UTF-8.
+ * @return The {@link ParcelFileDescriptor} that should be used for communication
+ * Do not un-hide -- only for use by Telephony
+ * @hide
+ */
+ public ParcelFileDescriptor getRttPipeFromInCall() {
+ return mRttPipeFromInCall;
+ }
+
+ /**
+ * Gets the {@link android.telecom.Connection.RttTextStream} object that should be used to
+ * send and receive RTT text to/from the in-call app.
+ * @return An instance of {@link android.telecom.Connection.RttTextStream}, or {@code null}
+ * if this connection request is not requesting an RTT session upon connection establishment.
+ * @hide
+ */
+ public Connection.RttTextStream getRttTextStream() {
+ if (isRequestingRtt()) {
+ return new Connection.RttTextStream(mRttPipeToInCall, mRttPipeFromInCall);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Convenience method for determining whether the ConnectionRequest is requesting an RTT session
+ * @return {@code true} if RTT is requested, {@code false} otherwise.
+ * @hide
+ */
+ public boolean isRequestingRtt() {
+ return mRttPipeFromInCall != null && mRttPipeToInCall != null;
+ }
+
@Override
public String toString() {
return String.format("ConnectionRequest %s %s",
@@ -186,5 +365,7 @@ public final class ConnectionRequest implements Parcelable {
destination.writeInt(mVideoState);
destination.writeString(mTelecomCallId);
destination.writeInt(mShouldShowIncomingCallUi ? 1 : 0);
+ destination.writeParcelable(mRttPipeFromInCall, 0);
+ destination.writeParcelable(mRttPipeToInCall, 0);
}
}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index ce3144bbeacf..6e100298da35 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -98,6 +98,7 @@ public abstract class ConnectionService extends Service {
private static final String SESSION_ADD_CS_ADAPTER = "CS.aCSA";
private static final String SESSION_REMOVE_CS_ADAPTER = "CS.rCSA";
private static final String SESSION_CREATE_CONN = "CS.crCo";
+ private static final String SESSION_CREATE_CONN_FAILED = "CS.crCoF";
private static final String SESSION_ABORT = "CS.ab";
private static final String SESSION_ANSWER = "CS.an";
private static final String SESSION_ANSWER_VIDEO = "CS.anV";
@@ -142,6 +143,7 @@ public abstract class ConnectionService extends Service {
private static final int MSG_PULL_EXTERNAL_CALL = 22;
private static final int MSG_SEND_CALL_EVENT = 23;
private static final int MSG_ON_EXTRAS_CHANGED = 24;
+ private static final int MSG_CREATE_CONNECTION_FAILED = 25;
private static Connection sNullConnection;
@@ -211,6 +213,25 @@ public abstract class ConnectionService extends Service {
}
@Override
+ public void createConnectionFailed(
+ String callId,
+ ConnectionRequest request,
+ boolean isIncoming,
+ Session.Info sessionInfo) {
+ Log.startSession(sessionInfo, SESSION_CREATE_CONN_FAILED);
+ try {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = request;
+ args.arg3 = Log.createSubsession();
+ args.argi1 = isIncoming ? 1 : 0;
+ mHandler.obtainMessage(MSG_CREATE_CONNECTION_FAILED, args).sendToTarget();
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
public void abort(String callId, Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_ABORT);
try {
@@ -552,6 +573,35 @@ public abstract class ConnectionService extends Service {
}
break;
}
+ case MSG_CREATE_CONNECTION_FAILED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Log.continueSession((Session) args.arg3, SESSION_HANDLER +
+ SESSION_CREATE_CONN_FAILED);
+ try {
+ final String id = (String) args.arg1;
+ final ConnectionRequest request = (ConnectionRequest) args.arg2;
+ final boolean isIncoming = args.argi1 == 1;
+ if (!mAreAccountsInitialized) {
+ Log.d(this, "Enqueueing pre-init request %s", id);
+ mPreInitializationConnectionRequests.add(
+ new android.telecom.Logging.Runnable(
+ SESSION_HANDLER + SESSION_CREATE_CONN_FAILED + ".pICR",
+ null /*lock*/) {
+ @Override
+ public void loggedRun() {
+ createConnectionFailed(id, request, isIncoming);
+ }
+ }.prepare());
+ } else {
+ Log.i(this, "createConnectionFailed %s", id);
+ createConnectionFailed(id, request, isIncoming);
+ }
+ } finally {
+ args.recycle();
+ Log.endSession();
+ }
+ break;
+ }
case MSG_ABORT: {
SomeArgs args = (SomeArgs) msg.obj;
Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_ABORT);
@@ -1175,6 +1225,17 @@ public abstract class ConnectionService extends Service {
}
}
+ private void createConnectionFailed(final String callId, final ConnectionRequest request,
+ boolean isIncoming) {
+
+ Log.i(this, "createConnectionFailed %s", callId);
+ if (isIncoming) {
+ onCreateIncomingConnectionFailed(request);
+ } else {
+ onCreateOutgoingConnectionFailed(request);
+ }
+ }
+
private void abort(String callId) {
Log.d(this, "abort %s", callId);
findConnectionForAction(callId, "abort").onAbort();
@@ -1756,7 +1817,13 @@ public abstract class ConnectionService extends Service {
*/
private String addExistingConnectionInternal(PhoneAccountHandle handle, Connection connection) {
String id;
- if (handle == null) {
+
+ if (connection.getExtras() != null && connection.getExtras()
+ .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
+ id = connection.getExtras().getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID);
+ Log.d(this, "addExistingConnectionInternal - conn %s reusing original id %s",
+ connection.getTelecomCallId(), id);
+ } else if (handle == null) {
// If no phone account handle was provided, we cannot be sure the call ID is unique,
// so just use a random UUID.
id = UUID.randomUUID().toString();
@@ -1790,13 +1857,21 @@ public abstract class ConnectionService extends Service {
}
private String addConferenceInternal(Conference conference) {
+ String originalId = null;
+ if (conference.getExtras() != null && conference.getExtras()
+ .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
+ originalId = conference.getExtras().getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID);
+ Log.d(this, "addConferenceInternal: conf %s reusing original id %s",
+ conference.getTelecomCallId(),
+ originalId);
+ }
if (mIdByConference.containsKey(conference)) {
Log.w(this, "Re-adding an existing conference: %s.", conference);
} else if (conference != null) {
// Conferences do not (yet) have a PhoneAccountHandle associated with them, so we
// cannot determine a ConnectionService class name to associate with the ID, so use
// a unique UUID (for now).
- String id = UUID.randomUUID().toString();
+ String id = originalId == null ? UUID.randomUUID().toString() : originalId;
mConferenceById.put(id, conference);
mIdByConference.put(conference, id);
conference.addListener(mConferenceListener);
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 3f270d9c5829..d640b1dd6022 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -34,7 +34,7 @@ import java.util.List;
* <p>
* The adapter will stop functioning when there are no more calls.
*
- * {@hide}
+ * @hide
*/
public final class InCallAdapter {
private final IInCallAdapter mAdapter;
@@ -375,4 +375,48 @@ public final class InCallAdapter {
} catch (RemoteException ignored) {
}
}
+
+ /**
+ * Sends an RTT upgrade request to the remote end of the connection.
+ */
+ public void sendRttRequest() {
+ try {
+ mAdapter.sendRttRequest();
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
+ * Responds to an RTT upgrade request initiated from the remote end.
+ *
+ * @param id the ID of the request as specified by Telecom
+ * @param accept Whether the request should be accepted.
+ */
+ public void respondToRttRequest(int id, boolean accept) {
+ try {
+ mAdapter.respondToRttRequest(id, accept);
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
+ * Instructs Telecom to shut down the RTT communication channel.
+ */
+ public void stopRtt() {
+ try {
+ mAdapter.stopRtt();
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
+ * Sets the RTT audio mode.
+ * @param mode the desired RTT audio mode
+ */
+ public void setRttMode(int mode) {
+ try {
+ mAdapter.setRttMode(mode);
+ } catch (RemoteException ignored) {
+ }
+ }
}
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 69de89d5ed74..4bc64c05bfee 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -76,6 +76,7 @@ public abstract class InCallService extends Service {
private static final int MSG_ON_CAN_ADD_CALL_CHANGED = 7;
private static final int MSG_SILENCE_RINGER = 8;
private static final int MSG_ON_CONNECTION_EVENT = 9;
+ private static final int MSG_ON_RTT_UPGRADE_REQUEST = 10;
/** Default Handler used to consolidate binder method calls onto a single thread. */
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -87,7 +88,8 @@ public abstract class InCallService extends Service {
switch (msg.what) {
case MSG_SET_IN_CALL_ADAPTER:
- mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj));
+ String callingPackage = getApplicationContext().getOpPackageName();
+ mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj), callingPackage);
mPhone.addListener(mPhoneListener);
onPhoneCreated(mPhone);
break;
@@ -132,6 +134,12 @@ public abstract class InCallService extends Service {
}
break;
}
+ case MSG_ON_RTT_UPGRADE_REQUEST: {
+ String callId = (String) msg.obj;
+ int requestId = msg.arg1;
+ mPhone.internalOnRttUpgradeRequest(callId, requestId);
+ break;
+ }
default:
break;
}
@@ -197,6 +205,11 @@ public abstract class InCallService extends Service {
args.arg3 = extras;
mHandler.obtainMessage(MSG_ON_CONNECTION_EVENT, args).sendToTarget();
}
+
+ @Override
+ public void onRttUpgradeRequest(String callId, int id) {
+ mHandler.obtainMessage(MSG_ON_RTT_UPGRADE_REQUEST, id, 0, callId).sendToTarget();
+ }
}
private Phone.Listener mPhoneListener = new Phone.Listener() {
@@ -664,7 +677,8 @@ public abstract class InCallService extends Service {
* {@link Connection.VideoProvider#SESSION_EVENT_TX_START},
* {@link Connection.VideoProvider#SESSION_EVENT_TX_STOP},
* {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_FAILURE},
- * {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_READY}.
+ * {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_READY},
+ * {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_PERMISSION_ERROR}.
*/
public abstract void onCallSessionEvent(int event);
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index f7a6595241e0..975aa5a332ca 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -50,6 +50,8 @@ public final class ParcelableCall implements Parcelable {
private final boolean mIsVideoCallProviderChanged;
private final IVideoProvider mVideoCallProvider;
private VideoCallImpl mVideoCall;
+ private final boolean mIsRttCallChanged;
+ private final ParcelableRttCall mRttCall;
private final String mParentCallId;
private final List<String> mChildCallIds;
private final StatusHints mStatusHints;
@@ -75,6 +77,8 @@ public final class ParcelableCall implements Parcelable {
PhoneAccountHandle accountHandle,
boolean isVideoCallProviderChanged,
IVideoProvider videoCallProvider,
+ boolean isRttCallChanged,
+ ParcelableRttCall rttCall,
String parentCallId,
List<String> childCallIds,
StatusHints statusHints,
@@ -98,6 +102,8 @@ public final class ParcelableCall implements Parcelable {
mAccountHandle = accountHandle;
mIsVideoCallProviderChanged = isVideoCallProviderChanged;
mVideoCallProvider = videoCallProvider;
+ mIsRttCallChanged = isRttCallChanged;
+ mRttCall = rttCall;
mParentCallId = parentCallId;
mChildCallIds = childCallIds;
mStatusHints = statusHints;
@@ -190,10 +196,10 @@ public final class ParcelableCall implements Parcelable {
* @return The video call.
*/
- public VideoCallImpl getVideoCallImpl() {
+ public VideoCallImpl getVideoCallImpl(String callingPackageName) {
if (mVideoCall == null && mVideoCallProvider != null) {
try {
- mVideoCall = new VideoCallImpl(mVideoCallProvider);
+ mVideoCall = new VideoCallImpl(mVideoCallProvider, callingPackageName);
} catch (RemoteException ignored) {
// Ignore RemoteException.
}
@@ -202,6 +208,18 @@ public final class ParcelableCall implements Parcelable {
return mVideoCall;
}
+ public boolean getIsRttCallChanged() {
+ return mIsRttCallChanged;
+ }
+
+ /**
+ * RTT communication channel information
+ * @return The ParcelableRttCall
+ */
+ public ParcelableRttCall getParcelableRttCall() {
+ return mRttCall;
+ }
+
/**
* The conference call to which this call is conferenced. Null if not conferenced.
*/
@@ -301,6 +319,8 @@ public final class ParcelableCall implements Parcelable {
Bundle intentExtras = source.readBundle(classLoader);
Bundle extras = source.readBundle(classLoader);
int supportedAudioRoutes = source.readInt();
+ boolean isRttCallChanged = source.readByte() == 1;
+ ParcelableRttCall rttCall = source.readParcelable(classLoader);
return new ParcelableCall(
id,
state,
@@ -318,6 +338,8 @@ public final class ParcelableCall implements Parcelable {
accountHandle,
isVideoCallProviderChanged,
videoCallProvider,
+ isRttCallChanged,
+ rttCall,
parentCallId,
childCallIds,
statusHints,
@@ -366,6 +388,8 @@ public final class ParcelableCall implements Parcelable {
destination.writeBundle(mIntentExtras);
destination.writeBundle(mExtras);
destination.writeInt(mSupportedAudioRoutes);
+ destination.writeByte((byte) (mIsRttCallChanged ? 1 : 0));
+ destination.writeParcelable(mRttCall, 0);
}
@Override
diff --git a/telecomm/java/android/telecom/ParcelableRttCall.aidl b/telecomm/java/android/telecom/ParcelableRttCall.aidl
new file mode 100644
index 000000000000..4480710f51f6
--- /dev/null
+++ b/telecomm/java/android/telecom/ParcelableRttCall.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecom;
+
+/**
+ * {@hide}
+ */
+parcelable ParcelableRttCall;
diff --git a/telecomm/java/android/telecom/ParcelableRttCall.java b/telecomm/java/android/telecom/ParcelableRttCall.java
new file mode 100644
index 000000000000..763e48b19779
--- /dev/null
+++ b/telecomm/java/android/telecom/ParcelableRttCall.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telecom;
+
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Data container for information associated with the RTT connection on a call.
+ * @hide
+ */
+public class ParcelableRttCall implements Parcelable {
+ private final int mRttMode;
+ private final ParcelFileDescriptor mTransmitStream;
+ private final ParcelFileDescriptor mReceiveStream;
+
+ public ParcelableRttCall(
+ int rttMode,
+ ParcelFileDescriptor transmitStream,
+ ParcelFileDescriptor receiveStream) {
+ mRttMode = rttMode;
+ mTransmitStream = transmitStream;
+ mReceiveStream = receiveStream;
+ }
+
+ protected ParcelableRttCall(Parcel in) {
+ mRttMode = in.readInt();
+ mTransmitStream = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
+ mReceiveStream = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
+ }
+
+ public static final Creator<ParcelableRttCall> CREATOR = new Creator<ParcelableRttCall>() {
+ @Override
+ public ParcelableRttCall createFromParcel(Parcel in) {
+ return new ParcelableRttCall(in);
+ }
+
+ @Override
+ public ParcelableRttCall[] newArray(int size) {
+ return new ParcelableRttCall[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mRttMode);
+ dest.writeParcelable(mTransmitStream, flags);
+ dest.writeParcelable(mReceiveStream, flags);
+ }
+
+ public int getRttMode() {
+ return mRttMode;
+ }
+
+ public ParcelFileDescriptor getReceiveStream() {
+ return mReceiveStream;
+ }
+
+ public ParcelFileDescriptor getTransmitStream() {
+ return mTransmitStream;
+ }
+}
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index a4ef5601e551..ebd04c7cd666 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -125,13 +125,16 @@ public final class Phone {
private boolean mCanAddCall = true;
- Phone(InCallAdapter adapter) {
+ private final String mCallingPackage;
+
+ Phone(InCallAdapter adapter, String callingPackage) {
mInCallAdapter = adapter;
+ mCallingPackage = callingPackage;
}
final void internalAddCall(ParcelableCall parcelableCall) {
Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
- parcelableCall.getState());
+ parcelableCall.getState(), mCallingPackage);
mCallByTelecomCallId.put(parcelableCall.getId(), call);
mCalls.add(call);
checkCallTree(parcelableCall);
@@ -198,6 +201,13 @@ public final class Phone {
}
}
+ final void internalOnRttUpgradeRequest(String callId, int requestId) {
+ Call call = mCallByTelecomCallId.get(callId);
+ if (call != null) {
+ call.internalOnRttUpgradeRequest(requestId);
+ }
+ }
+
/**
* Called to destroy the phone and cleanup any lingering calls.
*/
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 845a1033c123..3926e201a5e3 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -204,6 +204,18 @@ public final class PhoneAccount implements Parcelable {
public static final int CAPABILITY_SELF_MANAGED = 0x800;
/**
+ * Flag indicating that this {@link PhoneAccount} is capable of making a call with an
+ * RTT (Real-time text) session.
+ * When set, Telecom will attempt to open an RTT session on outgoing calls that specify
+ * that they should be placed with an RTT session , and the in-call app will be displayed
+ * with text entry fields for RTT. Likewise, the in-call app can request that an RTT
+ * session be opened during a call if this bit is set.
+ */
+ public static final int CAPABILITY_RTT = 0x1000;
+
+ /* NEXT CAPABILITY: 0x2000 */
+
+ /**
* URI scheme for telephone number URIs.
*/
public static final String SCHEME_TEL = "tel";
diff --git a/telecomm/java/android/telecom/RemoteConference.java b/telecomm/java/android/telecom/RemoteConference.java
index 4bff688dc5ca..502b7c01b0c0 100644
--- a/telecomm/java/android/telecom/RemoteConference.java
+++ b/telecomm/java/android/telecom/RemoteConference.java
@@ -311,6 +311,9 @@ public final class RemoteConference {
/** @hide */
void putExtras(final Bundle extras) {
+ if (extras == null) {
+ return;
+ }
if (mExtras == null) {
mExtras = new Bundle();
}
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 11842a0d02e2..77e0e5486127 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -408,6 +408,8 @@ public final class RemoteConnection {
private final IVideoProvider mVideoProviderBinder;
+ private final String mCallingPackage;
+
/**
* ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
* load factor before resizing, 1 means we only expect a single thread to
@@ -416,8 +418,9 @@ public final class RemoteConnection {
private final Set<Callback> mCallbacks = Collections.newSetFromMap(
new ConcurrentHashMap<Callback, Boolean>(8, 0.9f, 1));
- VideoProvider(IVideoProvider videoProviderBinder) {
+ VideoProvider(IVideoProvider videoProviderBinder, String callingPackage) {
mVideoProviderBinder = videoProviderBinder;
+ mCallingPackage = callingPackage;
try {
mVideoProviderBinder.addVideoCallback(mVideoCallbackServant.getStub().asBinder());
} catch (RemoteException e) {
@@ -452,7 +455,7 @@ public final class RemoteConnection {
*/
public void setCamera(String cameraId) {
try {
- mVideoProviderBinder.setCamera(cameraId);
+ mVideoProviderBinder.setCamera(cameraId, mCallingPackage);
} catch (RemoteException e) {
}
}
@@ -628,7 +631,7 @@ public final class RemoteConnection {
* @hide
*/
RemoteConnection(String callId, IConnectionService connectionService,
- ParcelableConnection connection) {
+ ParcelableConnection connection, String callingPackage) {
mConnectionId = callId;
mConnectionService = connectionService;
mConnected = true;
@@ -640,7 +643,7 @@ public final class RemoteConnection {
mVideoState = connection.getVideoState();
IVideoProvider videoProvider = connection.getVideoProvider();
if (videoProvider != null) {
- mVideoProvider = new RemoteConnection.VideoProvider(videoProvider);
+ mVideoProvider = new RemoteConnection.VideoProvider(videoProvider, callingPackage);
} else {
mVideoProvider = null;
}
@@ -651,6 +654,14 @@ public final class RemoteConnection {
mCallerDisplayName = connection.getCallerDisplayName();
mCallerDisplayNamePresentation = connection.getCallerDisplayNamePresentation();
mConference = null;
+ putExtras(connection.getExtras());
+
+ // Stash the original connection ID as it exists in the source ConnectionService.
+ // Telecom will use this to avoid adding duplicates later.
+ // See comments on Connection.EXTRA_ORIGINAL_CONNECTION_ID for more information.
+ Bundle newExtras = new Bundle();
+ newExtras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
+ putExtras(newExtras);
}
/**
@@ -1350,6 +1361,9 @@ public final class RemoteConnection {
/** @hide */
void putExtras(final Bundle extras) {
+ if (extras == null) {
+ return;
+ }
if (mExtras == null) {
mExtras = new Bundle();
}
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index fe14003bca68..60a40f5261dd 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -219,18 +219,27 @@ final class RemoteConnectionService {
conference.addConnection(c);
}
}
-
if (conference.getConnections().size() == 0) {
// A conference was created, but none of its connections are ones that have been
// created by, and therefore being tracked by, this remote connection service. It
// is of no interest to us.
+ Log.d(this, "addConferenceCall - skipping");
return;
}
conference.setState(parcel.getState());
conference.setConnectionCapabilities(parcel.getConnectionCapabilities());
conference.setConnectionProperties(parcel.getConnectionProperties());
+ conference.putExtras(parcel.getExtras());
mConferenceById.put(callId, conference);
+
+ // Stash the original connection ID as it exists in the source ConnectionService.
+ // Telecom will use this to avoid adding duplicates later.
+ // See comments on Connection.EXTRA_ORIGINAL_CONNECTION_ID for more information.
+ Bundle newExtras = new Bundle();
+ newExtras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
+ conference.putExtras(newExtras);
+
conference.registerCallback(new RemoteConference.Callback() {
@Override
public void onDestroyed(RemoteConference c) {
@@ -274,9 +283,13 @@ final class RemoteConnectionService {
@Override
public void setVideoProvider(String callId, IVideoProvider videoProvider,
Session.Info sessionInfo) {
+
+ String callingPackage = mOurConnectionServiceImpl.getApplicationContext()
+ .getOpPackageName();
RemoteConnection.VideoProvider remoteVideoProvider = null;
if (videoProvider != null) {
- remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider);
+ remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider,
+ callingPackage);
}
findConnectionForAction(callId, "setVideoProvider")
.setVideoProvider(remoteVideoProvider);
@@ -342,11 +355,19 @@ final class RemoteConnectionService {
@Override
public void addExistingConnection(String callId, ParcelableConnection connection,
Session.Info sessionInfo) {
- // TODO: add contents of this method
- RemoteConnection remoteConnction = new RemoteConnection(callId,
- mOutgoingConnectionServiceRpc, connection);
-
- mOurConnectionServiceImpl.addRemoteExistingConnection(remoteConnction);
+ String callingPackage = mOurConnectionServiceImpl.getApplicationContext().
+ getOpPackageName();
+ RemoteConnection remoteConnection = new RemoteConnection(callId,
+ mOutgoingConnectionServiceRpc, connection, callingPackage);
+ mConnectionById.put(callId, remoteConnection);
+ remoteConnection.registerCallback(new RemoteConnection.Callback() {
+ @Override
+ public void onDestroyed(RemoteConnection connection) {
+ mConnectionById.remove(callId);
+ maybeDisconnectAdapter();
+ }
+ });
+ mOurConnectionServiceImpl.addRemoteExistingConnection(remoteConnection);
}
@Override
@@ -429,11 +450,14 @@ final class RemoteConnectionService {
ConnectionRequest request,
boolean isIncoming) {
final String id = UUID.randomUUID().toString();
- final ConnectionRequest newRequest = new ConnectionRequest(
- request.getAccountHandle(),
- request.getAddress(),
- request.getExtras(),
- request.getVideoState());
+ final ConnectionRequest newRequest = new ConnectionRequest.Builder()
+ .setAccountHandle(request.getAccountHandle())
+ .setAddress(request.getAddress())
+ .setExtras(request.getExtras())
+ .setVideoState(request.getVideoState())
+ .setRttPipeFromInCall(request.getRttPipeFromInCall())
+ .setRttPipeToInCall(request.getRttPipeToInCall())
+ .build();
try {
if (mConnectionById.isEmpty()) {
mOutgoingConnectionServiceRpc.addConnectionServiceAdapter(mServant.getStub(),
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index ba7b6a174a32..6807ef4b0601 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -317,6 +317,23 @@ public class TelecomManager {
public static final String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
/**
+ * The number of milliseconds that Telecom should wait after disconnecting a call via the
+ * ACTION_NEW_OUTGOING_CALL broadcast, in order to wait for the app which cancelled the call
+ * to make a new one.
+ * @hide
+ */
+ public static final String EXTRA_NEW_OUTGOING_CALL_CANCEL_TIMEOUT =
+ "android.telecom.extra.NEW_OUTGOING_CALL_CANCEL_TIMEOUT";
+
+ /**
+ * A boolean extra, which when set on the {@link Intent#ACTION_CALL} intent or on the bundle
+ * passed into {@link #placeCall(Uri, Bundle)}, indicates that the call should be initiated with
+ * an RTT session open. See {@link android.telecom.Call.RttCall} for more information on RTT.
+ */
+ public static final String EXTRA_START_CALL_WITH_RTT =
+ "android.telecom.extra.START_CALL_WITH_RTT";
+
+ /**
* A boolean meta-data value indicating whether an {@link InCallService} implements an
* in-call user interface. Dialer implementations (see {@link #getDefaultDialerPackage()}) which
* would also like to replace the in-call interface should set this meta-data to {@code true} in
@@ -1517,6 +1534,10 @@ public class TelecomManager {
* otherwise.
*/
public boolean isIncomingCallPermitted(PhoneAccountHandle phoneAccountHandle) {
+ if (phoneAccountHandle == null) {
+ return false;
+ }
+
ITelecomService service = getTelecomService();
if (service != null) {
try {
diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index e54abeebb880..d8ede5c21316 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -43,6 +43,7 @@ public class VideoCallImpl extends VideoCall {
private VideoCall.Callback mCallback;
private int mVideoQuality = VideoProfile.QUALITY_UNKNOWN;
private int mVideoState = VideoProfile.STATE_AUDIO_ONLY;
+ private final String mCallingPackageName;
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
@@ -197,12 +198,13 @@ public class VideoCallImpl extends VideoCall {
private Handler mHandler;
- VideoCallImpl(IVideoProvider videoProvider) throws RemoteException {
+ VideoCallImpl(IVideoProvider videoProvider, String callingPackageName) throws RemoteException {
mVideoProvider = videoProvider;
mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
mBinder = new VideoCallListenerBinder();
mVideoProvider.addVideoCallback(mBinder);
+ mCallingPackageName = callingPackageName;
}
public void destroy() {
@@ -240,7 +242,8 @@ public class VideoCallImpl extends VideoCall {
/** {@inheritDoc} */
public void setCamera(String cameraId) {
try {
- mVideoProvider.setCamera(cameraId);
+ Log.w(this, "setCamera: cameraId=%s, calling=%s", cameraId, mCallingPackageName);
+ mVideoProvider.setCamera(cameraId, mCallingPackageName);
} catch (RemoteException e) {
}
}
diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java
index 216603cad5ee..e0e3a085315a 100644
--- a/telecomm/java/android/telecom/VideoProfile.java
+++ b/telecomm/java/android/telecom/VideoProfile.java
@@ -235,7 +235,7 @@ public class VideoProfile implements Parcelable {
StringBuilder sb = new StringBuilder();
sb.append("Audio");
- if (isAudioOnly(videoState)) {
+ if (videoState == STATE_AUDIO_ONLY) {
sb.append(" Only");
} else {
if (isTransmissionEnabled(videoState)) {
@@ -256,6 +256,9 @@ public class VideoProfile implements Parcelable {
/**
* Indicates whether the video state is audio only.
+ * <p>
+ * Note: Considers only whether either both the {@link #STATE_RX_ENABLED} or
+ * {@link #STATE_TX_ENABLED} bits are off, but not {@link #STATE_PAUSED}.
*
* @param videoState The video state.
* @return {@code True} if the video state is audio only, {@code false} otherwise.
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 8a27675e08ab..20feba78f5c9 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -46,6 +46,9 @@ oneway interface IConnectionService {
boolean isUnknown,
in Session.Info sessionInfo);
+ void createConnectionFailed(String callId, in ConnectionRequest request, boolean isIncoming,
+ in Session.Info sessionInfo);
+
void abort(String callId, in Session.Info sessionInfo);
void answerVideo(String callId, int videoState, in Session.Info sessionInfo);
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index 49f9b3b8af73..47c3e6cfc3d5 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -69,4 +69,12 @@ oneway interface IInCallAdapter {
void putExtras(String callId, in Bundle extras);
void removeExtras(String callId, in List<String> keys);
+
+ void sendRttRequest();
+
+ void respondToRttRequest(int id, boolean accept);
+
+ void stopRtt();
+
+ void setRttMode(int mode);
}
diff --git a/telecomm/java/com/android/internal/telecom/IInCallService.aidl b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
index 3e43fe22cdfb..1f92e0c42443 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
@@ -50,4 +50,6 @@ oneway interface IInCallService {
void silenceRinger();
void onConnectionEvent(String callId, String event, in Bundle extras);
+
+ void onRttUpgradeRequest(String callId, int id);
}
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 6ca0bc513463..d9465dce49d2 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -259,4 +259,9 @@ interface ITelecomService {
* @see TelecomServiceImpl#isOutgoingCallPermitted
*/
boolean isOutgoingCallPermitted(in PhoneAccountHandle phoneAccountHandle);
+
+ /**
+ * @see TelecomServiceImpl#waitOnHandler
+ */
+ void waitOnHandlers();
}
diff --git a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
index 68e5fd48e1ac..a109e90243fe 100644
--- a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
+++ b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
@@ -30,7 +30,7 @@ oneway interface IVideoProvider {
void removeVideoCallback(IBinder videoCallbackBinder);
- void setCamera(String cameraId);
+ void setCamera(String cameraId, in String mCallingPackageName);
void setPreviewSurface(in Surface surface);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 69f91331c31c..02774b319625 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -238,6 +238,12 @@ public class CarrierConfigManager {
KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array";
/**
+ * Override the device's configuration for the ImsService to use for this SIM card.
+ */
+ public static final String KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING =
+ "config_ims_package_override_string";
+
+ /**
* Override the platform's notion of a network operator being considered roaming.
* Value is string array of SIDs to be considered roaming for 3GPP2 RATs.
*/
@@ -811,7 +817,7 @@ public class CarrierConfigManager {
/**
* Defines carrier-specific actions which act upon
- * android.intent.action.CARRIER_SIGNAL_REDIRECTED, used for customization of the
+ * com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED, used for customization of the
* default carrier app
* Format: "CARRIER_ACTION_IDX, ..."
* Where {@code CARRIER_ACTION_IDX} is an integer defined in
@@ -826,7 +832,7 @@ public class CarrierConfigManager {
/**
* Defines carrier-specific actions which act upon
- * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+ * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
* and configured signal args:
* {@link com.android.internal.telephony.TelephonyIntents#EXTRA_APN_TYPE_KEY apnType},
* {@link com.android.internal.telephony.TelephonyIntents#EXTRA_ERROR_CODE_KEY errorCode}
@@ -867,11 +873,11 @@ public class CarrierConfigManager {
* @see com.android.internal.telephony.TelephonyIntents
* Example:
* <item>com.google.android.carrierAPK/.CarrierSignalReceiverA:
- * android.intent.action.CARRIER_SIGNAL_REDIRECTED,
- * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+ * com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED,
+ * com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE
* </item>
* <item>com.google.android.carrierAPK/.CarrierSignalReceiverB:
- * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+ * com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE
* </item>
* @hide
*/
@@ -886,11 +892,11 @@ public class CarrierConfigManager {
* @see com.android.internal.telephony.TelephonyIntents
* Example:
* <item>com.google.android.carrierAPK/.CarrierSignalReceiverA:
- * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
- * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+ * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
+ * com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE
* </item>
* <item>com.google.android.carrierAPK/.CarrierSignalReceiverB:
- * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+ * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
* </item>
* @hide
*/
@@ -1058,6 +1064,9 @@ public class CarrierConfigManager {
* and {@code NEW_CODE} is the new {@code ImsReasonInfo#CODE_*} which this combination of
* original code and message shall be remapped to.
*
+ * Note: If {@code *} is specified for the original code, any ImsReasonInfo with the matching
+ * {@code MESSAGE} will be remapped to {@code NEW_CODE}.
+ *
* Example: "501|call completion elsewhere|1014"
* When the {@link ImsReasonInfo#getCode()} is {@link ImsReasonInfo#CODE_USER_TERMINATED} and
* the {@link ImsReasonInfo#getExtraMessage()} is {@code "call completion elsewhere"},
@@ -1110,6 +1119,14 @@ public class CarrierConfigManager {
public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL =
"editable_wfc_roaming_mode_bool";
+ /**
+ * Indicates whether the carrier supports 3gpp call forwarding MMI codes while roaming. If
+ * false, the user will be notified that call forwarding is not available when the MMI code
+ * fails.
+ */
+ public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL =
+ "support_3gpp_call_forwarding_while_roaming_bool";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -1215,6 +1232,7 @@ public class CarrierConfigManager {
});
sDefaults.putStringArray(KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY, null);
sDefaults.putStringArray(KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY, null);
+ sDefaults.putString(KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING, null);
sDefaults.putStringArray(KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY, null);
sDefaults.putStringArray(KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY, null);
sDefaults.putStringArray(KEY_DIAL_STRING_REPLACE_STRING_ARRAY, null);
@@ -1283,7 +1301,7 @@ public class CarrierConfigManager {
sDefaults.putStringArray(KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
new String[]{
"com.android.carrierdefaultapp/.CarrierDefaultBroadcastReceiver:" +
- "android.intent.action.CARRIER_SIGNAL_REDIRECTED"
+ "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED"
});
sDefaults.putStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY, null);
@@ -1313,6 +1331,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL, false);
sDefaults.putStringArray(KEY_FILTERED_CNAP_NAMES_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false);
+ sDefaults.putBoolean(KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL, true);
}
/**
diff --git a/telephony/java/android/telephony/ClientRequestStats.aidl b/telephony/java/android/telephony/ClientRequestStats.aidl
new file mode 100644
index 000000000000..206ee705614e
--- /dev/null
+++ b/telephony/java/android/telephony/ClientRequestStats.aidl
@@ -0,0 +1,22 @@
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony;
+
+/**
+ * @hide
+ */
+parcelable ClientRequestStats;
diff --git a/telephony/java/android/telephony/ClientRequestStats.java b/telephony/java/android/telephony/ClientRequestStats.java
new file mode 100644
index 000000000000..381c847d4db4
--- /dev/null
+++ b/telephony/java/android/telephony/ClientRequestStats.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.TelephonyHistogram;
+import android.util.SparseArray;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Parcelable class to store Client request statistics information.
+ *
+ * @hide
+ */
+public final class ClientRequestStats implements Parcelable {
+ public static final Parcelable.Creator<ClientRequestStats> CREATOR =
+ new Parcelable.Creator<ClientRequestStats>() {
+
+ public ClientRequestStats createFromParcel(Parcel in) {
+ return new ClientRequestStats(in);
+ }
+
+ public ClientRequestStats[] newArray(int size) {
+ return new ClientRequestStats[size];
+ }
+ };
+ private static final int REQUEST_HISTOGRAM_BUCKET_COUNT = 5;
+ private String mCallingPackage;
+ /* completed requests wake lock time in milli seconds */
+ private long mCompletedRequestsWakelockTime = 0;
+ private long mCompletedRequestsCount = 0;
+ private long mPendingRequestsWakelockTime = 0;
+ private long mPendingRequestsCount = 0;
+ private SparseArray<TelephonyHistogram> mRequestHistograms =
+ new SparseArray<TelephonyHistogram>();
+
+ public ClientRequestStats(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public ClientRequestStats() {
+ }
+
+ public ClientRequestStats(ClientRequestStats clientRequestStats) {
+ mCallingPackage = clientRequestStats.getCallingPackage();
+ mCompletedRequestsCount = clientRequestStats.getCompletedRequestsCount();
+ mCompletedRequestsWakelockTime = clientRequestStats.getCompletedRequestsWakelockTime();
+ mPendingRequestsCount = clientRequestStats.getPendingRequestsCount();
+ mPendingRequestsWakelockTime = clientRequestStats.getPendingRequestsWakelockTime();
+
+ List<TelephonyHistogram> list = clientRequestStats.getRequestHistograms();
+ for (TelephonyHistogram entry : list) {
+ mRequestHistograms.put(entry.getId(), entry);
+ }
+ }
+
+ public String getCallingPackage() {
+ return mCallingPackage;
+ }
+
+ public void setCallingPackage(String mCallingPackage) {
+ this.mCallingPackage = mCallingPackage;
+ }
+
+ public long getCompletedRequestsWakelockTime() {
+ return mCompletedRequestsWakelockTime;
+ }
+
+ public void addCompletedWakelockTime(long completedRequestsWakelockTime) {
+ this.mCompletedRequestsWakelockTime += completedRequestsWakelockTime;
+ }
+
+ public long getPendingRequestsWakelockTime() {
+ return mPendingRequestsWakelockTime;
+ }
+
+ public void setPendingRequestsWakelockTime(long pendingRequestsWakelockTime) {
+ this.mPendingRequestsWakelockTime = pendingRequestsWakelockTime;
+ }
+
+ public long getCompletedRequestsCount() {
+ return mCompletedRequestsCount;
+ }
+
+ public void incrementCompletedRequestsCount() {
+ this.mCompletedRequestsCount++;
+ }
+
+ public long getPendingRequestsCount() {
+ return mPendingRequestsCount;
+ }
+
+ public void setPendingRequestsCount(long pendingRequestsCount) {
+ this.mPendingRequestsCount = pendingRequestsCount;
+ }
+
+ public List<TelephonyHistogram> getRequestHistograms() {
+ List<TelephonyHistogram> list;
+ synchronized (mRequestHistograms) {
+ list = new ArrayList<>(mRequestHistograms.size());
+ for (int i = 0; i < mRequestHistograms.size(); i++) {
+ TelephonyHistogram entry = new TelephonyHistogram(mRequestHistograms.valueAt(i));
+ list.add(entry);
+ }
+ }
+ return list;
+ }
+
+ public void updateRequestHistograms(int requestId, int time) {
+ synchronized (mRequestHistograms) {
+ TelephonyHistogram entry = mRequestHistograms.get(requestId);
+ if (entry == null) {
+ entry = new TelephonyHistogram(TelephonyHistogram.TELEPHONY_CATEGORY_RIL,
+ requestId, REQUEST_HISTOGRAM_BUCKET_COUNT);
+ mRequestHistograms.put(requestId, entry);
+ }
+ entry.addTimeTaken(time);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "ClientRequestStats{" +
+ "mCallingPackage='" + mCallingPackage + '\'' +
+ ", mCompletedRequestsWakelockTime=" + mCompletedRequestsWakelockTime +
+ ", mCompletedRequestsCount=" + mCompletedRequestsCount +
+ ", mPendingRequestsWakelockTime=" + mPendingRequestsWakelockTime +
+ ", mPendingRequestsCount=" + mPendingRequestsCount +
+ '}';
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public void readFromParcel(Parcel in) {
+ mCallingPackage = in.readString();
+ mCompletedRequestsWakelockTime = in.readLong();
+ mCompletedRequestsCount = in.readLong();
+ mPendingRequestsWakelockTime = in.readLong();
+ mPendingRequestsCount = in.readLong();
+ ArrayList<TelephonyHistogram> requestHistograms = new ArrayList<TelephonyHistogram>();
+ in.readTypedList(requestHistograms, TelephonyHistogram.CREATOR);
+ for (TelephonyHistogram h : requestHistograms) {
+ mRequestHistograms.put(h.getId(), h);
+ }
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mCallingPackage);
+ dest.writeLong(mCompletedRequestsWakelockTime);
+ dest.writeLong(mCompletedRequestsCount);
+ dest.writeLong(mPendingRequestsWakelockTime);
+ dest.writeLong(mPendingRequestsCount);
+ dest.writeTypedList(getRequestHistograms());
+ }
+}
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index 811c99602599..6a081d0fe64d 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -240,23 +240,19 @@ public class DisconnectCause {
*/
public static final int IMEI_NOT_ACCEPTED = 57;
+ /**
+ * A call over WIFI was disconnected because the WIFI signal was lost or became too degraded to
+ * continue the call.
+ */
+ public static final int WIFI_LOST = 59;
+
//*********************************************************************************************
// When adding a disconnect type:
- // 1) Please assign the new type the next id value below.
- // 2) Increment the next id value below to a new value.
- // 3) Update MAXIMUM_VALID_VALUE to the new disconnect type.
- // 4) Update toString() with the newly added disconnect type.
- // 5) Update android.telecom.DisconnectCauseUtil with any mappings to a telecom.DisconnectCause.
+ // 1) Update toString() with the newly added disconnect type.
+ // 2) Update android.telecom.DisconnectCauseUtil with any mappings to a telecom.DisconnectCause.
//
- // NextId: 58
//*********************************************************************************************
- /** Smallest valid value for call disconnect codes. */
- public static final int MINIMUM_VALID_VALUE = NOT_DISCONNECTED;
-
- /** Largest valid value for call disconnect codes. */
- public static final int MAXIMUM_VALID_VALUE = IMEI_NOT_ACCEPTED;
-
/** Private constructor to avoid class instantiation. */
private DisconnectCause() {
// Do nothing.
@@ -379,6 +375,8 @@ public class DisconnectCause {
return "DIALED_ON_WRONG_SLOT";
case IMEI_NOT_ACCEPTED:
return "IMEI_NOT_ACCEPTED";
+ case WIFI_LOST:
+ return "WIFI_LOST";
default:
return "INVALID: " + cause;
}
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 152b8685027e..38cffae96132 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1139,6 +1139,8 @@ public class PhoneNumberUtils
private static final String KOREA_ISO_COUNTRY_CODE = "KR";
+ private static final String JAPAN_ISO_COUNTRY_CODE = "JP";
+
/**
* Breaks the given number down and formats it according to the rules
* for the country the number is from.
@@ -1459,15 +1461,25 @@ public class PhoneNumberUtils
String result = null;
try {
PhoneNumber pn = util.parseAndKeepRawInput(phoneNumber, defaultCountryIso);
- /**
- * Need to reformat any local Korean phone numbers (when the user is in Korea) with
- * country code to corresponding national format which would replace the leading
- * +82 with 0.
- */
- if (KOREA_ISO_COUNTRY_CODE.equals(defaultCountryIso) &&
+
+ if (KOREA_ISO_COUNTRY_CODE.equalsIgnoreCase(defaultCountryIso) &&
(pn.getCountryCode() == util.getCountryCodeForRegion(KOREA_ISO_COUNTRY_CODE)) &&
(pn.getCountryCodeSource() ==
PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN)) {
+ /**
+ * Need to reformat any local Korean phone numbers (when the user is in Korea) with
+ * country code to corresponding national format which would replace the leading
+ * +82 with 0.
+ */
+ result = util.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
+ } else if (JAPAN_ISO_COUNTRY_CODE.equalsIgnoreCase(defaultCountryIso) &&
+ pn.getCountryCode() == util.getCountryCodeForRegion(JAPAN_ISO_COUNTRY_CODE) &&
+ (pn.getCountryCodeSource() ==
+ PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN)) {
+ /**
+ * Need to reformat Japanese phone numbers (when user is in Japan) with the national
+ * dialing format.
+ */
result = util.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
} else {
result = util.formatInOriginalFormat(pn, defaultCountryIso);
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 32f487bb5dbe..afff6d548e86 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -20,17 +20,9 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.telephony.SubscriptionManager;
-import android.telephony.CellLocation;
-import android.telephony.CellInfo;
-import android.telephony.VoLteServiceState;
-import android.telephony.Rlog;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-import android.telephony.PreciseCallState;
-import android.telephony.PreciseDataConnectionState;
import com.android.internal.telephony.IPhoneStateListener;
+
import java.util.List;
import java.lang.ref.WeakReference;
@@ -216,7 +208,9 @@ public class PhoneStateListener {
*
* @see #onOemHookRawEvent
* @hide
+ * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
*/
+ @Deprecated
public static final int LISTEN_OEM_HOOK_RAW_EVENT = 0x00008000;
/**
@@ -228,6 +222,38 @@ public class PhoneStateListener {
*/
public static final int LISTEN_CARRIER_NETWORK_CHANGE = 0x00010000;
+ /**
+ * Listen for changes to the sim voice activation state
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
+ * {@more}
+ * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates voice service has been
+ * fully activated
+ *
+ * @see #onVoiceActivationStateChanged
+ * @hide
+ */
+ public static final int LISTEN_VOICE_ACTIVATION_STATE = 0x00020000;
+
+ /**
+ * Listen for changes to the sim data activation state
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
+ * {@more}
+ * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates data service has been
+ * fully activated
+ *
+ * @see #onDataActivationStateChanged
+ * @hide
+ */
+ public static final int LISTEN_DATA_ACTIVATION_STATE = 0x00040000;
+
/*
* Subscription used to listen to the phone state changes
* @hide
@@ -327,6 +353,12 @@ public class PhoneStateListener {
case LISTEN_VOLTE_STATE:
PhoneStateListener.this.onVoLteServiceStateChanged((VoLteServiceState)msg.obj);
break;
+ case LISTEN_VOICE_ACTIVATION_STATE:
+ PhoneStateListener.this.onVoiceActivationStateChanged((int)msg.obj);
+ break;
+ case LISTEN_DATA_ACTIVATION_STATE:
+ PhoneStateListener.this.onDataActivationStateChanged((int)msg.obj);
+ break;
case LISTEN_OEM_HOOK_RAW_EVENT:
PhoneStateListener.this.onOemHookRawEvent((byte[])msg.obj);
break;
@@ -506,6 +538,24 @@ public class PhoneStateListener {
}
/**
+ * Callback invoked when the SIM voice activation state has changed
+ * @param state is the current SIM voice activation state
+ * @hide
+ */
+ public void onVoiceActivationStateChanged(int state) {
+
+ }
+
+ /**
+ * Callback invoked when the SIM data activation state has changed
+ * @param state is the current SIM data activation state
+ * @hide
+ */
+ public void onDataActivationStateChanged(int state) {
+
+ }
+
+ /**
* Callback invoked when OEM hook raw event is received. Requires
* the READ_PRIVILEGED_PHONE_STATE permission.
* @param rawData is the byte array of the OEM hook raw data.
@@ -619,6 +669,14 @@ public class PhoneStateListener {
send(LISTEN_VOLTE_STATE, 0, 0, lteState);
}
+ public void onVoiceActivationStateChanged(int activationState) {
+ send(LISTEN_VOICE_ACTIVATION_STATE, 0, 0, activationState);
+ }
+
+ public void onDataActivationStateChanged(int activationState) {
+ send(LISTEN_DATA_ACTIVATION_STATE, 0, 0, activationState);
+ }
+
public void onOemHookRawEvent(byte[] rawData) {
send(LISTEN_OEM_HOOK_RAW_EVENT, 0, 0, rawData);
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 307dc1a6e74f..8479f88a8217 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.SdkConstant;
@@ -38,9 +39,13 @@ import android.os.SystemProperties;
import android.service.carrier.CarrierIdentifier;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
+import android.telephony.ClientRequestStats;
import android.telephony.TelephonyHistogram;
+import android.telephony.ims.feature.ImsFeature;
import android.util.Log;
+import com.android.ims.internal.IImsServiceController;
+import com.android.ims.internal.IImsServiceFeatureListener;
import com.android.internal.telecom.ITelecomService;
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.IPhoneSubInfo;
@@ -53,6 +58,8 @@ import com.android.internal.telephony.TelephonyProperties;
import java.io.FileInputStream;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -2719,6 +2726,148 @@ public class TelephonyManager {
}
/**
+ * Initial SIM activation state, unknown. Not set by any carrier apps.
+ * @hide
+ */
+ public static final int SIM_ACTIVATION_STATE_UNKNOWN = 0;
+
+ /**
+ * indicate SIM is under activation procedure now.
+ * intermediate state followed by another state update with activation procedure result:
+ * @see #SIM_ACTIVATION_STATE_ACTIVATED
+ * @see #SIM_ACTIVATION_STATE_DEACTIVATED
+ * @see #SIM_ACTIVATION_STATE_RESTRICTED
+ * @hide
+ */
+ public static final int SIM_ACTIVATION_STATE_ACTIVATING = 1;
+
+ /**
+ * Indicate SIM has been successfully activated with full service
+ * @hide
+ */
+ public static final int SIM_ACTIVATION_STATE_ACTIVATED = 2;
+
+ /**
+ * Indicate SIM has been deactivated by the carrier so that service is not available
+ * and requires activation service to enable services.
+ * Carrier apps could be signalled to set activation state to deactivated if detected
+ * deactivated sim state and set it back to activated after successfully run activation service.
+ * @hide
+ */
+ public static final int SIM_ACTIVATION_STATE_DEACTIVATED = 3;
+
+ /**
+ * Restricted state indicate SIM has been activated but service are restricted.
+ * note this is currently available for data activation state. For example out of byte sim.
+ * @hide
+ */
+ public static final int SIM_ACTIVATION_STATE_RESTRICTED = 4;
+
+ /**
+ * Sets the voice activation state for the given subscriber.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * @param subId The subscription id.
+ * @param activationState The voice activation state of the given subscriber.
+ * @see #SIM_ACTIVATION_STATE_UNKNOWN
+ * @see #SIM_ACTIVATION_STATE_ACTIVATING
+ * @see #SIM_ACTIVATION_STATE_ACTIVATED
+ * @see #SIM_ACTIVATION_STATE_DEACTIVATED
+ * @hide
+ */
+ public void setVoiceActivationState(int subId, int activationState) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null)
+ telephony.setVoiceActivationState(subId, activationState);
+ } catch (RemoteException ex) {
+ } catch (NullPointerException ex) {
+ }
+ }
+
+ /**
+ * Sets the data activation state for the given subscriber.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+ * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * @param subId The subscription id.
+ * @param activationState The data activation state of the given subscriber.
+ * @see #SIM_ACTIVATION_STATE_UNKNOWN
+ * @see #SIM_ACTIVATION_STATE_ACTIVATING
+ * @see #SIM_ACTIVATION_STATE_ACTIVATED
+ * @see #SIM_ACTIVATION_STATE_DEACTIVATED
+ * @see #SIM_ACTIVATION_STATE_RESTRICTED
+ * @hide
+ */
+ public void setDataActivationState(int subId, int activationState) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null)
+ telephony.setDataActivationState(subId, activationState);
+ } catch (RemoteException ex) {
+ } catch (NullPointerException ex) {
+ }
+ }
+
+ /**
+ * Returns the voice activation state for the given subscriber.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE}
+ *
+ * @param subId The subscription id.
+ *
+ * @return voiceActivationState for the given subscriber
+ * @see #SIM_ACTIVATION_STATE_UNKNOWN
+ * @see #SIM_ACTIVATION_STATE_ACTIVATING
+ * @see #SIM_ACTIVATION_STATE_ACTIVATED
+ * @see #SIM_ACTIVATION_STATE_DEACTIVATED
+ * @hide
+ */
+ public int getVoiceActivationState(int subId) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null)
+ return telephony.getVoiceActivationState(subId, getOpPackageName());
+ } catch (RemoteException ex) {
+ } catch (NullPointerException ex) {
+ }
+ return SIM_ACTIVATION_STATE_UNKNOWN;
+ }
+
+ /**
+ * Returns the data activation state for the given subscriber.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE}
+ *
+ * @param subId The subscription id.
+ *
+ * @return dataActivationState for the given subscriber
+ * @see #SIM_ACTIVATION_STATE_UNKNOWN
+ * @see #SIM_ACTIVATION_STATE_ACTIVATING
+ * @see #SIM_ACTIVATION_STATE_ACTIVATED
+ * @see #SIM_ACTIVATION_STATE_DEACTIVATED
+ * @see #SIM_ACTIVATION_STATE_RESTRICTED
+ * @hide
+ */
+ public int getDataActivationState(int subId) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null)
+ return telephony.getDataActivationState(subId, getOpPackageName());
+ } catch (RemoteException ex) {
+ } catch (NullPointerException ex) {
+ }
+ return SIM_ACTIVATION_STATE_UNKNOWN;
+ }
+
+ /**
* Returns the voice mail count. Return 0 if unavailable, -1 if there are unread voice messages
* but the count is unknown.
* <p>
@@ -4041,6 +4190,37 @@ public class TelephonyManager {
}
}
+ /** @hide */
+ @IntDef({ImsFeature.EMERGENCY_MMTEL, ImsFeature.MMTEL, ImsFeature.RCS})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Feature {}
+
+ /**
+ * Returns the {@link IImsServiceController} that corresponds to the given slot Id and IMS
+ * feature or {@link null} if the service is not available. If an ImsServiceController is
+ * available, the {@link IImsServiceFeatureListener} callback is registered as a listener for
+ * feature updates.
+ * @param slotId The SIM slot that we are requesting the {@link IImsServiceController} for.
+ * @param feature The IMS Feature we are requesting, corresponding to {@link ImsFeature}.
+ * @param callback Listener that will send updates to ImsManager when there are updates to
+ * ImsServiceController.
+ * @return {@link IImsServiceController} interface for the feature specified or {@link null} if
+ * it is unavailable.
+ * @hide
+ */
+ public IImsServiceController getImsServiceControllerAndListen(int slotId, @Feature int feature,
+ IImsServiceFeatureListener callback) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getImsServiceControllerAndListen(slotId, feature, callback);
+ }
+ } catch (RemoteException e) {
+ Rlog.e(TAG, "getImsServiceControllerAndListen, RemoteException: " + e.getMessage());
+ }
+ return null;
+ }
+
/**
* Set IMS registration state
*
@@ -4860,7 +5040,9 @@ public class TelephonyManager {
* 0 request was handled succesfully, but no response data
* positive value success, data length of response
* @hide
+ * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
*/
+ @Deprecated
public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
try {
ITelephony telephony = getITelephony();
@@ -5153,6 +5335,44 @@ public class TelephonyManager {
}
/**
+ * Set SIM card power state. Request is equivalent to inserting or removing the card.
+ *
+ * @param powerUp True if powering up the SIM, otherwise powering down
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ *
+ * @hide
+ **/
+ public void setSimPowerState(boolean powerUp) {
+ setSimPowerStateForSlot(getDefaultSim(), powerUp);
+ }
+
+ /**
+ * Set SIM card power state. Request is equivalent to inserting or removing the card.
+ *
+ * @param slotId SIM slot id
+ * @param powerUp True if powering up the SIM, otherwise powering down
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ *
+ * @hide
+ **/
+ public void setSimPowerStateForSlot(int slotId, boolean powerUp) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.setSimPowerStateForSlot(slotId, powerUp);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#setSimPowerStateForSlot", e);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Permission error calling ITelephony#setSimPowerStateForSlot", e);
+ }
+ }
+
+ /**
* Set baseband version for the default phone.
*
* @param version baseband version
@@ -5807,5 +6027,27 @@ public class TelephonyManager {
Log.e(TAG, "Error calling ITelephony#setPolicyDataEnabled", e);
}
}
+
+ /**
+ * Get Client request stats which will contain statistical information
+ * on each request made by client.
+ * Callers require either READ_PRIVILEGED_PHONE_STATE or
+ * READ_PHONE_STATE to retrieve the information.
+ * @param subId sub id
+ * @return List of Client Request Stats
+ * @hide
+ */
+ public List<ClientRequestStats> getClientRequestStats(int subId) {
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ return service.getClientRequestStats(getOpPackageName(), subId);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#getClientRequestStats", e);
+ }
+
+ return null;
+ }
}
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
new file mode 100644
index 000000000000..f1f683c70735
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.ims;
+
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telephony.CarrierConfigManager;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.feature.MMTelFeature;
+import android.telephony.ims.feature.RcsFeature;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsFeatureStatusCallback;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsServiceController;
+import com.android.ims.internal.IImsServiceFeatureListener;
+import com.android.ims.internal.IImsUt;
+import com.android.internal.annotations.VisibleForTesting;
+
+import static android.Manifest.permission.MODIFY_PHONE_STATE;
+import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
+
+/**
+ * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
+ * ImsService must register the service in their AndroidManifest to be detected by the framework.
+ * First, the application must declare that they use the "android.permission.BIND_IMS_SERVICE"
+ * permission. Then, the ImsService definition in the manifest must follow the following format:
+ *
+ * ...
+ * <service android:name=".EgImsService"
+ * android:permission="android.permission.BIND_IMS_SERVICE" >
+ * <!-- Apps must declare which features they support as metadata. The different categories are
+ * defined below. In this example, the RCS_FEATURE feature is supported. -->
+ * <meta-data android:name="android.telephony.ims.RCS_FEATURE" android:value="true" />
+ * <intent-filter>
+ * <action android:name="android.telephony.ims.ImsService" />
+ * </intent-filter>
+ * </service>
+ * ...
+ *
+ * The telephony framework will then bind to the ImsService you have defined in your manifest
+ * if you are either:
+ * 1) Defined as the default ImsService for the device in the device overlay using
+ * "config_ims_package".
+ * 2) Defined as a Carrier Provided ImsService in the Carrier Configuration using
+ * {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}.
+ *
+ * The features that are currently supported in an ImsService are:
+ * - RCS_FEATURE: This ImsService implements the {@link RcsFeature} class.
+ * - MMTEL_FEATURE: This ImsService implements the {@link MMTelFeature} class.
+ * - EMERGENCY_MMTEL_FEATURE: This ImsService implements the {@link MMTelFeature} class and will be
+ * available to place emergency calls at all times. This MUST be implemented by the default
+ * ImsService provided in the device overlay.
+ *
+ * @hide
+ */
+public abstract class ImsService extends ImsServiceBase {
+
+ private static final String LOG_TAG = "ImsService";
+
+ /**
+ * The intent that must be defined as an intent-filter in the AndroidManifest of the ImsService.
+ */
+ public static final String SERVICE_INTERFACE = "android.telephony.ims.ImsService";
+
+ // A map of slot Id -> Set of features corresponding to that slot.
+ private final SparseArray<SparseArray<ImsFeature>> mFeatures = new SparseArray<>();
+
+ // Implements all supported features as a flat interface.
+ protected final IBinder mImsServiceController = new IImsServiceController.Stub() {
+
+ @Override
+ public void createImsFeature(int slotId, int feature, IImsFeatureStatusCallback c)
+ throws RemoteException {
+ synchronized (mFeatures) {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createImsFeature");
+ onCreateImsFeatureInternal(slotId, feature, c);
+ }
+ }
+
+ @Override
+ public void removeImsFeature(int slotId, int feature) throws RemoteException {
+ synchronized (mFeatures) {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "removeImsFeature");
+ onRemoveImsFeatureInternal(slotId, feature);
+ }
+ }
+
+ @Override
+ public int startSession(int slotId, int featureType, PendingIntent incomingCallIntent,
+ IImsRegistrationListener listener) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "startSession");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.startSession(incomingCallIntent, listener);
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public void endSession(int slotId, int featureType, int sessionId) throws RemoteException {
+ synchronized (mFeatures) {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "endSession");
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ feature.endSession(sessionId);
+ }
+ }
+ }
+
+ @Override
+ public boolean isConnected(int slotId, int featureType, int callSessionType, int callType)
+ throws RemoteException {
+ enforceReadPhoneStatePermission("isConnected");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.isConnected(callSessionType, callType);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isOpened(int slotId, int featureType) throws RemoteException {
+ enforceReadPhoneStatePermission("isOpened");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.isOpened();
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int getFeatureStatus(int slotId, int featureType) throws RemoteException {
+ enforceReadPhoneStatePermission("getFeatureStatus");
+ int status = ImsFeature.STATE_NOT_AVAILABLE;
+ synchronized (mFeatures) {
+ SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
+ if (featureMap != null) {
+ ImsFeature feature = getImsFeatureFromType(featureMap, featureType);
+ if (feature != null) {
+ status = feature.getFeatureState();
+ }
+ }
+ }
+ return status;
+ }
+
+ @Override
+ public void addRegistrationListener(int slotId, int featureType,
+ IImsRegistrationListener listener) throws RemoteException {
+ enforceReadPhoneStatePermission("addRegistrationListener");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ feature.addRegistrationListener(listener);
+ }
+ }
+ }
+
+ @Override
+ public void removeRegistrationListener(int slotId, int featureType,
+ IImsRegistrationListener listener) throws RemoteException {
+ enforceReadPhoneStatePermission("removeRegistrationListener");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ feature.removeRegistrationListener(listener);
+ }
+ }
+ }
+
+ @Override
+ public ImsCallProfile createCallProfile(int slotId, int featureType, int sessionId,
+ int callSessionType, int callType) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createCallProfile");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.createCallProfile(sessionId, callSessionType, callType);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public IImsCallSession createCallSession(int slotId, int featureType, int sessionId,
+ ImsCallProfile profile, IImsCallSessionListener listener) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createCallSession");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.createCallSession(sessionId, profile, listener);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public IImsCallSession getPendingCallSession(int slotId, int featureType, int sessionId,
+ String callId) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getPendingCallSession");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.getPendingCallSession(sessionId, callId);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public IImsUt getUtInterface(int slotId, int featureType)
+ throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getUtInterface");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.getUtInterface();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public IImsConfig getConfigInterface(int slotId, int featureType)
+ throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getConfigInterface");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.getConfigInterface();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void turnOnIms(int slotId, int featureType) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "turnOnIms");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ feature.turnOnIms();
+ }
+ }
+ }
+
+ @Override
+ public void turnOffIms(int slotId, int featureType) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "turnOffIms");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ feature.turnOffIms();
+ }
+ }
+ }
+
+ @Override
+ public IImsEcbm getEcbmInterface(int slotId, int featureType)
+ throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getEcbmInterface");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.getEcbmInterface();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void setUiTTYMode(int slotId, int featureType, int uiTtyMode, Message onComplete)
+ throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "setUiTTYMode");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ feature.setUiTTYMode(uiTtyMode, onComplete);
+ }
+ }
+ }
+
+ @Override
+ public IImsMultiEndpoint getMultiEndpointInterface(int slotId, int featureType)
+ throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getMultiEndpointInterface");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.getMultiEndpointInterface();
+ }
+ }
+ return null;
+ }
+
+ };
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if(SERVICE_INTERFACE.equals(intent.getAction())) {
+ return mImsServiceController;
+ }
+ return null;
+ }
+
+ /**
+ * Called from the ImsResolver to create the requested ImsFeature, as defined by the slot and
+ * featureType
+ * @param slotId An integer representing which SIM slot the ImsFeature is assigned to.
+ * @param featureType An integer representing the type of ImsFeature being created. This is
+ * defined in {@link ImsFeature}.
+ */
+ // Be sure to lock on mFeatures before accessing this method
+ private void onCreateImsFeatureInternal(int slotId, int featureType,
+ IImsFeatureStatusCallback c) {
+ SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
+ if (featureMap == null) {
+ featureMap = new SparseArray<>();
+ mFeatures.put(slotId, featureMap);
+ }
+ ImsFeature f = makeImsFeature(slotId, featureType);
+ if (f != null) {
+ f.setContext(this);
+ f.setSlotId(slotId);
+ f.setImsFeatureStatusCallback(c);
+ featureMap.put(featureType, f);
+ }
+
+ }
+ /**
+ * Called from the ImsResolver to remove an existing ImsFeature, as defined by the slot and
+ * featureType.
+ * @param slotId An integer representing which SIM slot the ImsFeature is assigned to.
+ * @param featureType An integer representing the type of ImsFeature being removed. This is
+ * defined in {@link ImsFeature}.
+ */
+ // Be sure to lock on mFeatures before accessing this method
+ private void onRemoveImsFeatureInternal(int slotId, int featureType) {
+ SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
+ if (featureMap == null) {
+ return;
+ }
+
+ ImsFeature featureToRemove = getImsFeatureFromType(featureMap, featureType);
+ if (featureToRemove != null) {
+ featureMap.remove(featureType);
+ featureToRemove.notifyFeatureRemoved(slotId);
+ // Remove reference to Binder
+ featureToRemove.setImsFeatureStatusCallback(null);
+ }
+ }
+
+ // Be sure to lock on mFeatures before accessing this method
+ private MMTelFeature resolveMMTelFeature(int slotId, int featureType) {
+ SparseArray<ImsFeature> features = getImsFeatureMap(slotId);
+ MMTelFeature feature = null;
+ if (features != null) {
+ feature = resolveImsFeature(features, featureType, MMTelFeature.class);
+ }
+ return feature;
+ }
+
+ // Be sure to lock on mFeatures before accessing this method
+ private <T extends ImsFeature> T resolveImsFeature(SparseArray<ImsFeature> set, int featureType,
+ Class<T> className) {
+ ImsFeature feature = getImsFeatureFromType(set, featureType);
+ if (feature == null) {
+ return null;
+ }
+ try {
+ return className.cast(feature);
+ } catch (ClassCastException e)
+ {
+ Log.e(LOG_TAG, "Can not cast ImsFeature! Exception: " + e.getMessage());
+ }
+ return null;
+ }
+
+ @VisibleForTesting
+ // Be sure to lock on mFeatures before accessing this method
+ public SparseArray<ImsFeature> getImsFeatureMap(int slotId) {
+ return mFeatures.get(slotId);
+ }
+
+ @VisibleForTesting
+ // Be sure to lock on mFeatures before accessing this method
+ public ImsFeature getImsFeatureFromType(SparseArray<ImsFeature> set, int featureType) {
+ return set.get(featureType);
+ }
+
+ private ImsFeature makeImsFeature(int slotId, int feature) {
+ switch (feature) {
+ case ImsFeature.EMERGENCY_MMTEL: {
+ return onCreateEmergencyMMTelImsFeature(slotId);
+ }
+ case ImsFeature.MMTEL: {
+ return onCreateMMTelImsFeature(slotId);
+ }
+ case ImsFeature.RCS: {
+ return onCreateRcsFeature(slotId);
+ }
+ }
+ // Tried to create feature that is not defined.
+ return null;
+ }
+
+ /**
+ * Check for both READ_PHONE_STATE and READ_PRIVILEGED_PHONE_STATE. READ_PHONE_STATE is a
+ * public permission and READ_PRIVILEGED_PHONE_STATE is only granted to system apps.
+ */
+ private void enforceReadPhoneStatePermission(String fn) {
+ if (checkCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE)
+ != PackageManager.PERMISSION_GRANTED) {
+ enforceCallingOrSelfPermission(READ_PHONE_STATE, fn);
+ }
+ }
+
+ /**
+ * @return An implementation of MMTelFeature that will be used by the system for MMTel
+ * functionality. Must be able to handle emergency calls at any time as well.
+ */
+ public abstract MMTelFeature onCreateEmergencyMMTelImsFeature(int slotId);
+
+ /**
+ * @return An implementation of MMTelFeature that will be used by the system for MMTel
+ * functionality.
+ */
+ public abstract MMTelFeature onCreateMMTelImsFeature(int slotId);
+
+ /**
+ * @return An implementation of RcsFeature that will be used by the system for RCS.
+ */
+ public abstract RcsFeature onCreateRcsFeature(int slotId);
+}
diff --git a/telephony/java/android/telephony/ims/ImsServiceBase.java b/telephony/java/android/telephony/ims/ImsServiceBase.java
new file mode 100644
index 000000000000..0878db845347
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsServiceBase.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.ims;
+
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * Base ImsService Implementation, which is used by the ImsResolver to bind. ImsServices that do not
+ * need to provide an ImsService implementation but still wish to be managed by the ImsResolver
+ * lifecycle may implement this class directly.
+ * @hide
+ */
+@SystemApi
+public class ImsServiceBase extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/telephony/java/android/telephony/ims/ImsServiceProxy.java b/telephony/java/android/telephony/ims/ImsServiceProxy.java
new file mode 100644
index 000000000000..38ea6e6ff9a0
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsServiceProxy.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.ims;
+
+import android.app.PendingIntent;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telephony.ims.feature.IRcsFeature;
+import android.telephony.ims.feature.ImsFeature;
+import android.util.Log;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsServiceController;
+import com.android.ims.internal.IImsServiceFeatureListener;
+import com.android.ims.internal.IImsUt;
+
+/**
+ * A container of the IImsServiceController binder, which implements all of the ImsFeatures that
+ * the platform currently supports: MMTel and RCS.
+ * @hide
+ */
+
+public class ImsServiceProxy extends ImsServiceProxyCompat implements IRcsFeature {
+
+ protected String LOG_TAG = "ImsServiceProxy";
+ private final int mSupportedFeature;
+
+ // Start by assuming the proxy is available for usage.
+ private boolean mIsAvailable = true;
+ // ImsFeature Status from the ImsService. Cached.
+ private Integer mFeatureStatusCached = null;
+ private ImsServiceProxy.INotifyStatusChanged mStatusCallback;
+ private final Object mLock = new Object();
+
+ public interface INotifyStatusChanged {
+ void notifyStatusChanged();
+ }
+
+ private final IImsServiceFeatureListener mListenerBinder =
+ new IImsServiceFeatureListener.Stub() {
+
+ @Override
+ public void imsFeatureCreated(int slotId, int feature) throws RemoteException {
+ // The feature has been re-enabled. This may happen when the service crashes.
+ synchronized (mLock) {
+ if (!mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
+ Log.i(LOG_TAG, "Feature enabled on slotId: " + slotId + " for feature: " +
+ feature);
+ mIsAvailable = true;
+ }
+ }
+ }
+
+ @Override
+ public void imsFeatureRemoved(int slotId, int feature) throws RemoteException {
+ synchronized (mLock) {
+ if (mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
+ Log.i(LOG_TAG, "Feature disabled on slotId: " + slotId + " for feature: " +
+ feature);
+ mIsAvailable = false;
+ }
+ }
+ }
+
+ @Override
+ public void imsStatusChanged(int slotId, int feature, int status) throws RemoteException {
+ synchronized (mLock) {
+ Log.i(LOG_TAG, "imsStatusChanged: slot: " + slotId + " feature: " + feature +
+ " status: " + status);
+ if (mSlotId == slotId && feature == mSupportedFeature) {
+ mFeatureStatusCached = status;
+ }
+ }
+ if (mStatusCallback != null) {
+ mStatusCallback.notifyStatusChanged();
+ }
+ }
+ };
+
+ public ImsServiceProxy(int slotId, IBinder binder, int featureType) {
+ super(slotId, binder);
+ mSupportedFeature = featureType;
+ }
+
+ public ImsServiceProxy(int slotId, int featureType) {
+ super(slotId, null /*IBinder*/);
+ mSupportedFeature = featureType;
+ }
+
+ public IImsServiceFeatureListener getListener() {
+ return mListenerBinder;
+ }
+
+ public void setBinder(IBinder binder) {
+ mBinder = binder;
+ }
+
+ @Override
+ public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
+ throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).startSession(mSlotId, mSupportedFeature,
+ incomingCallIntent, listener);
+ }
+ }
+
+ @Override
+ public void endSession(int sessionId) throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ getServiceInterface(mBinder).endSession(mSlotId, mSupportedFeature, sessionId);
+ }
+ }
+
+ @Override
+ public boolean isConnected(int callServiceType, int callType)
+ throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).isConnected(mSlotId, mSupportedFeature,
+ callServiceType, callType);
+ }
+ }
+
+ @Override
+ public boolean isOpened() throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).isOpened(mSlotId, mSupportedFeature);
+ }
+ }
+
+ @Override
+ public void addRegistrationListener(IImsRegistrationListener listener)
+ throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ getServiceInterface(mBinder).addRegistrationListener(mSlotId, mSupportedFeature,
+ listener);
+ }
+ }
+
+ @Override
+ public void removeRegistrationListener(IImsRegistrationListener listener)
+ throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ getServiceInterface(mBinder).removeRegistrationListener(mSlotId, mSupportedFeature,
+ listener);
+ }
+ }
+
+ @Override
+ public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
+ throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).createCallProfile(mSlotId, mSupportedFeature,
+ sessionId, callServiceType, callType);
+ }
+ }
+
+ @Override
+ public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
+ IImsCallSessionListener listener) throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).createCallSession(mSlotId, mSupportedFeature,
+ sessionId, profile, listener);
+ }
+ }
+
+ @Override
+ public IImsCallSession getPendingCallSession(int sessionId, String callId)
+ throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getPendingCallSession(mSlotId, mSupportedFeature,
+ sessionId, callId);
+ }
+ }
+
+ @Override
+ public IImsUt getUtInterface() throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getUtInterface(mSlotId, mSupportedFeature);
+ }
+ }
+
+ @Override
+ public IImsConfig getConfigInterface() throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getConfigInterface(mSlotId, mSupportedFeature);
+ }
+ }
+
+ @Override
+ public void turnOnIms() throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ getServiceInterface(mBinder).turnOnIms(mSlotId, mSupportedFeature);
+ }
+ }
+
+ @Override
+ public void turnOffIms() throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ getServiceInterface(mBinder).turnOffIms(mSlotId, mSupportedFeature);
+ }
+ }
+
+ @Override
+ public IImsEcbm getEcbmInterface() throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getEcbmInterface(mSlotId, mSupportedFeature);
+ }
+ }
+
+ @Override
+ public void setUiTTYMode(int uiTtyMode, Message onComplete)
+ throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ getServiceInterface(mBinder).setUiTTYMode(mSlotId, mSupportedFeature, uiTtyMode,
+ onComplete);
+ }
+ }
+
+ @Override
+ public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getMultiEndpointInterface(mSlotId,
+ mSupportedFeature);
+ }
+ }
+
+ @Override
+ public int getFeatureStatus() {
+ synchronized (mLock) {
+ if (mFeatureStatusCached != null) {
+ return mFeatureStatusCached;
+ }
+ }
+ // Don't synchronize on Binder call.
+ Integer status = retrieveFeatureStatus();
+ synchronized (mLock) {
+ if (status == null) {
+ return ImsFeature.STATE_NOT_AVAILABLE;
+ }
+ // Cache only non-null value for feature status.
+ mFeatureStatusCached = status;
+ }
+ return status;
+ }
+
+ /**
+ * Internal method used to retrieve the feature status from the corresponding ImsService.
+ */
+ private Integer retrieveFeatureStatus() {
+ if (mBinder != null) {
+ try {
+ return getServiceInterface(mBinder).getFeatureStatus(mSlotId, mSupportedFeature);
+ } catch (RemoteException e) {
+ // Status check failed, don't update cache
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param c Callback that will fire when the feature status has changed.
+ */
+ public void setStatusCallback(INotifyStatusChanged c) {
+ mStatusCallback = c;
+ }
+
+ @Override
+ public boolean isBinderAlive() {
+ return mIsAvailable && getFeatureStatus() == ImsFeature.STATE_READY && mBinder != null &&
+ mBinder.isBinderAlive();
+ }
+
+ private IImsServiceController getServiceInterface(IBinder b) {
+ return IImsServiceController.Stub.asInterface(b);
+ }
+}
diff --git a/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java b/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java
new file mode 100644
index 000000000000..bbd5f0279913
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.ims;
+
+import android.app.PendingIntent;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telephony.ims.feature.IMMTelFeature;
+import android.telephony.ims.feature.ImsFeature;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsService;
+import com.android.ims.internal.IImsUt;
+
+/**
+ * Compatibility class that implements the new ImsService IMMTelFeature interface, but
+ * uses the old IImsService interface to support older devices that implement the deprecated
+ * opt/net/ims interface.
+ * @hide
+ */
+
+public class ImsServiceProxyCompat implements IMMTelFeature {
+
+ private static final int SERVICE_ID = ImsFeature.MMTEL;
+
+ protected final int mSlotId;
+ protected IBinder mBinder;
+
+ public ImsServiceProxyCompat(int slotId, IBinder binder) {
+ mSlotId = slotId;
+ mBinder = binder;
+ }
+
+ @Override
+ public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
+ throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).open(mSlotId, ImsFeature.MMTEL, incomingCallIntent,
+ listener);
+ }
+
+ @Override
+ public void endSession(int sessionId) throws RemoteException {
+ checkBinderConnection();
+ getServiceInterface(mBinder).close(sessionId);
+ }
+
+ @Override
+ public boolean isConnected(int callServiceType, int callType)
+ throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).isConnected(SERVICE_ID, callServiceType, callType);
+ }
+
+ @Override
+ public boolean isOpened() throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).isOpened(SERVICE_ID);
+ }
+
+ @Override
+ public void addRegistrationListener(IImsRegistrationListener listener)
+ throws RemoteException {
+ checkBinderConnection();
+ getServiceInterface(mBinder).addRegistrationListener(mSlotId, ImsFeature.MMTEL, listener);
+ }
+
+ @Override
+ public void removeRegistrationListener(IImsRegistrationListener listener)
+ throws RemoteException {
+ // Not Implemented in old ImsService. If the registration listener becomes invalid, the
+ // ImsService will remove.
+ }
+
+ @Override
+ public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
+ throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).createCallProfile(sessionId, callServiceType, callType);
+ }
+
+ @Override
+ public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
+ IImsCallSessionListener listener) throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).createCallSession(sessionId, profile, listener);
+ }
+
+ @Override
+ public IImsCallSession getPendingCallSession(int sessionId, String callId)
+ throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getPendingCallSession(sessionId, callId);
+ }
+
+ @Override
+ public IImsUt getUtInterface() throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getUtInterface(SERVICE_ID);
+ }
+
+ @Override
+ public IImsConfig getConfigInterface() throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getConfigInterface(mSlotId);
+ }
+
+ @Override
+ public void turnOnIms() throws RemoteException {
+ checkBinderConnection();
+ getServiceInterface(mBinder).turnOnIms(mSlotId);
+ }
+
+ @Override
+ public void turnOffIms() throws RemoteException {
+ checkBinderConnection();
+ getServiceInterface(mBinder).turnOffIms(mSlotId);
+ }
+
+ @Override
+ public IImsEcbm getEcbmInterface() throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getEcbmInterface(SERVICE_ID);
+ }
+
+ @Override
+ public void setUiTTYMode(int uiTtyMode, Message onComplete)
+ throws RemoteException {
+ checkBinderConnection();
+ getServiceInterface(mBinder).setUiTTYMode(SERVICE_ID, uiTtyMode, onComplete);
+ }
+
+ @Override
+ public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getMultiEndpointInterface(SERVICE_ID);
+ }
+
+ /**
+ * Base implementation, always returns READY for compatibility with old ImsService.
+ */
+ public int getFeatureStatus() {
+ return ImsFeature.STATE_READY;
+ }
+
+ /**
+ * @return false if the binder connection is no longer alive.
+ */
+ public boolean isBinderAlive() {
+ return mBinder != null && mBinder.isBinderAlive();
+ }
+
+ private IImsService getServiceInterface(IBinder b) {
+ return IImsService.Stub.asInterface(b);
+ }
+
+ protected void checkBinderConnection() throws RemoteException {
+ if (!isBinderAlive()) {
+ throw new RemoteException("ImsServiceProxy is not available for that feature.");
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/ims/feature/IMMTelFeature.java b/telephony/java/android/telephony/ims/feature/IMMTelFeature.java
new file mode 100644
index 000000000000..d65e27ebbb51
--- /dev/null
+++ b/telephony/java/android/telephony/ims/feature/IMMTelFeature.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.ims.feature;
+
+import android.app.PendingIntent;
+import android.os.Message;
+import android.os.RemoteException;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsUt;
+
+/**
+ * MMTel interface for an ImsService. When updating this interface, ensure that base implementations
+ * of your changes are also present in MMTelFeature for compatibility with older versions of the
+ * MMTel feature.
+ * @hide
+ */
+
+public interface IMMTelFeature {
+
+ /**
+ * Notifies the MMTel feature that you would like to start a session. This should always be
+ * done before making/receiving IMS calls. The IMS service will register the device to the
+ * operator's network with the credentials (from ISIM) periodically in order to receive calls
+ * from the operator's network. When the IMS service receives a new call, it will send out an
+ * intent with the provided action string. The intent contains a call ID extra
+ * {@link IImsCallSession#getCallId} and it can be used to take a call.
+ *
+ * @param incomingCallIntent When an incoming call is received, the IMS service will call
+ * {@link PendingIntent#send} to send back the intent to the caller with
+ * {@link #INCOMING_CALL_RESULT_CODE} as the result code and the intent to fill in the call ID;
+ * It cannot be null.
+ * @param listener To listen to IMS registration events; It cannot be null
+ * @return an integer (greater than 0) representing the session id associated with the session
+ * that has been started.
+ */
+ int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
+ throws RemoteException;
+
+ /**
+ * End a previously started session using the associated sessionId.
+ * @param sessionId an integer (greater than 0) representing the ongoing session. See
+ * {@link #startSession}.
+ */
+ void endSession(int sessionId) throws RemoteException;
+
+ /**
+ * Checks if the IMS service has successfully registered to the IMS network with the specified
+ * service & call type.
+ *
+ * @param callServiceType a service type that is specified in {@link ImsCallProfile}
+ * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
+ * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
+ * @param callType a call type that is specified in {@link ImsCallProfile}
+ * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
+ * {@link ImsCallProfile#CALL_TYPE_VOICE}
+ * {@link ImsCallProfile#CALL_TYPE_VT}
+ * {@link ImsCallProfile#CALL_TYPE_VS}
+ * @return true if the specified service id is connected to the IMS network; false otherwise
+ * @throws RemoteException
+ */
+ boolean isConnected(int callServiceType, int callType) throws RemoteException;
+
+ /**
+ * Checks if the specified IMS service is opened.
+ *
+ * @return true if the specified service id is opened; false otherwise
+ */
+ boolean isOpened() throws RemoteException;
+
+ /**
+ * Add a new registration listener for the client associated with the session Id.
+ * @param listener An implementation of IImsRegistrationListener.
+ */
+ void addRegistrationListener(IImsRegistrationListener listener)
+ throws RemoteException;
+
+ /**
+ * Remove a previously registered listener using {@link #addRegistrationListener} for the client
+ * associated with the session Id.
+ * @param listener A previously registered IImsRegistrationListener
+ */
+ void removeRegistrationListener(IImsRegistrationListener listener)
+ throws RemoteException;
+
+ /**
+ * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
+ *
+ * @param sessionId a session id which is obtained from {@link #startSession}
+ * @param callServiceType a service type that is specified in {@link ImsCallProfile}
+ * {@link ImsCallProfile#SERVICE_TYPE_NONE}
+ * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
+ * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
+ * @param callType a call type that is specified in {@link ImsCallProfile}
+ * {@link ImsCallProfile#CALL_TYPE_VOICE}
+ * {@link ImsCallProfile#CALL_TYPE_VT}
+ * {@link ImsCallProfile#CALL_TYPE_VT_TX}
+ * {@link ImsCallProfile#CALL_TYPE_VT_RX}
+ * {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
+ * {@link ImsCallProfile#CALL_TYPE_VS}
+ * {@link ImsCallProfile#CALL_TYPE_VS_TX}
+ * {@link ImsCallProfile#CALL_TYPE_VS_RX}
+ * @return a {@link ImsCallProfile} object
+ */
+ ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
+ throws RemoteException;
+
+ /**
+ * Creates a {@link ImsCallSession} with the specified call profile.
+ * Use other methods, if applicable, instead of interacting with
+ * {@link ImsCallSession} directly.
+ *
+ * @param sessionId a session id which is obtained from {@link #startSession}
+ * @param profile a call profile to make the call
+ * @param listener An implementation of IImsCallSessionListener.
+ */
+ IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
+ IImsCallSessionListener listener) throws RemoteException;
+
+ /**
+ * Retrieves the call session associated with a pending call.
+ *
+ * @param sessionId a session id which is obtained from {@link #startSession}
+ * @param callId a call id to make the call
+ */
+ IImsCallSession getPendingCallSession(int sessionId, String callId) throws RemoteException;
+
+ /**
+ * @return The Ut interface for the supplementary service configuration.
+ */
+ IImsUt getUtInterface() throws RemoteException;
+
+ /**
+ * @return The config interface for IMS Configuration
+ */
+ IImsConfig getConfigInterface() throws RemoteException;
+
+ /**
+ * Signal the MMTelFeature to turn on IMS when it has been turned off using {@link #turnOffIms}
+ * @param sessionId a session id which is obtained from {@link #startSession}
+ */
+ void turnOnIms() throws RemoteException;
+
+ /**
+ * Signal the MMTelFeature to turn off IMS when it has been turned on using {@link #turnOnIms}
+ * @param sessionId a session id which is obtained from {@link #startSession}
+ */
+ void turnOffIms() throws RemoteException;
+
+ /**
+ * @return The Emergency call-back mode interface for emergency VoLTE calls that support it.
+ */
+ IImsEcbm getEcbmInterface() throws RemoteException;
+
+ /**
+ * Sets the current UI TTY mode for the MMTelFeature.
+ * @param uiTtyMode An integer containing the new UI TTY Mode.
+ * @param onComplete A {@link Message} to be used when the mode has been set.
+ * @throws RemoteException
+ */
+ void setUiTTYMode(int uiTtyMode, Message onComplete) throws RemoteException;
+
+ /**
+ * @return MultiEndpoint interface for DEP notifications
+ */
+ IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException;
+}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/telephony/java/android/telephony/ims/feature/IRcsFeature.java
new file mode 100644
index 000000000000..e28e1b38dfcd
--- /dev/null
+++ b/telephony/java/android/telephony/ims/feature/IRcsFeature.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.ims.feature;
+
+/**
+ * Feature interface that provides access to RCS APIs. Currently empty until RCS support is added
+ * in the framework.
+ * @hide
+ */
+
+public interface IRcsFeature {
+}
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
new file mode 100644
index 000000000000..988dd588ecad
--- /dev/null
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.ims.feature;
+
+import android.annotation.IntDef;
+import android.content.Context;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
+
+import com.android.ims.internal.IImsFeatureStatusCallback;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base class for all IMS features that are supported by the framework.
+ * @hide
+ */
+public abstract class ImsFeature {
+
+ private static final String LOG_TAG = "ImsFeature";
+
+ /**
+ * Action to broadcast when ImsService is up.
+ * Internal use only.
+ * Only defined here separately compatibility purposes with the old ImsService.
+ * @hide
+ */
+ public static final String ACTION_IMS_SERVICE_UP =
+ "com.android.ims.IMS_SERVICE_UP";
+
+ /**
+ * Action to broadcast when ImsService is down.
+ * Internal use only.
+ * Only defined here separately for compatibility purposes with the old ImsService.
+ * @hide
+ */
+ public static final String ACTION_IMS_SERVICE_DOWN =
+ "com.android.ims.IMS_SERVICE_DOWN";
+
+ /**
+ * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
+ * A long value; the phone ID corresponding to the IMS service coming up or down.
+ * Only defined here separately for compatibility purposes with the old ImsService.
+ * @hide
+ */
+ public static final String EXTRA_PHONE_ID = "android:phone_id";
+
+ // Invalid feature value
+ public static final int INVALID = -1;
+ // ImsFeatures that are defined in the Manifests. Ensure that these values match the previously
+ // defined values in ImsServiceClass for compatibility purposes.
+ public static final int EMERGENCY_MMTEL = 0;
+ public static final int MMTEL = 1;
+ public static final int RCS = 2;
+ // Total number of features defined
+ public static final int MAX = 3;
+
+ // Integer values defining the state of the ImsFeature at any time.
+ @IntDef(flag = true,
+ value = {
+ STATE_NOT_AVAILABLE,
+ STATE_INITIALIZING,
+ STATE_READY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ImsState {}
+ public static final int STATE_NOT_AVAILABLE = 0;
+ public static final int STATE_INITIALIZING = 1;
+ public static final int STATE_READY = 2;
+
+ private List<INotifyFeatureRemoved> mRemovedListeners = new ArrayList<>();
+ private IImsFeatureStatusCallback mStatusCallback;
+ private @ImsState int mState = STATE_NOT_AVAILABLE;
+ private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+ private Context mContext;
+
+ public interface INotifyFeatureRemoved {
+ void onFeatureRemoved(int slotId);
+ }
+
+ public void setContext(Context context) {
+ mContext = context;
+ }
+
+ public void setSlotId(int slotId) {
+ mSlotId = slotId;
+ }
+
+ public void addFeatureRemovedListener(INotifyFeatureRemoved listener) {
+ synchronized (mRemovedListeners) {
+ mRemovedListeners.add(listener);
+ }
+ }
+
+ public void removeFeatureRemovedListener(INotifyFeatureRemoved listener) {
+ synchronized (mRemovedListeners) {
+ mRemovedListeners.remove(listener);
+ }
+ }
+
+ // Not final for testing.
+ public void notifyFeatureRemoved(int slotId) {
+ synchronized (mRemovedListeners) {
+ mRemovedListeners.forEach(l -> l.onFeatureRemoved(slotId));
+ onFeatureRemoved();
+ }
+ }
+
+ public int getFeatureState() {
+ return mState;
+ }
+
+ protected final void setFeatureState(@ImsState int state) {
+ if (mState != state) {
+ mState = state;
+ notifyFeatureState(state);
+ }
+ }
+
+ // Not final for testing.
+ public void setImsFeatureStatusCallback(IImsFeatureStatusCallback c) {
+ mStatusCallback = c;
+ // If we have just connected, send queued status.
+ notifyFeatureState(mState);
+ }
+
+ /**
+ * Internal method called by ImsFeature when setFeatureState has changed.
+ * @param state
+ */
+ private void notifyFeatureState(@ImsState int state) {
+ if (mStatusCallback != null) {
+ try {
+ Log.i(LOG_TAG, "notifying ImsFeatureState");
+ mStatusCallback.notifyImsFeatureStatus(state);
+ } catch (RemoteException e) {
+ mStatusCallback = null;
+ Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage());
+ }
+ }
+ sendImsServiceIntent(state);
+ }
+
+ /**
+ * Provide backwards compatibility using deprecated service UP/DOWN intents.
+ */
+ private void sendImsServiceIntent(@ImsState int state) {
+ if(mContext == null || mSlotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ return;
+ }
+ Intent intent;
+ switch (state) {
+ case ImsFeature.STATE_NOT_AVAILABLE:
+ case ImsFeature.STATE_INITIALIZING:
+ intent = new Intent(ACTION_IMS_SERVICE_DOWN);
+ break;
+ case ImsFeature.STATE_READY:
+ intent = new Intent(ACTION_IMS_SERVICE_UP);
+ break;
+ default:
+ intent = new Intent(ACTION_IMS_SERVICE_DOWN);
+ }
+ intent.putExtra(EXTRA_PHONE_ID, mSlotId);
+ mContext.sendBroadcast(intent);
+ }
+
+ /**
+ * Called when the feature is being removed and must be cleaned up.
+ */
+ public abstract void onFeatureRemoved();
+}
diff --git a/telephony/java/android/telephony/ims/feature/MMTelFeature.java b/telephony/java/android/telephony/ims/feature/MMTelFeature.java
new file mode 100644
index 000000000000..a71f0bf0c7fd
--- /dev/null
+++ b/telephony/java/android/telephony/ims/feature/MMTelFeature.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.ims.feature;
+
+import android.app.PendingIntent;
+import android.os.Message;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsUt;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base implementation, which implements all methods in IMMTelFeature. Any class wishing to use
+ * MMTelFeature should extend this class and implement all methods that the service supports.
+ *
+ * @hide
+ */
+
+public class MMTelFeature extends ImsFeature implements IMMTelFeature {
+
+ @Override
+ public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener) {
+ return 0;
+ }
+
+ @Override
+ public void endSession(int sessionId) {
+ }
+
+ @Override
+ public boolean isConnected(int callSessionType, int callType) {
+ return false;
+ }
+
+ @Override
+ public boolean isOpened() {
+ return false;
+ }
+
+ @Override
+ public void addRegistrationListener(IImsRegistrationListener listener) {
+ }
+
+ @Override
+ public void removeRegistrationListener(IImsRegistrationListener listener) {
+ }
+
+ @Override
+ public ImsCallProfile createCallProfile(int sessionId, int callSessionType, int callType) {
+ return null;
+ }
+
+ @Override
+ public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
+ IImsCallSessionListener listener) {
+ return null;
+ }
+
+ @Override
+ public IImsCallSession getPendingCallSession(int sessionId, String callId) {
+ return null;
+ }
+
+ @Override
+ public IImsUt getUtInterface() {
+ return null;
+ }
+
+ @Override
+ public IImsConfig getConfigInterface() {
+ return null;
+ }
+
+ @Override
+ public void turnOnIms() {
+ }
+
+ @Override
+ public void turnOffIms() {
+ }
+
+ @Override
+ public IImsEcbm getEcbmInterface() {
+ return null;
+ }
+
+ @Override
+ public void setUiTTYMode(int uiTtyMode, Message onComplete) {
+ }
+
+ @Override
+ public IImsMultiEndpoint getMultiEndpointInterface() {
+ return null;
+ }
+
+ @Override
+ public void onFeatureRemoved() {
+
+ }
+}
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
new file mode 100644
index 000000000000..9cddc1b934db
--- /dev/null
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.ims.feature;
+
+/**
+ * Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend
+ * this class and provide implementations of the IRcsFeature methods that they support.
+ * @hide
+ */
+
+public class RcsFeature extends ImsFeature implements IRcsFeature {
+
+ public RcsFeature() {
+ super();
+ }
+
+ @Override
+ public void onFeatureRemoved() {
+
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
new file mode 100644
index 000000000000..69b8acc5b6a9
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.ims.stub;
+
+import android.os.Message;
+import android.os.RemoteException;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.ImsStreamMediaProfile;
+import com.android.ims.internal.ImsCallSession;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsVideoCallProvider;
+
+/**
+ * Base implementation of IImsCallSession, which implements stub versions of the methods in the
+ * IImsCallSession AIDL. Override the methods that your implementation of ImsCallSession supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsCallSession maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsCallSessionImplBase extends IImsCallSession.Stub {
+
+ /**
+ * Closes the object. This object is not usable after being closed.
+ */
+ @Override
+ public void close() throws RemoteException {
+
+ }
+
+ /**
+ * Gets the call ID of the session.
+ *
+ * @return the call ID
+ */
+ @Override
+ public String getCallId() throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Gets the call profile that this session is associated with
+ *
+ * @return the {@link ImsCallProfile} that this session is associated with
+ */
+ @Override
+ public ImsCallProfile getCallProfile() throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Gets the local call profile that this session is associated with
+ *
+ * @return the local {@link ImsCallProfile} that this session is associated with
+ */
+ @Override
+ public ImsCallProfile getLocalCallProfile() throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Gets the remote call profile that this session is associated with
+ *
+ * @return the remote {@link ImsCallProfile} that this session is associated with
+ */
+ @Override
+ public ImsCallProfile getRemoteCallProfile() throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Gets the value associated with the specified property of this session.
+ *
+ * @return the string value associated with the specified property
+ */
+ @Override
+ public String getProperty(String name) throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Gets the session state.
+ * The value returned must be one of the states in {@link ImsCallSession.State}.
+ *
+ * @return the session state
+ */
+ @Override
+ public int getState() throws RemoteException {
+ return ImsCallSession.State.INVALID;
+ }
+
+ /**
+ * Checks if the session is in call.
+ *
+ * @return true if the session is in call, false otherwise
+ */
+ @Override
+ public boolean isInCall() throws RemoteException {
+ return false;
+ }
+
+ /**
+ * Sets the listener to listen to the session events. An {@link ImsCallSession}
+ * can only hold one listener at a time. Subsequent calls to this method
+ * override the previous listener.
+ *
+ * @param listener to listen to the session events of this object
+ */
+ @Override
+ public void setListener(IImsCallSessionListener listener) throws RemoteException {
+ }
+
+ /**
+ * Mutes or unmutes the mic for the active call.
+ *
+ * @param muted true if the call is muted, false otherwise
+ */
+ @Override
+ public void setMute(boolean muted) throws RemoteException {
+ }
+
+ /**
+ * Initiates an IMS call with the specified target and call profile.
+ * The session listener set in {@link #setListener} is called back upon defined session events.
+ * The method is only valid to call when the session state is in
+ * {@link ImsCallSession.State#IDLE}.
+ *
+ * @param callee dialed string to make the call to
+ * @param profile call profile to make the call with the specified service type,
+ * call type and media information
+ * @see {@link ImsCallSession.Listener#callSessionStarted},
+ * {@link ImsCallSession.Listener#callSessionStartFailed}
+ */
+ @Override
+ public void start(String callee, ImsCallProfile profile) throws RemoteException {
+ }
+
+ /**
+ * Initiates an IMS call with the specified participants and call profile.
+ * The session listener set in {@link #setListener} is called back upon defined session events.
+ * The method is only valid to call when the session state is in
+ * {@link ImsCallSession.State#IDLE}.
+ *
+ * @param participants participant list to initiate an IMS conference call
+ * @param profile call profile to make the call with the specified service type,
+ * call type and media information
+ * @see {@link ImsCallSession.Listener#callSessionStarted},
+ * {@link ImsCallSession.Listener#callSessionStartFailed}
+ */
+ @Override
+ public void startConference(String[] participants, ImsCallProfile profile)
+ throws RemoteException {
+ }
+
+ /**
+ * Accepts an incoming call or session update.
+ *
+ * @param callType call type specified in {@link ImsCallProfile} to be answered
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to be answered
+ * @see {@link ImsCallSession.Listener#callSessionStarted}
+ */
+ @Override
+ public void accept(int callType, ImsStreamMediaProfile profile) throws RemoteException {
+ }
+
+ /**
+ * Rejects an incoming call or session update.
+ *
+ * @param reason reason code to reject an incoming call, defined in
+ * com.android.ims.ImsReasonInfo
+ * {@link ImsCallSession.Listener#callSessionStartFailed}
+ */
+ @Override
+ public void reject(int reason) throws RemoteException {
+ }
+
+ /**
+ * Terminates a call.
+ *
+ * @param reason reason code to terminate a call, defined in
+ * com.android.ims.ImsReasonInfo
+ *
+ * @see {@link ImsCallSession.Listener#callSessionTerminated}
+ */
+ @Override
+ public void terminate(int reason) throws RemoteException {
+ }
+
+ /**
+ * Puts a call on hold. When it succeeds, {@link ImsCallSession.Listener#callSessionHeld} is
+ * called.
+ *
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to hold the call
+ * @see {@link ImsCallSession.Listener#callSessionHeld},
+ * {@link ImsCallSession.Listener#callSessionHoldFailed}
+ */
+ @Override
+ public void hold(ImsStreamMediaProfile profile) throws RemoteException {
+ }
+
+ /**
+ * Continues a call that's on hold. When it succeeds,
+ * {@link ImsCallSession.Listener#callSessionResumed} is called.
+ *
+ * @param profile stream media profile with {@link ImsStreamMediaProfile} to resume the call
+ * @see {@link ImsCallSession.Listener#callSessionResumed},
+ * {@link ImsCallSession.Listener#callSessionResumeFailed}
+ */
+ @Override
+ public void resume(ImsStreamMediaProfile profile) throws RemoteException {
+ }
+
+ /**
+ * Merges the active & hold call. When the merge starts,
+ * {@link ImsCallSession.Listener#callSessionMergeStarted} is called.
+ * {@link ImsCallSession.Listener#callSessionMergeComplete} is called if the merge is
+ * successful, and {@link ImsCallSession.Listener#callSessionMergeFailed} is called if the merge
+ * fails.
+ *
+ * @see {@link ImsCallSession.Listener#callSessionMergeStarted},
+ * {@link ImsCallSession.Listener#callSessionMergeComplete},
+ * {@link ImsCallSession.Listener#callSessionMergeFailed}
+ */
+ @Override
+ public void merge() throws RemoteException {
+ }
+
+ /**
+ * Updates the current call's properties (ex. call mode change: video upgrade / downgrade).
+ *
+ * @param callType call type specified in {@link ImsCallProfile} to be updated
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to be updated
+ * @see {@link ImsCallSession.Listener#callSessionUpdated},
+ * {@link ImsCallSession.Listener#callSessionUpdateFailed}
+ */
+ @Override
+ public void update(int callType, ImsStreamMediaProfile profile) throws RemoteException {
+ }
+
+ /**
+ * Extends this call to the conference call with the specified recipients.
+ *
+ * @param participants participant list to be invited to the conference call after extending the
+ * call
+ * @see {@link ImsCallSession.Listener#callSessionConferenceExtended},
+ * {@link ImsCallSession.Listener#callSessionConferenceExtendFailed}
+ */
+ @Override
+ public void extendToConference(String[] participants) throws RemoteException {
+ }
+
+ /**
+ * Requests the conference server to invite an additional participants to the conference.
+ *
+ * @param participants participant list to be invited to the conference call
+ * @see {@link ImsCallSession.Listener#callSessionInviteParticipantsRequestDelivered},
+ * {@link ImsCallSession.Listener#callSessionInviteParticipantsRequestFailed}
+ */
+ @Override
+ public void inviteParticipants(String[] participants) throws RemoteException {
+ }
+
+ /**
+ * Requests the conference server to remove the specified participants from the conference.
+ *
+ * @param participants participant list to be removed from the conference call
+ * @see {@link ImsCallSession.Listener#callSessionRemoveParticipantsRequestDelivered},
+ * {@link ImsCallSession.Listener#callSessionRemoveParticipantsRequestFailed}
+ */
+ @Override
+ public void removeParticipants(String[] participants) throws RemoteException {
+ }
+
+ /**
+ * Sends a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+ * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+ * and event flash to 16. Currently, event flash is not supported.
+ *
+ * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+ */
+ @Override
+ public void sendDtmf(char c, Message result) throws RemoteException {
+ }
+
+ /**
+ * Start a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+ * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+ * and event flash to 16. Currently, event flash is not supported.
+ *
+ * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+ */
+ @Override
+ public void startDtmf(char c) throws RemoteException {
+ }
+
+ /**
+ * Stop a DTMF code.
+ */
+ @Override
+ public void stopDtmf() throws RemoteException {
+ }
+
+ /**
+ * Sends an USSD message.
+ *
+ * @param ussdMessage USSD message to send
+ */
+ @Override
+ public void sendUssd(String ussdMessage) throws RemoteException {
+ }
+
+ /**
+ * Returns a binder for the video call provider implementation contained within the IMS service
+ * process. This binder is used by the VideoCallProvider subclass in Telephony which
+ * intermediates between the propriety implementation and Telecomm/InCall.
+ */
+ @Override
+ public IImsVideoCallProvider getVideoCallProvider() throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Determines if the current session is multiparty.
+ * @return {@code True} if the session is multiparty.
+ */
+ @Override
+ public boolean isMultiparty() throws RemoteException {
+ return false;
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionListenerImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionListenerImplBase.java
new file mode 100644
index 000000000000..46f8f808a92c
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionListenerImplBase.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.ims.stub;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.ImsConferenceState;
+import com.android.ims.ImsReasonInfo;
+import com.android.ims.ImsStreamMediaProfile;
+import com.android.ims.ImsSuppServiceNotification;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+
+/**
+ * Base implementation of ImsCallSessionListenerBase, which implements stub versions of the methods
+ * in the IImsCallSessionListener AIDL. Override the methods that your implementation of
+ * ImsCallSessionListener supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsCallSessionListener maintained by other ImsServices.
+ *
+ * @hide
+ */
+public class ImsCallSessionListenerImplBase extends IImsCallSessionListener.Stub {
+ /**
+ * Notifies the result of the basic session operation (setup / terminate).
+ */
+ @Override
+ public void callSessionProgressing(IImsCallSession session, ImsStreamMediaProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionStarted(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionStartFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionTerminated(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Notifies the result of the call hold/resume operation.
+ */
+ @Override
+ public void callSessionHeld(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionHoldFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionHoldReceived(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionResumed(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionResumeFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionResumeReceived(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Notifies the result of call merge operation.
+ */
+ @Override
+ public void callSessionMergeStarted(IImsCallSession session, IImsCallSession newSession,
+ ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionMergeComplete(IImsCallSession session) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionMergeFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Notifies the result of call upgrade / downgrade or any other call
+ * updates.
+ */
+ @Override
+ public void callSessionUpdated(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionUpdateFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionUpdateReceived(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Notifies the result of conference extension.
+ */
+ @Override
+ public void callSessionConferenceExtended(IImsCallSession session, IImsCallSession newSession,
+ ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionConferenceExtendFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionConferenceExtendReceived(IImsCallSession session,
+ IImsCallSession newSession,
+ ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Notifies the result of the participant invitation / removal to/from the
+ * conference session.
+ */
+ @Override
+ public void callSessionInviteParticipantsRequestDelivered(IImsCallSession session) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionInviteParticipantsRequestFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionRemoveParticipantsRequestDelivered(IImsCallSession session) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionRemoveParticipantsRequestFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Notifies the changes of the conference info. the conference session.
+ */
+ @Override
+ public void callSessionConferenceStateUpdated(IImsCallSession session,
+ ImsConferenceState state) {
+ // no-op
+ }
+
+ /**
+ * Notifies the incoming USSD message.
+ */
+ @Override
+ public void callSessionUssdMessageReceived(IImsCallSession session, int mode,
+ String ussdMessage) {
+ // no-op
+ }
+
+ /**
+ * Notifies of handover information for this call
+ */
+ @Override
+ public void callSessionHandover(IImsCallSession session, int srcAccessTech,
+ int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionHandoverFailed(IImsCallSession session, int srcAccessTech,
+ int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Notifies the TTY mode change by remote party.
+ *
+ * @param mode one of the following: -
+ * {@link com.android.internal.telephony.Phone#TTY_MODE_OFF} -
+ * {@link com.android.internal.telephony.Phone#TTY_MODE_FULL} -
+ * {@link com.android.internal.telephony.Phone#TTY_MODE_HCO} -
+ * {@link com.android.internal.telephony.Phone#TTY_MODE_VCO}
+ */
+ @Override
+ public void callSessionTtyModeReceived(IImsCallSession session, int mode) {
+ // no-op
+ }
+
+ /**
+ * Notifies of a change to the multiparty state for this
+ * {@code ImsCallSession}.
+ *
+ * @param session The call session.
+ * @param isMultiParty {@code true} if the session became multiparty,
+ * {@code false} otherwise.
+ */
+ @Override
+ public void callSessionMultipartyStateChanged(IImsCallSession session, boolean isMultiParty) {
+ // no-op
+ }
+
+ /**
+ * Notifies the supplementary service information for the current session.
+ */
+ @Override
+ public void callSessionSuppServiceReceived(IImsCallSession session,
+ ImsSuppServiceNotification suppSrvNotification) {
+ // no-op
+ }
+}
+
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
new file mode 100644
index 000000000000..5a4db99ee0d0
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.ims.stub;
+
+import android.os.RemoteException;
+
+import com.android.ims.ImsConfig;
+import com.android.ims.ImsConfigListener;
+import com.android.ims.internal.IImsConfig;
+
+/**
+ * Base implementation of ImsConfig, which implements stub versions of the methods
+ * in the IImsConfig AIDL. Override the methods that your implementation of ImsConfig supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsConfig maintained by other ImsServices.
+ *
+ * Provides APIs to get/set the IMS service feature/capability/parameters.
+ * The config items include:
+ * 1) Items provisioned by the operator.
+ * 2) Items configured by user. Mainly service feature class.
+ *
+ * @hide
+ */
+
+public class ImsConfigImplBase extends IImsConfig.Stub {
+
+ /**
+ * Gets the value for ims service/capabilities parameters from the provisioned
+ * value storage. Synchronous blocking call.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @return value in Integer format.
+ */
+ @Override
+ public int getProvisionedValue(int item) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Gets the value for ims service/capabilities parameters from the provisioned
+ * value storage. Synchronous blocking call.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @return value in String format.
+ */
+ @Override
+ public String getProvisionedStringValue(int item) throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Sets the value for IMS service/capabilities parameters by the operator device
+ * management entity. It sets the config item value in the provisioned storage
+ * from which the master value is derived. Synchronous blocking call.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @param value in Integer format.
+ * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
+ */
+ @Override
+ public int setProvisionedValue(int item, int value) throws RemoteException {
+ return ImsConfig.OperationStatusConstants.FAILED;
+ }
+
+ /**
+ * Sets the value for IMS service/capabilities parameters by the operator device
+ * management entity. It sets the config item value in the provisioned storage
+ * from which the master value is derived. Synchronous blocking call.
+ *
+ * @param item as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @param value in String format.
+ * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
+ */
+ @Override
+ public int setProvisionedStringValue(int item, String value) throws RemoteException {
+ return ImsConfig.OperationStatusConstants.FAILED;
+ }
+
+ /**
+ * Gets the value of the specified IMS feature item for specified network type.
+ * This operation gets the feature config value from the master storage (i.e. final
+ * value). Asynchronous non-blocking call.
+ *
+ * @param feature as defined in com.android.ims.ImsConfig#FeatureConstants.
+ * @param network as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
+ * @param listener feature value returned asynchronously through listener.
+ */
+ @Override
+ public void getFeatureValue(int feature, int network, ImsConfigListener listener)
+ throws RemoteException {
+ }
+
+ /**
+ * Sets the value for IMS feature item for specified network type.
+ * This operation stores the user setting in setting db from which master db
+ * is derived.
+ *
+ * @param feature as defined in com.android.ims.ImsConfig#FeatureConstants.
+ * @param network as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
+ * @param value as defined in com.android.ims.ImsConfig#FeatureValueConstants.
+ * @param listener, provided if caller needs to be notified for set result.
+ */
+ @Override
+ public void setFeatureValue(int feature, int network, int value, ImsConfigListener listener)
+ throws RemoteException {
+ }
+
+ /**
+ * Gets the value for IMS VoLTE provisioned.
+ * This should be the same as the operator provisioned value if applies.
+ */
+ @Override
+ public boolean getVolteProvisioned() throws RemoteException {
+ return false;
+ }
+
+ /**
+ * Gets the value for IMS feature item video quality.
+ *
+ * @param listener Video quality value returned asynchronously through listener.
+ */
+ @Override
+ public void getVideoQuality(ImsConfigListener listener) throws RemoteException {
+ }
+
+ /**
+ * Sets the value for IMS feature item video quality.
+ *
+ * @param quality, defines the value of video quality.
+ * @param listener, provided if caller needs to be notified for set result.
+ */
+ @Override
+ public void setVideoQuality(int quality, ImsConfigListener listener) throws RemoteException {
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
new file mode 100644
index 000000000000..89f95ff0142d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.ims.stub;
+
+import android.os.RemoteException;
+
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsEcbmListener;
+
+/**
+ * Base implementation of ImsEcbm, which implements stub versions of the methods
+ * in the IImsEcbm AIDL. Override the methods that your implementation of ImsEcbm supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsEcbm maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsEcbmImplBase extends IImsEcbm.Stub {
+
+ /**
+ * Sets the listener.
+ */
+ @Override
+ public void setListener(IImsEcbmListener listener) throws RemoteException {
+
+ }
+
+ /**
+ * Requests Modem to come out of ECBM mode
+ */
+ @Override
+ public void exitEmergencyCallbackMode() throws RemoteException {
+
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
new file mode 100644
index 000000000000..05da9da485a9
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.ims.stub;
+
+import android.os.RemoteException;
+
+import com.android.ims.internal.IImsExternalCallStateListener;
+import com.android.ims.internal.IImsMultiEndpoint;
+
+/**
+ * Base implementation of ImsMultiEndpoint, which implements stub versions of the methods
+ * in the IImsMultiEndpoint AIDL. Override the methods that your implementation of
+ * ImsMultiEndpoint supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsMultiEndpoint maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsMultiEndpointImplBase extends IImsMultiEndpoint.Stub {
+
+ /**
+ * Sets the listener.
+ */
+ @Override
+ public void setListener(IImsExternalCallStateListener listener) throws RemoteException {
+
+ }
+
+ /**
+ * Query API to get the latest Dialog Event Package information
+ * Should be invoked only after setListener is done
+ */
+ @Override
+ public void requestImsExternalCallStateInfo() throws RemoteException {
+
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsStreamMediaSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsStreamMediaSessionImplBase.java
new file mode 100644
index 000000000000..92f1a018677d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsStreamMediaSessionImplBase.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.ims.stub;
+
+import android.os.RemoteException;
+
+import com.android.ims.internal.IImsStreamMediaSession;
+
+/**
+ * Base implementation of ImsStreamMediaSession, which implements stub versions of the methods
+ * in the IImsStreamMediaSession AIDL. Override the methods that your implementation of
+ * ImsStreamMediaSession supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsStreamMediaSession maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsStreamMediaSessionImplBase extends IImsStreamMediaSession.Stub {
+
+ @Override
+ public void close() throws RemoteException {
+
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
new file mode 100644
index 000000000000..dc74094d6f93
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.ims.stub;
+
+import android.os.Bundle;
+import android.os.RemoteException;
+
+import com.android.ims.internal.IImsUt;
+import com.android.ims.internal.IImsUtListener;
+
+/**
+ * Base implementation of ImsUt, which implements stub versions of the methods
+ * in the IImsUt AIDL. Override the methods that your implementation of ImsUt supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsUt maintained by other ImsServices.
+ *
+ * Provides the Ut interface interworking to get/set the supplementary service configuration.
+ *
+ * @hide
+ */
+
+public class ImsUtImplBase extends IImsUt.Stub {
+
+ /**
+ * Closes the object. This object is not usable after being closed.
+ */
+ @Override
+ public void close() throws RemoteException {
+
+ }
+
+ /**
+ * Retrieves the configuration of the call barring.
+ */
+ @Override
+ public int queryCallBarring(int cbType) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the configuration of the call forward.
+ */
+ @Override
+ public int queryCallForward(int condition, String number) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the configuration of the call waiting.
+ */
+ @Override
+ public int queryCallWaiting() throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the default CLIR setting.
+ */
+ @Override
+ public int queryCLIR() throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the CLIP call setting.
+ */
+ @Override
+ public int queryCLIP() throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the COLR call setting.
+ */
+ @Override
+ public int queryCOLR() throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the COLP call setting.
+ */
+ @Override
+ public int queryCOLP() throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates or retrieves the supplementary service configuration.
+ */
+ @Override
+ public int transact(Bundle ssInfo) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the call barring.
+ */
+ @Override
+ public int updateCallBarring(int cbType, int action, String[] barrList) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the call forward.
+ */
+ @Override
+ public int updateCallForward(int action, int condition, String number, int serviceClass,
+ int timeSeconds) throws RemoteException {
+ return 0;
+ }
+
+ /**
+ * Updates the configuration of the call waiting.
+ */
+ @Override
+ public int updateCallWaiting(boolean enable, int serviceClass) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the CLIR supplementary service.
+ */
+ @Override
+ public int updateCLIR(int clirMode) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the CLIP supplementary service.
+ */
+ @Override
+ public int updateCLIP(boolean enable) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the COLR supplementary service.
+ */
+ @Override
+ public int updateCOLR(int presentation) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the COLP supplementary service.
+ */
+ @Override
+ public int updateCOLP(boolean enable) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Sets the listener.
+ */
+ @Override
+ public void setListener(IImsUtListener listener) throws RemoteException {
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java
new file mode 100644
index 000000000000..b371efb68030
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.ims.stub;
+
+import android.os.Bundle;
+import android.os.RemoteException;
+
+import com.android.ims.ImsCallForwardInfo;
+import com.android.ims.ImsReasonInfo;
+import com.android.ims.ImsSsInfo;
+import com.android.ims.internal.IImsUt;
+import com.android.ims.internal.IImsUtListener;
+
+/**
+ * Base implementation of ImsUtListener, which implements stub versions of the methods
+ * in the IImsUtListener AIDL. Override the methods that your implementation of
+ * ImsUtListener supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsUtListener maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsUtListenerImplBase extends IImsUtListener.Stub {
+
+ /**
+ * Notifies the result of the supplementary service configuration udpate.
+ */
+ @Override
+ public void utConfigurationUpdated(IImsUt ut, int id) throws RemoteException {
+ }
+
+ @Override
+ public void utConfigurationUpdateFailed(IImsUt ut, int id, ImsReasonInfo error)
+ throws RemoteException {
+ }
+
+ /**
+ * Notifies the result of the supplementary service configuration query.
+ */
+ @Override
+ public void utConfigurationQueried(IImsUt ut, int id, Bundle ssInfo) throws RemoteException {
+ }
+
+ @Override
+ public void utConfigurationQueryFailed(IImsUt ut, int id, ImsReasonInfo error)
+ throws RemoteException {
+ }
+
+ /**
+ * Notifies the status of the call barring supplementary service.
+ */
+ @Override
+ public void utConfigurationCallBarringQueried(IImsUt ut, int id, ImsSsInfo[] cbInfo)
+ throws RemoteException {
+ }
+
+ /**
+ * Notifies the status of the call forwarding supplementary service.
+ */
+ @Override
+ public void utConfigurationCallForwardQueried(IImsUt ut, int id, ImsCallForwardInfo[] cfInfo)
+ throws RemoteException {
+ }
+
+ /**
+ * Notifies the status of the call waiting supplementary service.
+ */
+ @Override
+ public void utConfigurationCallWaitingQueried(IImsUt ut, int id, ImsSsInfo[] cwInfo)
+ throws RemoteException {
+ }
+}
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
new file mode 100644
index 000000000000..cd076b1a52df
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -0,0 +1,694 @@
+/*
+ * 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.ims;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.telephony.Rlog;
+
+import com.android.ims.internal.IImsConfig;
+
+/**
+ * Provides APIs to get/set the IMS service feature/capability/parameters.
+ * The config items include:
+ * 1) Items provisioned by the operator.
+ * 2) Items configured by user. Mainly service feature class.
+ *
+ * @hide
+ */
+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
+ *
+ * @hide
+ */
+ public static final String ACTION_IMS_FEATURE_CHANGED =
+ "com.android.intent.action.IMS_FEATURE_CHANGED";
+
+ /**
+ * Broadcast action: the configuration was changed
+ *
+ * @hide
+ */
+ public static final String ACTION_IMS_CONFIG_CHANGED =
+ "com.android.intent.action.IMS_CONFIG_CHANGED";
+
+ /**
+ * Extra parameter "item" of intent ACTION_IMS_FEATURE_CHANGED and ACTION_IMS_CONFIG_CHANGED.
+ * It is the value of FeatureConstants or ConfigConstants.
+ *
+ * @hide
+ */
+ public static final String EXTRA_CHANGED_ITEM = "item";
+
+ /**
+ * Extra parameter "value" of intent ACTION_IMS_FEATURE_CHANGED and ACTION_IMS_CONFIG_CHANGED.
+ * It is the new value of "item".
+ *
+ * @hide
+ */
+ public static final String EXTRA_NEW_VALUE = "value";
+
+ /**
+ * Defines IMS service/capability feature constants.
+ */
+ public static class FeatureConstants {
+ public static final int FEATURE_TYPE_UNKNOWN = -1;
+
+ /**
+ * FEATURE_TYPE_VOLTE supports features defined in 3GPP and
+ * GSMA IR.92 over LTE.
+ */
+ public static final int FEATURE_TYPE_VOICE_OVER_LTE = 0;
+
+ /**
+ * FEATURE_TYPE_LVC supports features defined in 3GPP and
+ * GSMA IR.94 over LTE.
+ */
+ public static final int FEATURE_TYPE_VIDEO_OVER_LTE = 1;
+
+ /**
+ * FEATURE_TYPE_VOICE_OVER_WIFI supports features defined in 3GPP and
+ * GSMA IR.92 over WiFi.
+ */
+ public static final int FEATURE_TYPE_VOICE_OVER_WIFI = 2;
+
+ /**
+ * FEATURE_TYPE_VIDEO_OVER_WIFI supports features defined in 3GPP and
+ * GSMA IR.94 over WiFi.
+ */
+ public static final int FEATURE_TYPE_VIDEO_OVER_WIFI = 3;
+
+ /**
+ * FEATURE_TYPE_UT supports features defined in 3GPP and
+ * GSMA IR.92 over LTE.
+ */
+ public static final int FEATURE_TYPE_UT_OVER_LTE = 4;
+
+ /**
+ * FEATURE_TYPE_UT_OVER_WIFI supports features defined in 3GPP and
+ * GSMA IR.92 over WiFi.
+ */
+ public static final int FEATURE_TYPE_UT_OVER_WIFI = 5;
+ }
+
+ /**
+ * Defines IMS service/capability parameters.
+ */
+ public static class ConfigConstants {
+
+ // Define IMS config items
+ public static final int CONFIG_START = 0;
+
+ // Define operator provisioned config items
+ public static final int PROVISIONED_CONFIG_START = CONFIG_START;
+
+ /**
+ * AMR CODEC Mode Value set, 0-7 in comma separated sequence.
+ * Value is in String format.
+ */
+ public static final int VOCODER_AMRMODESET = CONFIG_START;
+
+ /**
+ * Wide Band AMR CODEC Mode Value set,0-7 in comma separated sequence.
+ * Value is in String format.
+ */
+ public static final int VOCODER_AMRWBMODESET = 1;
+
+ /**
+ * SIP Session Timer value (seconds).
+ * Value is in Integer format.
+ */
+ public static final int SIP_SESSION_TIMER = 2;
+
+ /**
+ * Minimum SIP Session Expiration Timer in (seconds).
+ * Value is in Integer format.
+ */
+ public static final int MIN_SE = 3;
+
+ /**
+ * SIP_INVITE cancellation time out value (in milliseconds). Integer format.
+ * Value is in Integer format.
+ */
+ public static final int CANCELLATION_TIMER = 4;
+
+ /**
+ * Delay time when an iRAT transition from eHRPD/HRPD/1xRTT to LTE.
+ * Value is in Integer format.
+ */
+ public static final int TDELAY = 5;
+
+ /**
+ * Silent redial status of Enabled (True), or Disabled (False).
+ * Value is in Integer format.
+ */
+ public static final int SILENT_REDIAL_ENABLE = 6;
+
+ /**
+ * SIP T1 timer value in milliseconds. See RFC 3261 for define.
+ * Value is in Integer format.
+ */
+ public static final int SIP_T1_TIMER = 7;
+
+ /**
+ * SIP T2 timer value in milliseconds. See RFC 3261 for define.
+ * Value is in Integer format.
+ */
+ public static final int SIP_T2_TIMER = 8;
+
+ /**
+ * SIP TF timer value in milliseconds. See RFC 3261 for define.
+ * Value is in Integer format.
+ */
+ public static final int SIP_TF_TIMER = 9;
+
+ /**
+ * VoLTE status for VLT/s status of Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ */
+ public static final int VLT_SETTING_ENABLED = 10;
+
+ /**
+ * VoLTE status for LVC/s status of Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ */
+ public static final int LVC_SETTING_ENABLED = 11;
+ /**
+ * Domain Name for the device to populate the request URI for REGISTRATION.
+ * Value is in String format.
+ */
+ public static final int DOMAIN_NAME = 12;
+ /**
+ * Device Outgoing SMS based on either 3GPP or 3GPP2 standards.
+ * Value is in Integer format. 3GPP2(0), 3GPP(1)
+ */
+ public static final int SMS_FORMAT = 13;
+ /**
+ * Turns IMS ON/OFF on the device.
+ * Value is in Integer format. ON (1), OFF(0).
+ */
+ public static final int SMS_OVER_IP = 14;
+ /**
+ * Requested expiration for Published Online availability.
+ * Value is in Integer format.
+ */
+ public static final int PUBLISH_TIMER = 15;
+ /**
+ * Requested expiration for Published Offline availability.
+ * Value is in Integer format.
+ */
+ public static final int PUBLISH_TIMER_EXTENDED = 16;
+ /**
+ *
+ * Value is in Integer format.
+ */
+ public static final int CAPABILITY_DISCOVERY_ENABLED = 17;
+ /**
+ * Period of time the capability information of the contact is cached on handset.
+ * Value is in Integer format.
+ */
+ public static final int CAPABILITIES_CACHE_EXPIRATION = 18;
+ /**
+ * Peiod of time the availability information of a contact is cached on device.
+ * Value is in Integer format.
+ */
+ public static final int AVAILABILITY_CACHE_EXPIRATION = 19;
+ /**
+ * Interval between successive capabilities polling.
+ * Value is in Integer format.
+ */
+ public static final int CAPABILITIES_POLL_INTERVAL = 20;
+ /**
+ * Minimum time between two published messages from the device.
+ * Value is in Integer format.
+ */
+ public static final int SOURCE_THROTTLE_PUBLISH = 21;
+ /**
+ * The Maximum number of MDNs contained in one Request Contained List.
+ * Value is in Integer format.
+ */
+ public static final int MAX_NUMENTRIES_IN_RCL = 22;
+ /**
+ * Expiration timer for subscription of a Request Contained List, used in capability
+ * polling.
+ * Value is in Integer format.
+ */
+ public static final int CAPAB_POLL_LIST_SUB_EXP = 23;
+ /**
+ * Applies compression to LIST Subscription.
+ * Value is in Integer format. Enable (1), Disable(0).
+ */
+ public static final int GZIP_FLAG = 24;
+ /**
+ * VOLTE Status for EAB/s status of Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ */
+ public static final int EAB_SETTING_ENABLED = 25;
+ /**
+ * Wi-Fi calling roaming status.
+ * Value is in Integer format. ON (1), OFF(0).
+ */
+ public static final int VOICE_OVER_WIFI_ROAMING = 26;
+ /**
+ * Wi-Fi calling modem - WfcModeFeatureValueConstants.
+ * Value is in Integer format.
+ */
+ public static final int VOICE_OVER_WIFI_MODE = 27;
+ /**
+ * VOLTE Status for voice over wifi status of Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ */
+ public static final int VOICE_OVER_WIFI_SETTING_ENABLED = 28;
+ /**
+ * Mobile data enabled.
+ * Value is in Integer format. On (1), OFF(0).
+ */
+ public static final int MOBILE_DATA_ENABLED = 29;
+ /**
+ * VoLTE user opted in status.
+ * Value is in Integer format. Opted-in (1) Opted-out (0).
+ */
+ public static final int VOLTE_USER_OPT_IN_STATUS = 30;
+ /**
+ * Proxy for Call Session Control Function(P-CSCF) address for Local-BreakOut(LBO).
+ * Value is in String format.
+ */
+ public static final int LBO_PCSCF_ADDRESS = 31;
+ /**
+ * Keep Alive Enabled for SIP.
+ * Value is in Integer format. On(1), OFF(0).
+ */
+ public static final int KEEP_ALIVE_ENABLED = 32;
+ /**
+ * Registration retry Base Time value in seconds.
+ * Value is in Integer format.
+ */
+ public static final int REGISTRATION_RETRY_BASE_TIME_SEC = 33;
+ /**
+ * Registration retry Max Time value in seconds.
+ * Value is in Integer format.
+ */
+ public static final int REGISTRATION_RETRY_MAX_TIME_SEC = 34;
+ /**
+ * Smallest RTP port for speech codec.
+ * Value is in integer format.
+ */
+ public static final int SPEECH_START_PORT = 35;
+ /**
+ * Largest RTP port for speech code.
+ * Value is in Integer format.
+ */
+ public static final int SPEECH_END_PORT = 36;
+ /**
+ * SIP Timer A's value in milliseconds. Timer A is the INVITE request
+ * retransmit interval, for UDP only.
+ * Value is in Integer format.
+ */
+ public static final int SIP_INVITE_REQ_RETX_INTERVAL_MSEC = 37;
+ /**
+ * SIP Timer B's value in milliseconds. Timer B is the wait time for
+ * INVITE message to be acknowledged.
+ * Value is in Integer format.
+ */
+ public static final int SIP_INVITE_RSP_WAIT_TIME_MSEC = 38;
+ /**
+ * SIP Timer D's value in milliseconds. Timer D is the wait time for
+ * response retransmits of the invite client transactions.
+ * Value is in Integer format.
+ */
+ public static final int SIP_INVITE_RSP_RETX_WAIT_TIME_MSEC = 39;
+ /**
+ * SIP Timer E's value in milliseconds. Timer E is the value Non-INVITE
+ * request retransmit interval, for UDP only.
+ * Value is in Integer format.
+ */
+ public static final int SIP_NON_INVITE_REQ_RETX_INTERVAL_MSEC = 40;
+ /**
+ * SIP Timer F's value in milliseconds. Timer F is the Non-INVITE transaction
+ * timeout timer.
+ * Value is in Integer format.
+ */
+ public static final int SIP_NON_INVITE_TXN_TIMEOUT_TIMER_MSEC = 41;
+ /**
+ * SIP Timer G's value in milliseconds. Timer G is the value of INVITE response
+ * retransmit interval.
+ * Value is in Integer format.
+ */
+ public static final int SIP_INVITE_RSP_RETX_INTERVAL_MSEC = 42;
+ /**
+ * SIP Timer H's value in milliseconds. Timer H is the value of wait time for
+ * ACK receipt.
+ * Value is in Integer format.
+ */
+ public static final int SIP_ACK_RECEIPT_WAIT_TIME_MSEC = 43;
+ /**
+ * SIP Timer I's value in milliseconds. Timer I is the value of wait time for
+ * ACK retransmits.
+ * Value is in Integer format.
+ */
+ public static final int SIP_ACK_RETX_WAIT_TIME_MSEC = 44;
+ /**
+ * SIP Timer J's value in milliseconds. Timer J is the value of wait time for
+ * non-invite request retransmission.
+ * Value is in Integer format.
+ */
+ public static final int SIP_NON_INVITE_REQ_RETX_WAIT_TIME_MSEC = 45;
+ /**
+ * SIP Timer K's value in milliseconds. Timer K is the value of wait time for
+ * non-invite response retransmits.
+ * Value is in Integer format.
+ */
+ public static final int SIP_NON_INVITE_RSP_RETX_WAIT_TIME_MSEC = 46;
+ /**
+ * AMR WB octet aligned dynamic payload type.
+ * Value is in Integer format.
+ */
+ public static final int AMR_WB_OCTET_ALIGNED_PT = 47;
+ /**
+ * AMR WB bandwidth efficient payload type.
+ * Value is in Integer format.
+ */
+ public static final int AMR_WB_BANDWIDTH_EFFICIENT_PT = 48;
+ /**
+ * AMR octet aligned dynamic payload type.
+ * Value is in Integer format.
+ */
+ public static final int AMR_OCTET_ALIGNED_PT = 49;
+ /**
+ * AMR bandwidth efficient payload type.
+ * Value is in Integer format.
+ */
+ public static final int AMR_BANDWIDTH_EFFICIENT_PT = 50;
+ /**
+ * DTMF WB payload type.
+ * Value is in Integer format.
+ */
+ public static final int DTMF_WB_PT = 51;
+ /**
+ * DTMF NB payload type.
+ * Value is in Integer format.
+ */
+ public static final int DTMF_NB_PT = 52;
+ /**
+ * AMR Default encoding mode.
+ * Value is in Integer format.
+ */
+ public static final int AMR_DEFAULT_MODE = 53;
+ /**
+ * SMS Public Service Identity.
+ * Value is in String format.
+ */
+ public static final int SMS_PSI = 54;
+ /**
+ * Video Quality - VideoQualityFeatureValuesConstants.
+ * Value is in Integer format.
+ */
+ public static final int VIDEO_QUALITY = 55;
+ /**
+ * LTE threshold.
+ * Handover from LTE to WiFi if LTE < THLTE1 and WiFi >= VOWT_A.
+ */
+ public static final int TH_LTE1 = 56;
+ /**
+ * LTE threshold.
+ * Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2).
+ */
+ public static final int TH_LTE2 = 57;
+ /**
+ * LTE threshold.
+ * Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2).
+ */
+ public static final int TH_LTE3 = 58;
+ /**
+ * 1x threshold.
+ * Handover from 1x to WiFi if 1x < TH1x
+ */
+ public static final int TH_1x = 59;
+ /**
+ * WiFi threshold.
+ * Handover from LTE to WiFi if LTE < THLTE1 and WiFi >= VOWT_A.
+ */
+ public static final int VOWT_A = 60;
+ /**
+ * WiFi threshold.
+ * Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2).
+ */
+ public static final int VOWT_B = 61;
+ /**
+ * LTE ePDG timer.
+ * Device shall not handover back to LTE until the T_ePDG_LTE timer expires.
+ */
+ public static final int T_EPDG_LTE = 62;
+ /**
+ * WiFi ePDG timer.
+ * Device shall not handover back to WiFi until the T_ePDG_WiFi timer expires.
+ */
+ public static final int T_EPDG_WIFI = 63;
+ /**
+ * 1x ePDG timer.
+ * Device shall not re-register on 1x until the T_ePDG_1x timer expires.
+ */
+ public static final int T_EPDG_1X = 64;
+ /**
+ * MultiEndpoint status: Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ */
+ public static final int VICE_SETTING_ENABLED = 65;
+
+ // Expand the operator config items as needed here, need to change
+ // PROVISIONED_CONFIG_END after that.
+ public static final int PROVISIONED_CONFIG_END = VICE_SETTING_ENABLED;
+
+ // Expand the operator config items as needed here.
+ }
+
+ /**
+ * Defines IMS set operation status.
+ */
+ public static class OperationStatusConstants {
+ public static final int UNKNOWN = -1;
+ public static final int SUCCESS = 0;
+ public static final int FAILED = 1;
+ public static final int UNSUPPORTED_CAUSE_NONE = 2;
+ public static final int UNSUPPORTED_CAUSE_RAT = 3;
+ public static final int UNSUPPORTED_CAUSE_DISABLED = 4;
+ }
+
+ /**
+ * Defines IMS get operation values.
+ */
+ public static class OperationValuesConstants {
+ /**
+ * Values related to Video Quality
+ */
+ public static final int VIDEO_QUALITY_UNKNOWN = -1;
+ public static final int VIDEO_QUALITY_LOW = 0;
+ public static final int VIDEO_QUALITY_HIGH = 1;
+ }
+
+ /**
+ * Defines IMS video quality feature value.
+ */
+ public static class VideoQualityFeatureValuesConstants {
+ public static final int LOW = 0;
+ public static final int HIGH = 1;
+ }
+
+ /**
+ * Defines IMS feature value.
+ */
+ public static class FeatureValueConstants {
+ public static final int OFF = 0;
+ public static final int ON = 1;
+ }
+
+ /**
+ * Defines IMS feature value.
+ */
+ public static class WfcModeFeatureValueConstants {
+ public static final int WIFI_ONLY = 0;
+ public static final int CELLULAR_PREFERRED = 1;
+ public static final int WIFI_PREFERRED = 2;
+ }
+
+ public ImsConfig(IImsConfig iconfig, Context context) {
+ if (DBG) Rlog.d(TAG, "ImsConfig creates");
+ miConfig = iconfig;
+ mContext = context;
+ }
+
+ /**
+ * Gets the provisioned value for IMS service/capabilities parameters used by IMS stack.
+ * This function should not be called from the mainthread as it could block the
+ * mainthread.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @return the value in Integer format.
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public int getProvisionedValue(int item) throws ImsException {
+ int ret = 0;
+ try {
+ ret = miConfig.getProvisionedValue(item);
+ } catch (RemoteException e) {
+ throw new ImsException("getValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ if (DBG) Rlog.d(TAG, "getProvisionedValue(): item = " + item + ", ret =" + ret);
+
+ return ret;
+ }
+
+ /**
+ * Gets the provisioned value for IMS service/capabilities parameters used by IMS stack.
+ * This function should not be called from the mainthread as it could block the
+ * mainthread.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @return value in String format.
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public String getProvisionedStringValue(int item) throws ImsException {
+ String ret = "Unknown";
+ try {
+ ret = miConfig.getProvisionedStringValue(item);
+ } catch (RemoteException e) {
+ throw new ImsException("getProvisionedStringValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ if (DBG) Rlog.d(TAG, "getProvisionedStringValue(): item = " + item + ", ret =" + ret);
+
+ return ret;
+ }
+
+ /**
+ * Sets the value for IMS service/capabilities parameters by
+ * the operator device management entity.
+ * This function should not be called from main thread as it could block
+ * mainthread.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @param value in Integer format.
+ * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public int setProvisionedValue(int item, int value)
+ throws ImsException {
+ int ret = OperationStatusConstants.UNKNOWN;
+ if (DBG) {
+ Rlog.d(TAG, "setProvisionedValue(): item = " + item +
+ "value = " + value);
+ }
+ try {
+ ret = miConfig.setProvisionedValue(item, value);
+ } catch (RemoteException e) {
+ throw new ImsException("setProvisionedValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ if (DBG) {
+ Rlog.d(TAG, "setProvisionedValue(): item = " + item +
+ " value = " + value + " ret = " + ret);
+ }
+ return ret;
+ }
+
+ /**
+ * Sets the value for IMS service/capabilities parameters by
+ * the operator device management entity.
+ * This function should not be called from main thread as it could block
+ * mainthread.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @param value in String format.
+ * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public int setProvisionedStringValue(int item, String value)
+ throws ImsException {
+ int ret = OperationStatusConstants.UNKNOWN;
+ try {
+ ret = miConfig.setProvisionedStringValue(item, value);
+ } catch (RemoteException e) {
+ throw new ImsException("setProvisionedStringValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ if (DBG) {
+ Rlog.d(TAG, "setProvisionedStringValue(): item = " + item +
+ ", value =" + value);
+ }
+ return ret;
+ }
+
+ /**
+ * Gets the value for IMS feature item for specified network type.
+ *
+ * @param feature, defined as in FeatureConstants.
+ * @param network, defined as in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
+ * @param listener, provided to be notified for the feature on/off status.
+ * @return void
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public void getFeatureValue(int feature, int network,
+ ImsConfigListener listener) throws ImsException {
+ if (DBG) {
+ Rlog.d(TAG, "getFeatureValue: feature = " + feature + ", network =" + network +
+ ", listener =" + listener);
+ }
+ try {
+ miConfig.getFeatureValue(feature, network, listener);
+ } catch (RemoteException e) {
+ throw new ImsException("getFeatureValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ }
+
+ /**
+ * Sets the value for IMS feature item for specified network type.
+ *
+ * @param feature, as defined in FeatureConstants.
+ * @param network, as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
+ * @param value, as defined in FeatureValueConstants.
+ * @param listener, provided if caller needs to be notified for set result.
+ * @return void
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public void setFeatureValue(int feature, int network, int value,
+ ImsConfigListener listener) throws ImsException {
+ if (DBG) {
+ Rlog.d(TAG, "setFeatureValue: feature = " + feature + ", network =" + network +
+ ", value =" + value + ", listener =" + listener);
+ }
+ try {
+ miConfig.setFeatureValue(feature, network, value, listener);
+ } catch (RemoteException e) {
+ throw new ImsException("setFeatureValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ }
+}
diff --git a/telephony/java/com/android/ims/ImsException.java b/telephony/java/com/android/ims/ImsException.java
new file mode 100644
index 000000000000..74b20f472641
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims;
+
+/**
+ * This class defines a general IMS-related exception.
+ *
+ * @hide
+ */
+public class ImsException extends Exception {
+
+ /**
+ * Refer to CODE_LOCAL_* in {@link ImsReasonInfo}
+ */
+ private int mCode;
+
+ public ImsException() {
+ }
+
+ public ImsException(String message, int code) {
+ super(message + ", code = " + code);
+ mCode = code;
+ }
+
+ public ImsException(String message, Throwable cause, int code) {
+ super(message, cause);
+ mCode = code;
+ }
+
+ /**
+ * Gets the detailed exception code when ImsException is throwed
+ *
+ * @return the exception code in {@link ImsReasonInfo}
+ */
+ public int getCode() {
+ return mCode;
+ }
+}
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index 56b882221cd7..e4f380f7a749 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -308,6 +308,17 @@ public class ImsReasonInfo implements Parcelable {
public static final int CODE_DATA_DISABLED = 1406;
/**
+ * Indicates a call was disconnected due to loss of wifi signal.
+ */
+ public static final int CODE_WIFI_LOST = 1407;
+
+ /**
+ * Indicates the registration attempt on IWLAN failed due to IKEv2 authetication failure
+ * during tunnel establishment.
+ */
+ public static final int CODE_IKEV2_AUTH_FAILURE = 1408;
+
+ /**
* Network string error messages.
* mExtraMessage may have these values.
*/
diff --git a/telephony/java/com/android/ims/ImsUtInterface.java b/telephony/java/com/android/ims/ImsUtInterface.java
new file mode 100644
index 000000000000..5984e789a363
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsUtInterface.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims;
+
+import android.os.Message;
+
+/**
+ * Provides APIs for the supplementary service settings using IMS (Ut interface).
+ * It is created from 3GPP TS 24.623 (XCAP(XML Configuration Access Protocol)
+ * over the Ut interface for manipulating supplementary services).
+ *
+ * @hide
+ */
+public interface ImsUtInterface {
+ /**
+ * Actions
+ * @hide
+ */
+ public static final int ACTION_DEACTIVATION = 0;
+ public static final int ACTION_ACTIVATION = 1;
+ public static final int ACTION_REGISTRATION = 3;
+ public static final int ACTION_ERASURE = 4;
+ public static final int ACTION_INTERROGATION = 5;
+
+ /**
+ * OIR (Originating Identification Restriction, 3GPP TS 24.607)
+ * OIP (Originating Identification Presentation, 3GPP TS 24.607)
+ * TIR (Terminating Identification Restriction, 3GPP TS 24.608)
+ * TIP (Terminating Identification Presentation, 3GPP TS 24.608)
+ */
+ public static final int OIR_DEFAULT = 0; // "user subscription default value"
+ public static final int OIR_PRESENTATION_RESTRICTED = 1;
+ public static final int OIR_PRESENTATION_NOT_RESTRICTED = 2;
+
+ /**
+ * CW (Communication Waiting, 3GPP TS 24.615)
+ */
+
+ /**
+ * CDIV (Communication Diversion, 3GPP TS 24.604)
+ * actions: target, no reply timer
+ */
+ public static final int CDIV_CF_UNCONDITIONAL = 0;
+ public static final int CDIV_CF_BUSY = 1;
+ public static final int CDIV_CF_NO_REPLY = 2;
+ public static final int CDIV_CF_NOT_REACHABLE = 3;
+ // For CS service code: 002
+ public static final int CDIV_CF_ALL = 4;
+ // For CS service code: 004
+ public static final int CDIV_CF_ALL_CONDITIONAL = 5;
+ // It's only supported in the IMS service (CS does not define it).
+ // IR.92 recommends that an UE activates both the CFNRc and the CFNL
+ // (CDIV using condition not-registered) to the same target.
+ public static final int CDIV_CF_NOT_LOGGED_IN = 6;
+
+ /**
+ * CB (Communication Barring, 3GPP TS 24.611)
+ */
+ // Barring of All Incoming Calls
+ public static final int CB_BAIC = 1;
+ // Barring of All Outgoing Calls
+ public static final int CB_BAOC = 2;
+ // Barring of Outgoing International Calls
+ public static final int CB_BOIC = 3;
+ // Barring of Outgoing International Calls - excluding Home Country
+ public static final int CB_BOIC_EXHC = 4;
+ // Barring of Incoming Calls - when roaming
+ public static final int CB_BIC_WR = 5;
+ // Barring of Anonymous Communication Rejection (ACR) - a particular case of ICB service
+ public static final int CB_BIC_ACR = 6;
+ // Barring of All Calls
+ public static final int CB_BA_ALL = 7;
+ // Barring of Outgoing Services (Service Code 333 - 3GPP TS 22.030 Table B-1)
+ public static final int CB_BA_MO = 8;
+ // Barring of Incoming Services (Service Code 353 - 3GPP TS 22.030 Table B-1)
+ public static final int CB_BA_MT = 9;
+ // Barring of Specific Incoming calls
+ public static final int CB_BS_MT = 10;
+
+ /**
+ * Invalid result value.
+ */
+ public static final int INVALID = (-1);
+
+
+
+ /**
+ * Operations for the supplementary service configuration
+ */
+
+ /**
+ * Retrieves the configuration of the call barring.
+ * The return value of ((AsyncResult)result.obj) is an array of {@link ImsSsInfo}.
+ */
+ public void queryCallBarring(int cbType, Message result);
+
+ /**
+ * Retrieves the configuration of the call forward.
+ * The return value of ((AsyncResult)result.obj) is an array of {@link ImsCallForwardInfo}.
+ */
+ public void queryCallForward(int condition, String number, Message result);
+
+ /**
+ * Retrieves the configuration of the call waiting.
+ * The return value of ((AsyncResult)result.obj) is an array of {@link ImsSsInfo}.
+ */
+ public void queryCallWaiting(Message result);
+
+ /**
+ * Retrieves the default CLIR setting.
+ */
+ public void queryCLIR(Message result);
+
+ /**
+ * Retrieves the CLIP call setting.
+ */
+ public void queryCLIP(Message result);
+
+ /**
+ * Retrieves the COLR call setting.
+ */
+ public void queryCOLR(Message result);
+
+ /**
+ * Retrieves the COLP call setting.
+ */
+ public void queryCOLP(Message result);
+
+ /**
+ * Modifies the configuration of the call barring.
+ */
+ public void updateCallBarring(int cbType, int action,
+ Message result, String[] barrList);
+
+ /**
+ * Modifies the configuration of the call forward.
+ */
+ public void updateCallForward(int action, int condition, String number,
+ int serviceClass, int timeSeconds, Message result);
+
+ /**
+ * Modifies the configuration of the call waiting.
+ */
+ public void updateCallWaiting(boolean enable, int serviceClass, Message result);
+
+ /**
+ * Updates the configuration of the CLIR supplementary service.
+ */
+ public void updateCLIR(int clirMode, Message result);
+
+ /**
+ * Updates the configuration of the CLIP supplementary service.
+ */
+ public void updateCLIP(boolean enable, Message result);
+
+ /**
+ * Updates the configuration of the COLR supplementary service.
+ */
+ public void updateCOLR(int presentation, Message result);
+
+ /**
+ * Updates the configuration of the COLP supplementary service.
+ */
+ public void updateCOLP(boolean enable, Message result);
+}
diff --git a/telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl b/telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl
new file mode 100644
index 000000000000..41b1042e9a86
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal;
+
+/**
+* Interface from ImsFeature in the ImsService to ImsServiceController.
+ * {@hide}
+ */
+oneway interface IImsFeatureStatusCallback {
+ void notifyImsFeatureStatus(int featureStatus);
+} \ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/IImsServiceController.aidl b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
new file mode 100644
index 000000000000..712816f9d20c
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
@@ -0,0 +1,64 @@
+/*
+ * 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.ims.internal;
+
+import android.app.PendingIntent;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsFeatureStatusCallback;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsUt;
+
+import android.os.Message;
+
+/**
+ * See ImsService and IMMTelFeature for more information.
+ * {@hide}
+ */
+interface IImsServiceController {
+ // ImsService Control
+ void createImsFeature(int slotId, int feature, IImsFeatureStatusCallback c);
+ void removeImsFeature(int slotId, int feature);
+ // MMTel Feature
+ int startSession(int slotId, int featureType, in PendingIntent incomingCallIntent,
+ in IImsRegistrationListener listener);
+ void endSession(int slotId, int featureType, int sessionId);
+ boolean isConnected(int slotId, int featureType, int callSessionType, int callType);
+ boolean isOpened(int slotId, int featureType);
+ int getFeatureStatus(int slotId, int featureType);
+ void addRegistrationListener(int slotId, int featureType, in IImsRegistrationListener listener);
+ void removeRegistrationListener(int slotId, int featureType,
+ in IImsRegistrationListener listener);
+ ImsCallProfile createCallProfile(int slotId, int featureType, int sessionId,
+ int callSessionType, int callType);
+ IImsCallSession createCallSession(int slotId, int featureType, int sessionId,
+ in ImsCallProfile profile, IImsCallSessionListener listener);
+ IImsCallSession getPendingCallSession(int slotId, int featureType, int sessionId,
+ String callId);
+ IImsUt getUtInterface(int slotId, int featureType);
+ IImsConfig getConfigInterface(int slotId, int featureType);
+ void turnOnIms(int slotId, int featureType);
+ void turnOffIms(int slotId, int featureType);
+ IImsEcbm getEcbmInterface(int slotId, int featureType);
+ void setUiTTYMode(int slotId, int featureType, int uiTtyMode, in Message onComplete);
+ IImsMultiEndpoint getMultiEndpointInterface(int slotId, int featureType);
+}
diff --git a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl b/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
new file mode 100644
index 000000000000..df10700283f2
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.ims.internal;
+
+/**
+ * Interface from ImsResolver to ImsServiceProxy in ImsManager.
+ * Callback to ImsManager when a feature changes in the ImsServiceController.
+ * {@hide}
+ */
+oneway interface IImsServiceFeatureListener {
+ void imsFeatureCreated(int slotId, int feature);
+ void imsFeatureRemoved(int slotId, int feature);
+ void imsStatusChanged(int slotId, int feature, int status);
+} \ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl b/telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl
index 39e83c66b9bb..0da27e163df1 100644
--- a/telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl
+++ b/telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl
@@ -43,7 +43,7 @@ import com.android.ims.internal.IImsVideoCallCallback;
oneway interface IImsVideoCallProvider {
void setCallback(IImsVideoCallCallback callback);
- void setCamera(String cameraId);
+ void setCamera(String cameraId, int uid);
void setPreviewSurface(in Surface surface);
diff --git a/telephony/java/com/android/ims/internal/ImsCallSession.java b/telephony/java/com/android/ims/internal/ImsCallSession.java
new file mode 100644
index 000000000000..8196b2367ce9
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/ImsCallSession.java
@@ -0,0 +1,1290 @@
+/*
+ * Copyright (c) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal;
+
+import android.os.Message;
+import android.os.RemoteException;
+
+import java.util.Objects;
+
+import android.telephony.ims.stub.ImsCallSessionListenerImplBase;
+import android.util.Log;
+import com.android.ims.ImsCallProfile;
+import com.android.ims.ImsConferenceState;
+import com.android.ims.ImsReasonInfo;
+import com.android.ims.ImsStreamMediaProfile;
+import com.android.ims.ImsSuppServiceNotification;
+
+/**
+ * Provides the call initiation/termination, and media exchange between two IMS endpoints.
+ * It directly communicates with IMS service which implements the IMS protocol behavior.
+ *
+ * @hide
+ */
+public class ImsCallSession {
+ private static final String TAG = "ImsCallSession";
+
+ /**
+ * Defines IMS call session state.
+ */
+ public static class State {
+ public static final int IDLE = 0;
+ public static final int INITIATED = 1;
+ public static final int NEGOTIATING = 2;
+ public static final int ESTABLISHING = 3;
+ public static final int ESTABLISHED = 4;
+
+ public static final int RENEGOTIATING = 5;
+ public static final int REESTABLISHING = 6;
+
+ public static final int TERMINATING = 7;
+ public static final int TERMINATED = 8;
+
+ public static final int INVALID = (-1);
+
+ /**
+ * Converts the state to string.
+ */
+ public static String toString(int state) {
+ switch (state) {
+ case IDLE:
+ return "IDLE";
+ case INITIATED:
+ return "INITIATED";
+ case NEGOTIATING:
+ return "NEGOTIATING";
+ case ESTABLISHING:
+ return "ESTABLISHING";
+ case ESTABLISHED:
+ return "ESTABLISHED";
+ case RENEGOTIATING:
+ return "RENEGOTIATING";
+ case REESTABLISHING:
+ return "REESTABLISHING";
+ case TERMINATING:
+ return "TERMINATING";
+ case TERMINATED:
+ return "TERMINATED";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ private State() {
+ }
+ }
+
+ /**
+ * Listener for events relating to an IMS session, such as when a session is being
+ * recieved ("on ringing") or a call is outgoing ("on calling").
+ * <p>Many of these events are also received by {@link ImsCall.Listener}.</p>
+ */
+ public static class Listener {
+ /**
+ * Called when a request is sent out to initiate a new session
+ * and 1xx response is received from the network.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionProgressing(ImsCallSession session,
+ ImsStreamMediaProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Called when the session is established.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionStarted(ImsCallSession session,
+ ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Called when the session establishment is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the session establishment failure
+ */
+ public void callSessionStartFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session is terminated.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the session termination
+ */
+ public void callSessionTerminated(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session is in hold.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionHeld(ImsCallSession session,
+ ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session hold is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the session hold failure
+ */
+ public void callSessionHoldFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session hold is received from the remote user.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionHoldReceived(ImsCallSession session,
+ ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session resume is done.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionResumed(ImsCallSession session,
+ ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session resume is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the session resume failure
+ */
+ public void callSessionResumeFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session resume is received from the remote user.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionResumeReceived(ImsCallSession session,
+ ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session merge has been started. At this point, the {@code newSession}
+ * represents the session which has been initiated to the IMS conference server for the
+ * new merged conference.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param newSession the session object that is merged with an active & hold session
+ */
+ public void callSessionMergeStarted(ImsCallSession session,
+ ImsCallSession newSession, ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session merge is successful and the merged session is active.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionMergeComplete(ImsCallSession session) {
+ }
+
+ /**
+ * Called when the session merge has failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the call merge failure
+ */
+ public void callSessionMergeFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session is updated (except for hold/unhold).
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionUpdated(ImsCallSession session,
+ ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session update is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the session update failure
+ */
+ public void callSessionUpdateFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session update is received from the remote user.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionUpdateReceived(ImsCallSession session,
+ ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Called when the session is extended to the conference session.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param newSession the session object that is extended to the conference
+ * from the active session
+ */
+ public void callSessionConferenceExtended(ImsCallSession session,
+ ImsCallSession newSession, ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the conference extension is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the conference extension failure
+ */
+ public void callSessionConferenceExtendFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the conference extension is received from the remote user.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionConferenceExtendReceived(ImsCallSession session,
+ ImsCallSession newSession, ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Called when the invitation request of the participants is delivered to the conference
+ * server.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionInviteParticipantsRequestDelivered(ImsCallSession session) {
+ // no-op
+ }
+
+ /**
+ * Called when the invitation request of the participants is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the conference invitation failure
+ */
+ public void callSessionInviteParticipantsRequestFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Called when the removal request of the participants is delivered to the conference
+ * server.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionRemoveParticipantsRequestDelivered(ImsCallSession session) {
+ // no-op
+ }
+
+ /**
+ * Called when the removal request of the participants is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the conference removal failure
+ */
+ public void callSessionRemoveParticipantsRequestFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Called when the conference state is updated.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionConferenceStateUpdated(ImsCallSession session,
+ ImsConferenceState state) {
+ // no-op
+ }
+
+ /**
+ * Called when the USSD message is received from the network.
+ *
+ * @param mode mode of the USSD message (REQUEST / NOTIFY)
+ * @param ussdMessage USSD message
+ */
+ public void callSessionUssdMessageReceived(ImsCallSession session,
+ int mode, String ussdMessage) {
+ // no-op
+ }
+
+ /**
+ * Called when session access technology changes
+ *
+ * @param session IMS session object
+ * @param srcAccessTech original access technology
+ * @param targetAccessTech new access technology
+ * @param reasonInfo
+ */
+ public void callSessionHandover(ImsCallSession session,
+ int srcAccessTech, int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Called when session access technology change fails
+ *
+ * @param session IMS session object
+ * @param srcAccessTech original access technology
+ * @param targetAccessTech new access technology
+ * @param reasonInfo handover failure reason
+ */
+ public void callSessionHandoverFailed(ImsCallSession session,
+ int srcAccessTech, int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Called when TTY mode of remote party changed
+ *
+ * @param session IMS session object
+ * @param mode TTY mode of remote party
+ */
+ public void callSessionTtyModeReceived(ImsCallSession session,
+ int mode) {
+ // no-op
+ }
+
+ /**
+ * Notifies of a change to the multiparty state for this {@code ImsCallSession}.
+ *
+ * @param session The call session.
+ * @param isMultiParty {@code true} if the session became multiparty, {@code false}
+ * otherwise.
+ */
+ public void callSessionMultipartyStateChanged(ImsCallSession session,
+ boolean isMultiParty) {
+ // no-op
+ }
+
+ /**
+ * Called when the session supplementary service is received
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionSuppServiceReceived(ImsCallSession session,
+ ImsSuppServiceNotification suppServiceInfo) {
+ }
+ }
+
+ private final IImsCallSession miSession;
+ private boolean mClosed = false;
+ private Listener mListener;
+
+ public ImsCallSession(IImsCallSession iSession) {
+ miSession = iSession;
+
+ if (iSession != null) {
+ try {
+ iSession.setListener(new IImsCallSessionListenerProxy());
+ } catch (RemoteException e) {
+ }
+ } else {
+ mClosed = true;
+ }
+ }
+
+ public ImsCallSession(IImsCallSession iSession, Listener listener) {
+ this(iSession);
+ setListener(listener);
+ }
+
+ /**
+ * Closes this object. This object is not usable after being closed.
+ */
+ public synchronized void close() {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.close();
+ mClosed = true;
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Gets the call ID of the session.
+ *
+ * @return the call ID
+ */
+ public String getCallId() {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getCallId();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the call profile that this session is associated with
+ *
+ * @return the call profile that this session is associated with
+ */
+ public ImsCallProfile getCallProfile() {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getCallProfile();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the local call profile that this session is associated with
+ *
+ * @return the local call profile that this session is associated with
+ */
+ public ImsCallProfile getLocalCallProfile() {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getLocalCallProfile();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the remote call profile that this session is associated with
+ *
+ * @return the remote call profile that this session is associated with
+ */
+ public ImsCallProfile getRemoteCallProfile() {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getRemoteCallProfile();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the video call provider for the session.
+ *
+ * @return The video call provider.
+ */
+ public IImsVideoCallProvider getVideoCallProvider() {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getVideoCallProvider();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the value associated with the specified property of this session.
+ *
+ * @return the string value associated with the specified property
+ */
+ public String getProperty(String name) {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getProperty(name);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the session state.
+ * The value returned must be one of the states in {@link State}.
+ *
+ * @return the session state
+ */
+ public int getState() {
+ if (mClosed) {
+ return State.INVALID;
+ }
+
+ try {
+ return miSession.getState();
+ } catch (RemoteException e) {
+ return State.INVALID;
+ }
+ }
+
+ /**
+ * Determines if the {@link ImsCallSession} is currently alive (e.g. not in a terminated or
+ * closed state).
+ *
+ * @return {@code True} if the session is alive.
+ */
+ public boolean isAlive() {
+ if (mClosed) {
+ return false;
+ }
+
+ int state = getState();
+ switch (state) {
+ case State.IDLE:
+ case State.INITIATED:
+ case State.NEGOTIATING:
+ case State.ESTABLISHING:
+ case State.ESTABLISHED:
+ case State.RENEGOTIATING:
+ case State.REESTABLISHING:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Gets the native IMS call session.
+ * @hide
+ */
+ public IImsCallSession getSession() {
+ return miSession;
+ }
+
+ /**
+ * Checks if the session is in call.
+ *
+ * @return true if the session is in call
+ */
+ public boolean isInCall() {
+ if (mClosed) {
+ return false;
+ }
+
+ try {
+ return miSession.isInCall();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Sets the listener to listen to the session events. A {@link ImsCallSession}
+ * can only hold one listener at a time. Subsequent calls to this method
+ * override the previous listener.
+ *
+ * @param listener to listen to the session events of this object
+ */
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Mutes or unmutes the mic for the active call.
+ *
+ * @param muted true if the call is muted, false otherwise
+ */
+ public void setMute(boolean muted) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.setMute(muted);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Initiates an IMS call with the specified target and call profile.
+ * The session listener is called back upon defined session events.
+ * The method is only valid to call when the session state is in
+ * {@link ImsCallSession.State#IDLE}.
+ *
+ * @param callee dialed string to make the call to
+ * @param profile call profile to make the call with the specified service type,
+ * call type and media information
+ * @see Listener#callSessionStarted, Listener#callSessionStartFailed
+ */
+ public void start(String callee, ImsCallProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.start(callee, profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Initiates an IMS conference call with the specified target and call profile.
+ * The session listener is called back upon defined session events.
+ * The method is only valid to call when the session state is in
+ * {@link ImsCallSession.State#IDLE}.
+ *
+ * @param participants participant list to initiate an IMS conference call
+ * @param profile call profile to make the call with the specified service type,
+ * call type and media information
+ * @see Listener#callSessionStarted, Listener#callSessionStartFailed
+ */
+ public void start(String[] participants, ImsCallProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.startConference(participants, profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Accepts an incoming call or session update.
+ *
+ * @param callType call type specified in {@link ImsCallProfile} to be answered
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to be answered
+ * @see Listener#callSessionStarted
+ */
+ public void accept(int callType, ImsStreamMediaProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.accept(callType, profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Rejects an incoming call or session update.
+ *
+ * @param reason reason code to reject an incoming call
+ * @see Listener#callSessionStartFailed
+ */
+ public void reject(int reason) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.reject(reason);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Terminates a call.
+ *
+ * @see Listener#callSessionTerminated
+ */
+ public void terminate(int reason) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.terminate(reason);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Puts a call on hold. When it succeeds, {@link Listener#callSessionHeld} is called.
+ *
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to hold the call
+ * @see Listener#callSessionHeld, Listener#callSessionHoldFailed
+ */
+ public void hold(ImsStreamMediaProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.hold(profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Continues a call that's on hold. When it succeeds,
+ * {@link Listener#callSessionResumed} is called.
+ *
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to resume the call
+ * @see Listener#callSessionResumed, Listener#callSessionResumeFailed
+ */
+ public void resume(ImsStreamMediaProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.resume(profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Merges the active & hold call. When it succeeds,
+ * {@link Listener#callSessionMergeStarted} is called.
+ *
+ * @see Listener#callSessionMergeStarted , Listener#callSessionMergeFailed
+ */
+ public void merge() {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.merge();
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Updates the current call's properties (ex. call mode change: video upgrade / downgrade).
+ *
+ * @param callType call type specified in {@link ImsCallProfile} to be updated
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to be updated
+ * @see Listener#callSessionUpdated, Listener#callSessionUpdateFailed
+ */
+ public void update(int callType, ImsStreamMediaProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.update(callType, profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Extends this call to the conference call with the specified recipients.
+ *
+ * @param participants list to be invited to the conference call after extending the call
+ * @see Listener#callSessionConferenceExtended
+ * @see Listener#callSessionConferenceExtendFailed
+ */
+ public void extendToConference(String[] participants) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.extendToConference(participants);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Requests the conference server to invite an additional participants to the conference.
+ *
+ * @param participants list to be invited to the conference call
+ * @see Listener#callSessionInviteParticipantsRequestDelivered
+ * @see Listener#callSessionInviteParticipantsRequestFailed
+ */
+ public void inviteParticipants(String[] participants) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.inviteParticipants(participants);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Requests the conference server to remove the specified participants from the conference.
+ *
+ * @param participants participant list to be removed from the conference call
+ * @see Listener#callSessionRemoveParticipantsRequestDelivered
+ * @see Listener#callSessionRemoveParticipantsRequestFailed
+ */
+ public void removeParticipants(String[] participants) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.removeParticipants(participants);
+ } catch (RemoteException e) {
+ }
+ }
+
+
+ /**
+ * Sends a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+ * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+ * and event flash to 16. Currently, event flash is not supported.
+ *
+ * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+ */
+ public void sendDtmf(char c, Message result) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.sendDtmf(c, result);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Starts a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+ * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+ * and event flash to 16. Currently, event flash is not supported.
+ *
+ * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+ */
+ public void startDtmf(char c) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.startDtmf(c);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Stops a DTMF code.
+ */
+ public void stopDtmf() {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.stopDtmf();
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Sends an USSD message.
+ *
+ * @param ussdMessage USSD message to send
+ */
+ public void sendUssd(String ussdMessage) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.sendUssd(ussdMessage);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Determines if the session is multiparty.
+ *
+ * @return {@code True} if the session is multiparty.
+ */
+ public boolean isMultiparty() {
+ if (mClosed) {
+ return false;
+ }
+
+ try {
+ return miSession.isMultiparty();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * A listener type for receiving notification on IMS call session events.
+ * When an event is generated for an {@link IImsCallSession},
+ * the application is notified by having one of the methods called on
+ * the {@link IImsCallSessionListener}.
+ */
+ private class IImsCallSessionListenerProxy extends ImsCallSessionListenerImplBase {
+ /**
+ * Notifies the result of the basic session operation (setup / terminate).
+ */
+ @Override
+ public void callSessionProgressing(IImsCallSession session,
+ ImsStreamMediaProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionProgressing(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionStarted(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionStarted(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionStartFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionStartFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionTerminated(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionTerminated(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ /**
+ * Notifies the result of the call hold/resume operation.
+ */
+ @Override
+ public void callSessionHeld(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionHeld(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionHoldFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionHoldFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionHoldReceived(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionHoldReceived(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionResumed(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionResumed(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionResumeFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionResumeFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionResumeReceived(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionResumeReceived(ImsCallSession.this, profile);
+ }
+ }
+
+ /**
+ * Notifies the start of a call merge operation.
+ *
+ * @param session The call session.
+ * @param newSession The merged call session.
+ * @param profile The call profile.
+ */
+ @Override
+ public void callSessionMergeStarted(IImsCallSession session,
+ IImsCallSession newSession, ImsCallProfile profile) {
+ // This callback can be used for future use to add additional
+ // functionality that may be needed between conference start and complete
+ Log.d(TAG, "callSessionMergeStarted");
+ }
+
+ /**
+ * Notifies the successful completion of a call merge operation.
+ *
+ * @param newSession The call session.
+ */
+ @Override
+ public void callSessionMergeComplete(IImsCallSession newSession) {
+ if (mListener != null) {
+ if (newSession != null) {
+ // Check if the active session is the same session that was
+ // active before the merge request was sent.
+ ImsCallSession validActiveSession = ImsCallSession.this;
+ try {
+ if (!Objects.equals(miSession.getCallId(), newSession.getCallId())) {
+ // New session created after conference
+ validActiveSession = new ImsCallSession(newSession);
+ }
+ } catch (RemoteException rex) {
+ Log.e(TAG, "callSessionMergeComplete: exception for getCallId!");
+ }
+ mListener.callSessionMergeComplete(validActiveSession);
+ } else {
+ // Session already exists. Hence no need to pass
+ mListener.callSessionMergeComplete(null);
+ }
+ }
+ }
+
+ /**
+ * Notifies of a failure to perform a call merge operation.
+ *
+ * @param session The call session.
+ * @param reasonInfo The merge failure reason.
+ */
+ @Override
+ public void callSessionMergeFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionMergeFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ /**
+ * Notifies the result of call upgrade / downgrade or any other call updates.
+ */
+ @Override
+ public void callSessionUpdated(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionUpdated(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionUpdateFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionUpdateFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionUpdateReceived(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionUpdateReceived(ImsCallSession.this, profile);
+ }
+ }
+
+ /**
+ * Notifies the result of conference extension.
+ */
+ @Override
+ public void callSessionConferenceExtended(IImsCallSession session,
+ IImsCallSession newSession, ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionConferenceExtended(ImsCallSession.this,
+ new ImsCallSession(newSession), profile);
+ }
+ }
+
+ @Override
+ public void callSessionConferenceExtendFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionConferenceExtendFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionConferenceExtendReceived(IImsCallSession session,
+ IImsCallSession newSession, ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionConferenceExtendReceived(ImsCallSession.this,
+ new ImsCallSession(newSession), profile);
+ }
+ }
+
+ /**
+ * Notifies the result of the participant invitation / removal to/from
+ * the conference session.
+ */
+ @Override
+ public void callSessionInviteParticipantsRequestDelivered(IImsCallSession session) {
+ if (mListener != null) {
+ mListener.callSessionInviteParticipantsRequestDelivered(ImsCallSession.this);
+ }
+ }
+
+ @Override
+ public void callSessionInviteParticipantsRequestFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionInviteParticipantsRequestFailed(ImsCallSession.this,
+ reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionRemoveParticipantsRequestDelivered(IImsCallSession session) {
+ if (mListener != null) {
+ mListener.callSessionRemoveParticipantsRequestDelivered(ImsCallSession.this);
+ }
+ }
+
+ @Override
+ public void callSessionRemoveParticipantsRequestFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionRemoveParticipantsRequestFailed(ImsCallSession.this,
+ reasonInfo);
+ }
+ }
+
+ /**
+ * Notifies the changes of the conference info. in the conference session.
+ */
+ @Override
+ public void callSessionConferenceStateUpdated(IImsCallSession session,
+ ImsConferenceState state) {
+ if (mListener != null) {
+ mListener.callSessionConferenceStateUpdated(ImsCallSession.this, state);
+ }
+ }
+
+ /**
+ * Notifies the incoming USSD message.
+ */
+ @Override
+ public void callSessionUssdMessageReceived(IImsCallSession session,
+ int mode, String ussdMessage) {
+ if (mListener != null) {
+ mListener.callSessionUssdMessageReceived(ImsCallSession.this, mode, ussdMessage);
+ }
+ }
+
+ /**
+ * Notifies of handover information for this call
+ */
+ @Override
+ public void callSessionHandover(IImsCallSession session,
+ int srcAccessTech, int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionHandover(ImsCallSession.this, srcAccessTech,
+ targetAccessTech, reasonInfo);
+ }
+ }
+
+ /**
+ * Notifies of handover failure info for this call
+ */
+ @Override
+ public void callSessionHandoverFailed(IImsCallSession session,
+ int srcAccessTech, int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionHandoverFailed(ImsCallSession.this, srcAccessTech,
+ targetAccessTech, reasonInfo);
+ }
+ }
+
+ /**
+ * Notifies the TTY mode received from remote party.
+ */
+ @Override
+ public void callSessionTtyModeReceived(IImsCallSession session,
+ int mode) {
+ if (mListener != null) {
+ mListener.callSessionTtyModeReceived(ImsCallSession.this, mode);
+ }
+ }
+
+ /**
+ * Notifies of a change to the multiparty state for this {@code ImsCallSession}.
+ *
+ * @param session The call session.
+ * @param isMultiParty {@code true} if the session became multiparty, {@code false}
+ * otherwise.
+ */
+ public void callSessionMultipartyStateChanged(IImsCallSession session,
+ boolean isMultiParty) {
+
+ if (mListener != null) {
+ mListener.callSessionMultipartyStateChanged(ImsCallSession.this, isMultiParty);
+ }
+ }
+
+ @Override
+ public void callSessionSuppServiceReceived(IImsCallSession session,
+ ImsSuppServiceNotification suppServiceInfo ) {
+ if (mListener != null) {
+ mListener.callSessionSuppServiceReceived(ImsCallSession.this, suppServiceInfo);
+ }
+ }
+
+ }
+
+ /**
+ * Provides a string representation of the {@link ImsCallSession}. Primarily intended for
+ * use in log statements.
+ *
+ * @return String representation of session.
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[ImsCallSession objId:");
+ sb.append(System.identityHashCode(this));
+ sb.append(" state:");
+ sb.append(State.toString(getState()));
+ sb.append(" callId:");
+ sb.append(getCallId());
+ sb.append("]");
+ return sb.toString();
+ }
+}
diff --git a/telephony/java/com/android/ims/internal/ImsVideoCallProvider.java b/telephony/java/com/android/ims/internal/ImsVideoCallProvider.java
new file mode 100644
index 000000000000..432dc3905737
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/ImsVideoCallProvider.java
@@ -0,0 +1,294 @@
+/*
+ * 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.ims.internal;
+
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telecom.Connection;
+import android.telecom.VideoProfile;
+import android.telecom.VideoProfile.CameraCapabilities;
+import android.view.Surface;
+
+import com.android.internal.os.SomeArgs;
+
+/**
+ * @hide
+ */
+public abstract class ImsVideoCallProvider {
+ private static final int MSG_SET_CALLBACK = 1;
+ private static final int MSG_SET_CAMERA = 2;
+ private static final int MSG_SET_PREVIEW_SURFACE = 3;
+ private static final int MSG_SET_DISPLAY_SURFACE = 4;
+ private static final int MSG_SET_DEVICE_ORIENTATION = 5;
+ private static final int MSG_SET_ZOOM = 6;
+ private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7;
+ private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8;
+ private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9;
+ private static final int MSG_REQUEST_CALL_DATA_USAGE = 10;
+ private static final int MSG_SET_PAUSE_IMAGE = 11;
+
+ private final ImsVideoCallProviderBinder mBinder;
+
+ private IImsVideoCallCallback mCallback;
+
+ /**
+ * Default handler used to consolidate binder method calls onto a single thread.
+ */
+ private final Handler mProviderHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SET_CALLBACK:
+ mCallback = (IImsVideoCallCallback) msg.obj;
+ break;
+ case MSG_SET_CAMERA:
+ {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ onSetCamera((String) args.arg1);
+ onSetCamera((String) args.arg1, args.argi1);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_SET_PREVIEW_SURFACE:
+ onSetPreviewSurface((Surface) msg.obj);
+ break;
+ case MSG_SET_DISPLAY_SURFACE:
+ onSetDisplaySurface((Surface) msg.obj);
+ break;
+ case MSG_SET_DEVICE_ORIENTATION:
+ onSetDeviceOrientation(msg.arg1);
+ break;
+ case MSG_SET_ZOOM:
+ onSetZoom((Float) msg.obj);
+ break;
+ case MSG_SEND_SESSION_MODIFY_REQUEST: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ VideoProfile fromProfile = (VideoProfile) args.arg1;
+ VideoProfile toProfile = (VideoProfile) args.arg2;
+
+ onSendSessionModifyRequest(fromProfile, toProfile);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_SEND_SESSION_MODIFY_RESPONSE:
+ onSendSessionModifyResponse((VideoProfile) msg.obj);
+ break;
+ case MSG_REQUEST_CAMERA_CAPABILITIES:
+ onRequestCameraCapabilities();
+ break;
+ case MSG_REQUEST_CALL_DATA_USAGE:
+ onRequestCallDataUsage();
+ break;
+ case MSG_SET_PAUSE_IMAGE:
+ onSetPauseImage((Uri) msg.obj);
+ break;
+ default:
+ break;
+ }
+ }
+ };
+
+ /**
+ * IImsVideoCallProvider stub implementation.
+ */
+ private final class ImsVideoCallProviderBinder extends IImsVideoCallProvider.Stub {
+ public void setCallback(IImsVideoCallCallback callback) {
+ mProviderHandler.obtainMessage(MSG_SET_CALLBACK, callback).sendToTarget();
+ }
+
+ public void setCamera(String cameraId, int uid) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = cameraId;
+ args.argi1 = uid;
+ mProviderHandler.obtainMessage(MSG_SET_CAMERA, args).sendToTarget();
+ }
+
+ public void setPreviewSurface(Surface surface) {
+ mProviderHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget();
+ }
+
+ public void setDisplaySurface(Surface surface) {
+ mProviderHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget();
+ }
+
+ public void setDeviceOrientation(int rotation) {
+ mProviderHandler.obtainMessage(MSG_SET_DEVICE_ORIENTATION, rotation, 0).sendToTarget();
+ }
+
+ public void setZoom(float value) {
+ mProviderHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget();
+ }
+
+ public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = fromProfile;
+ args.arg2 = toProfile;
+ mProviderHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_REQUEST, args).sendToTarget();
+ }
+
+ public void sendSessionModifyResponse(VideoProfile responseProfile) {
+ mProviderHandler.obtainMessage(
+ MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget();
+ }
+
+ public void requestCameraCapabilities() {
+ mProviderHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget();
+ }
+
+ public void requestCallDataUsage() {
+ mProviderHandler.obtainMessage(MSG_REQUEST_CALL_DATA_USAGE).sendToTarget();
+ }
+
+ public void setPauseImage(Uri uri) {
+ mProviderHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget();
+ }
+ }
+
+ public ImsVideoCallProvider() {
+ mBinder = new ImsVideoCallProviderBinder();
+ }
+
+ /**
+ * Returns binder object which can be used across IPC methods.
+ */
+ public final IImsVideoCallProvider getInterface() {
+ return mBinder;
+ }
+
+ /** @see Connection.VideoProvider#onSetCamera */
+ public abstract void onSetCamera(String cameraId);
+
+ /**
+ * Similar to {@link #onSetCamera(String)}, except includes the UID of the calling process which
+ * the IMS service uses when opening the camera. This ensures camera permissions are verified
+ * by the camera service.
+ *
+ * @param cameraId The id of the camera to be opened.
+ * @param uid The uid of the caller, used when opening the camera for permission verification.
+ * @see Connection.VideoProvider#onSetCamera
+ */
+ public void onSetCamera(String cameraId, int uid) {
+ }
+
+ /** @see Connection.VideoProvider#onSetPreviewSurface */
+ public abstract void onSetPreviewSurface(Surface surface);
+
+ /** @see Connection.VideoProvider#onSetDisplaySurface */
+ public abstract void onSetDisplaySurface(Surface surface);
+
+ /** @see Connection.VideoProvider#onSetDeviceOrientation */
+ public abstract void onSetDeviceOrientation(int rotation);
+
+ /** @see Connection.VideoProvider#onSetZoom */
+ public abstract void onSetZoom(float value);
+
+ /** @see Connection.VideoProvider#onSendSessionModifyRequest */
+ public abstract void onSendSessionModifyRequest(VideoProfile fromProfile,
+ VideoProfile toProfile);
+
+ /** @see Connection.VideoProvider#onSendSessionModifyResponse */
+ public abstract void onSendSessionModifyResponse(VideoProfile responseProfile);
+
+ /** @see Connection.VideoProvider#onRequestCameraCapabilities */
+ public abstract void onRequestCameraCapabilities();
+
+ /** @see Connection.VideoProvider#onRequestCallDataUsage */
+ public abstract void onRequestCallDataUsage();
+
+ /** @see Connection.VideoProvider#onSetPauseImage */
+ public abstract void onSetPauseImage(Uri uri);
+
+ /** @see Connection.VideoProvider#receiveSessionModifyRequest */
+ public void receiveSessionModifyRequest(VideoProfile VideoProfile) {
+ if (mCallback != null) {
+ try {
+ mCallback.receiveSessionModifyRequest(VideoProfile);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#receiveSessionModifyResponse */
+ public void receiveSessionModifyResponse(
+ int status, VideoProfile requestedProfile, VideoProfile responseProfile) {
+ if (mCallback != null) {
+ try {
+ mCallback.receiveSessionModifyResponse(status, requestedProfile, responseProfile);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#handleCallSessionEvent */
+ public void handleCallSessionEvent(int event) {
+ if (mCallback != null) {
+ try {
+ mCallback.handleCallSessionEvent(event);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#changePeerDimensions */
+ public void changePeerDimensions(int width, int height) {
+ if (mCallback != null) {
+ try {
+ mCallback.changePeerDimensions(width, height);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#changeCallDataUsage */
+ public void changeCallDataUsage(long dataUsage) {
+ if (mCallback != null) {
+ try {
+ mCallback.changeCallDataUsage(dataUsage);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#changeCameraCapabilities */
+ public void changeCameraCapabilities(CameraCapabilities CameraCapabilities) {
+ if (mCallback != null) {
+ try {
+ mCallback.changeCameraCapabilities(CameraCapabilities);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#changeVideoQuality */
+ public void changeVideoQuality(int videoQuality) {
+ if (mCallback != null) {
+ try {
+ mCallback.changeVideoQuality(videoQuality);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index cbedb95d2ea5..e9c5461ab421 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -43,6 +43,8 @@ oneway interface IPhoneStateListener {
void onPreciseDataConnectionStateChanged(in PreciseDataConnectionState dataConnectionState);
void onDataConnectionRealTimeInfoChanged(in DataConnectionRealTimeInfo dcRtInfo);
void onVoLteServiceStateChanged(in VoLteServiceState lteState);
+ void onVoiceActivationStateChanged(int activationState);
+ void onDataActivationStateChanged(int activationState);
void onOemHookRawEvent(in byte[] rawData);
void onCarrierNetworkChange(in boolean active);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index a8eaf3627013..42a80b77f907 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -24,6 +24,7 @@ import android.service.carrier.CarrierIdentifier;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telephony.CellInfo;
+import android.telephony.ClientRequestStats;
import android.telephony.IccOpenLogicalChannelResponse;
import android.telephony.ModemActivityInfo;
import android.telephony.NeighboringCellInfo;
@@ -31,6 +32,8 @@ import android.telephony.RadioAccessFamily;
import android.telephony.ServiceState;
import android.telephony.TelephonyHistogram;
import android.telephony.VisualVoicemailSmsFilterSettings;
+import com.android.ims.internal.IImsServiceController;
+import com.android.ims.internal.IImsServiceFeatureListener;
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.OperatorInfo;
@@ -442,6 +445,30 @@ interface ITelephony {
*/
boolean setVoiceMailNumber(int subId, String alphaTag, String number);
+ /**
+ * Sets the voice activation state for a particular subscriber.
+ */
+ void setVoiceActivationState(int subId, int activationState);
+
+ /**
+ * Sets the data activation state for a particular subscriber.
+ */
+ void setDataActivationState(int subId, int activationState);
+
+ /**
+ * Returns the voice activation state for a particular subscriber.
+ * @param subId user preferred sub
+ * @param callingPackage package queries voice activation state
+ */
+ int getVoiceActivationState(int subId, String callingPackage);
+
+ /**
+ * Returns the data activation state for a particular subscriber.
+ * @param subId user preferred sub
+ * @param callingPackage package queris data activation state
+ */
+ int getDataActivationState(int subId, String callingPackage);
+
/**
* Returns the unread count of voicemails
*/
@@ -715,6 +742,14 @@ interface ITelephony {
int getTetherApnRequired();
/**
+ * Get ImsServiceController binder from ImsResolver that corresponds to the subId and feature
+ * requested as well as registering the ImsServiceController for callbacks using the
+ * IImsServiceFeatureListener interface.
+ */
+ IImsServiceController getImsServiceControllerAndListen(int slotId, int feature,
+ IImsServiceFeatureListener callback);
+
+ /**
* Set the network selection mode to automatic.
*
* @param subId the id of the subscription to update.
@@ -1182,4 +1217,22 @@ interface ITelephony {
* @hide
*/
void setPolicyDataEnabled(boolean enabled, int subId);
+
+
+ /**
+ * Get Client request stats which will contain statistical information
+ * on each request made by client.
+ * @param callingPackage package making the call.
+ * @param subId Subscription index
+ * @hide
+ */
+ List<ClientRequestStats> getClientRequestStats(String callingPackage, int subid);
+
+ /**
+ * Set SIM card power state. Request is equivalent to inserting or removing the card.
+ * @param slotId SIM slot id
+ * @param powerUp True if powering up the SIM, otherwise powering down
+ * @hide
+ * */
+ void setSimPowerStateForSlot(int slotId, boolean powerUp);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 2c6be62ee7f5..2c2206c390f8 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -65,6 +65,8 @@ interface ITelephonyRegistry {
String failCause);
void notifyCellInfoForSubscriber(in int subId, in List<CellInfo> cellInfo);
void notifyVoLteServiceStateChanged(in VoLteServiceState lteState);
+ void notifySimActivationStateChangedForPhoneId(in int phoneId, in int subId,
+ int activationState, int activationType);
void notifyOemHookRawEventForSubscriber(in int subId, in byte[] rawData);
void notifySubscriptionInfoChanged();
void notifyCarrierNetworkChange(in boolean active);
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index fdc68b9fb7c6..f9de776f9a7b 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -74,6 +74,9 @@ public class PhoneConstants {
public static final int PRESENTATION_UNKNOWN = 3; // no specified or unknown by network
public static final int PRESENTATION_PAYPHONE = 4; // show pay phone info
+ // Sim activation type
+ public static final int SIM_ACTIVATION_TYPE_VOICE = 0;
+ public static final int SIM_ACTIVATION_TYPE_DATA = 1;
public static final String PHONE_NAME_KEY = "phoneName";
public static final String FAILURE_REASON_KEY = "reason";
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index a91e9beb3143..81ecdc9dbf27 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -411,13 +411,14 @@ cat include/telephony/ril.h | \
int RIL_REQUEST_GET_ACTIVITY_INFO = 135;
int RIL_REQUEST_SET_ALLOWED_CARRIERS = 136;
int RIL_REQUEST_GET_ALLOWED_CARRIERS = 137;
+ int RIL_REQUEST_SET_SIM_CARD_POWER = 140;
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
int RIL_UNSOL_RESPONSE_BASE = 1000;
int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
- int RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED = 1002;
+ int RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED = 1002;
int RIL_UNSOL_RESPONSE_NEW_SMS = 1003;
int RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT = 1004;
int RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM = 1005;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 0168874c5742..682b6722d29b 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -264,15 +264,6 @@ public class TelephonyIntents {
= "android.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS";
/**
- * Activity Action: Start this activity to invoke the carrier setup app.
- * The carrier app must be signed using a certificate that matches the UICC access rules.
- *
- * <p class="note">Callers of this should hold the android.permission.INVOKE_CARRIER_SETUP
- * permission.</p>
- */
- public static final String ACTION_CARRIER_SETUP = "android.intent.action.ACTION_CARRIER_SETUP";
-
- /**
* <p>Broadcast Action: Indicates that the action is forbidden by network.
* <p class="note">
* This is for the OEM applications to understand about possible provisioning issues.
@@ -411,7 +402,7 @@ public class TelephonyIntents {
* <p class="note">This is a protected intent that can only be sent by the system.</p>
*/
public static final String ACTION_CARRIER_SIGNAL_REDIRECTED =
- "android.intent.action.CARRIER_SIGNAL_REDIRECTED";
+ "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED";
/**
* <p>Broadcast Action: when data connections setup fails.
* intended for sim/account status checks and only sent to the specified carrier app
@@ -424,7 +415,7 @@ public class TelephonyIntents {
* <p class="note">This is a protected intent that can only be sent by the system. </p>
*/
public static final String ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED =
- "android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED";
+ "com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED";
/**
* <p>Broadcast Action: when pco value is available.
@@ -441,7 +432,7 @@ public class TelephonyIntents {
* <p class="note">This is a protected intent that can only be sent by the system. </p>
*/
public static final String ACTION_CARRIER_SIGNAL_PCO_VALUE =
- "android.intent.action.CARRIER_SIGNAL_PCO_VALUE";
+ "com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE";
// CARRIER_SIGNAL_ACTION extra keys
public static final String EXTRA_REDIRECTION_URL_KEY = "redirectionUrl";
diff --git a/test-runner/src/android/test/suitebuilder/TestMethod.java b/test-runner/src/android/test/suitebuilder/TestMethod.java
index 08568d5d1a9b..ae1db5e5d4e3 100644
--- a/test-runner/src/android/test/suitebuilder/TestMethod.java
+++ b/test-runner/src/android/test/suitebuilder/TestMethod.java
@@ -26,7 +26,11 @@ import java.lang.reflect.Method;
/**
* Represents a test to be run. Can be constructed without instantiating the TestCase or even
* loading the class.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class TestMethod {
private final String enclosingClassname;
diff --git a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
index 8c8948973f7e..3b920cff30e0 100644
--- a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
+++ b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
@@ -38,7 +38,11 @@ import java.util.Collections;
/**
* Build suites based on a combination of included packages, excluded packages,
* and predicates that must be satisfied.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class TestSuiteBuilder {
private Context context;
@@ -223,7 +227,11 @@ public class TestSuiteBuilder {
/**
* A special {@link junit.framework.TestCase} used to indicate a failure during the build()
* step.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+ @Deprecated
public static class FailedToCreateTests extends TestCase {
private final Exception exception;
diff --git a/test-runner/src/junit/runner/package-info.java b/test-runner/src/junit/runner/package-info.java
index b746185f333e..364e3621456e 100644
--- a/test-runner/src/junit/runner/package-info.java
+++ b/test-runner/src/junit/runner/package-info.java
@@ -1,4 +1,4 @@
/**
- * Provides JUnit v3.x test runners.
+ * Utility classes supporting the junit test framework.
*/
package junit.runner; \ No newline at end of file
diff --git a/test-runner/src/junit/runner/package.html b/test-runner/src/junit/runner/package.html
deleted file mode 100644
index f08fa7013299..000000000000
--- a/test-runner/src/junit/runner/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<HTML>
-<BODY>
-Utility classes supporting the junit test framework.
-</BODY>
-</HTML>
diff --git a/test-runner/src/junit/textui/package-info.java b/test-runner/src/junit/textui/package-info.java
index 2dcc10cf7388..28b2ef46b582 100644
--- a/test-runner/src/junit/textui/package-info.java
+++ b/test-runner/src/junit/textui/package-info.java
@@ -1,5 +1,5 @@
/**
- * Provides JUnit v3.x command line based tool to run tests.
+ * Utility classes supporting the junit test framework.
* {@hide}
*/
package junit.textui; \ No newline at end of file
diff --git a/test-runner/src/junit/textui/package.html b/test-runner/src/junit/textui/package.html
deleted file mode 100644
index 723f2ae5151c..000000000000
--- a/test-runner/src/junit/textui/package.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<HTML>
-<BODY>
-Utility classes supporting the junit test framework.
-{@hide} - Not needed for 1.0 SDK
-</BODY>
-</HTML>
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
new file mode 100644
index 000000000000..b984bbfddac3
--- /dev/null
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
+import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ConnectivityManagerTest {
+ static NetworkCapabilities verifyNetworkCapabilities(
+ int legacyType, int transportType, int... capabilities) {
+ final NetworkCapabilities nc = ConnectivityManager.networkCapabilitiesForType(legacyType);
+ assertNotNull(nc);
+ assertTrue(nc.hasTransport(transportType));
+ for (int capability : capabilities) {
+ assertTrue(nc.hasCapability(capability));
+ }
+
+ return nc;
+ }
+
+ static void verifyUnrestrictedNetworkCapabilities(int legacyType, int transportType) {
+ verifyNetworkCapabilities(
+ legacyType,
+ transportType,
+ NET_CAPABILITY_INTERNET,
+ NET_CAPABILITY_NOT_RESTRICTED,
+ NET_CAPABILITY_NOT_VPN,
+ NET_CAPABILITY_TRUSTED);
+ }
+
+ static void verifyRestrictedMobileNetworkCapabilities(int legacyType, int capability) {
+ final NetworkCapabilities nc = verifyNetworkCapabilities(
+ legacyType,
+ TRANSPORT_CELLULAR,
+ capability,
+ NET_CAPABILITY_NOT_VPN,
+ NET_CAPABILITY_TRUSTED);
+
+ assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
+ assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeMobile() {
+ verifyUnrestrictedNetworkCapabilities(
+ ConnectivityManager.TYPE_MOBILE, TRANSPORT_CELLULAR);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeMobileCbs() {
+ verifyRestrictedMobileNetworkCapabilities(
+ ConnectivityManager.TYPE_MOBILE_CBS, NET_CAPABILITY_CBS);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeMobileDun() {
+ verifyRestrictedMobileNetworkCapabilities(
+ ConnectivityManager.TYPE_MOBILE_DUN, NET_CAPABILITY_DUN);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeMobileFota() {
+ verifyRestrictedMobileNetworkCapabilities(
+ ConnectivityManager.TYPE_MOBILE_FOTA, NET_CAPABILITY_FOTA);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeMobileHipri() {
+ verifyUnrestrictedNetworkCapabilities(
+ ConnectivityManager.TYPE_MOBILE_HIPRI, TRANSPORT_CELLULAR);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeMobileIms() {
+ verifyRestrictedMobileNetworkCapabilities(
+ ConnectivityManager.TYPE_MOBILE_IMS, NET_CAPABILITY_IMS);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeMobileMms() {
+ final NetworkCapabilities nc = verifyNetworkCapabilities(
+ ConnectivityManager.TYPE_MOBILE_MMS,
+ TRANSPORT_CELLULAR,
+ NET_CAPABILITY_MMS,
+ NET_CAPABILITY_NOT_VPN,
+ NET_CAPABILITY_TRUSTED);
+
+ assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeMobileSupl() {
+ final NetworkCapabilities nc = verifyNetworkCapabilities(
+ ConnectivityManager.TYPE_MOBILE_SUPL,
+ TRANSPORT_CELLULAR,
+ NET_CAPABILITY_SUPL,
+ NET_CAPABILITY_NOT_VPN,
+ NET_CAPABILITY_TRUSTED);
+
+ assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeWifi() {
+ verifyUnrestrictedNetworkCapabilities(
+ ConnectivityManager.TYPE_WIFI, TRANSPORT_WIFI);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeWifiP2p() {
+ final NetworkCapabilities nc = verifyNetworkCapabilities(
+ ConnectivityManager.TYPE_WIFI_P2P,
+ TRANSPORT_WIFI,
+ NET_CAPABILITY_NOT_RESTRICTED, NET_CAPABILITY_NOT_VPN,
+ NET_CAPABILITY_TRUSTED, NET_CAPABILITY_WIFI_P2P);
+
+ assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeBluetooth() {
+ verifyUnrestrictedNetworkCapabilities(
+ ConnectivityManager.TYPE_BLUETOOTH, TRANSPORT_BLUETOOTH);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesForTypeEthernet() {
+ verifyUnrestrictedNetworkCapabilities(
+ ConnectivityManager.TYPE_ETHERNET, TRANSPORT_ETHERNET);
+ }
+}
diff --git a/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java b/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java
deleted file mode 100644
index f89603052213..000000000000
--- a/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.os.Bundle;
-import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
-import java.util.List;
-import junit.framework.TestCase;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class ConnectivityMetricsLoggerTest extends TestCase {
-
- // use same Parcel object everywhere for pointer equality
- static final Bundle FAKE_EV = new Bundle();
- static final int FAKE_COMPONENT = 1;
- static final int FAKE_EVENT = 2;
-
- @Mock IConnectivityMetricsLogger mService;
- ArgumentCaptor<ConnectivityMetricsEvent> evCaptor;
- ArgumentCaptor<ConnectivityMetricsEvent[]> evArrayCaptor;
-
- ConnectivityMetricsLogger mLog;
-
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- evCaptor = ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
- evArrayCaptor = ArgumentCaptor.forClass(ConnectivityMetricsEvent[].class);
- mLog = new ConnectivityMetricsLogger(mService);
- }
-
- @SmallTest
- public void testLogEvents() throws Exception {
- mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- mLog.logEvent(3, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-
- List<ConnectivityMetricsEvent> gotEvents = verifyEvents(3);
- assertEventsEqual(expectedEvent(1), gotEvents.get(0));
- assertEventsEqual(expectedEvent(2), gotEvents.get(1));
- assertEventsEqual(expectedEvent(3), gotEvents.get(2));
- }
-
- @SmallTest
- public void testLogEventTriggerThrottling() throws Exception {
- when(mService.logEvent(any())).thenReturn(1234L);
-
- mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-
- List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
- assertEventsEqual(expectedEvent(1), gotEvents.get(0));
- }
-
- @SmallTest
- public void testLogEventFails() throws Exception {
- when(mService.logEvent(any())).thenReturn(-1L); // Error.
-
- mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-
- List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
- assertEventsEqual(expectedEvent(1), gotEvents.get(0));
- }
-
- @SmallTest
- public void testLogEventWhenThrottling() throws Exception {
- when(mService.logEvent(any())).thenReturn(Long.MAX_VALUE); // Throttled
-
- // No events are logged. The service is only called once
- // After that, throttling state is maintained locally.
- mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-
- List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
- assertEventsEqual(expectedEvent(1), gotEvents.get(0));
- }
-
- @SmallTest
- public void testLogEventRecoverFromThrottling() throws Exception {
- final long throttleTimeout = System.currentTimeMillis() + 10;
- when(mService.logEvent(any())).thenReturn(throttleTimeout, 0L);
-
- mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- mLog.logEvent(3, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- Thread.sleep(100);
- mLog.logEvent(53, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-
- List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
- assertEventsEqual(expectedEvent(1), gotEvents.get(0));
-
- verify(mService, times(1)).logEvents(evArrayCaptor.capture());
- ConnectivityMetricsEvent[] gotOtherEvents = evArrayCaptor.getAllValues().get(0);
- assertEquals(ConnectivityMetricsLogger.TAG_SKIPPED_EVENTS, gotOtherEvents[0].eventTag);
- assertEventsEqual(expectedEvent(53), gotOtherEvents[1]);
- }
-
- List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
- verify(mService, times(n)).logEvent(evCaptor.capture());
- return evCaptor.getAllValues();
- }
-
- static ConnectivityMetricsEvent expectedEvent(int timestamp) {
- return new ConnectivityMetricsEvent((long)timestamp, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- }
-
- /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
- static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
- assertEquals(expected.timestamp, got.timestamp);
- assertEquals(expected.componentTag, got.componentTag);
- assertEquals(expected.eventTag, got.eventTag);
- assertEquals(expected.data, got.data);
- }
-}
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index ff6175427ce7..91d6c6840f47 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -29,9 +29,11 @@ import android.net.metrics.IpConnectivityLog;
import android.net.metrics.RaEvent;
import android.os.ConditionVariable;
import android.os.Parcelable;
+import android.os.SystemClock;
import android.system.ErrnoException;
import android.system.Os;
import android.test.AndroidTestCase;
+import android.text.format.DateUtils;
import android.test.suitebuilder.annotation.SmallTest;
import static android.system.OsConstants.*;
@@ -604,6 +606,8 @@ public class ApfTest extends AndroidTestCase {
public final static byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
private FileDescriptor mWriteSocket;
+ private final long mFixedTimeMs = SystemClock.elapsedRealtime();
+
public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
IpConnectivityLog log) throws Exception {
super(new ApfCapabilities(2, 1700, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
@@ -617,6 +621,11 @@ public class ApfTest extends AndroidTestCase {
}
@Override
+ protected long currentTimeSeconds() {
+ return mFixedTimeMs / DateUtils.SECOND_IN_MILLIS;
+ }
+
+ @Override
void maybeStartFilter() {
mHardwareAddress = MOCK_MAC_ADDR;
installNewProgramLocked();
@@ -969,27 +978,30 @@ public class ApfTest extends AndroidTestCase {
// Verify that the last program pushed to the IpManager.Callback properly filters the
// given packet for the given lifetime.
- private void verifyRaLifetime(MockIpManagerCallback ipManagerCallback, ByteBuffer packet,
- int lifetime) {
- byte[] program = ipManagerCallback.getApfProgram();
+ private void verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime) {
+ final int FRACTION_OF_LIFETIME = 6;
+ final int ageLimit = lifetime / FRACTION_OF_LIFETIME;
- // Verify new program should drop RA for 1/6th its lifetime
+ // Verify new program should drop RA for 1/6th its lifetime and pass afterwards.
assertDrop(program, packet.array());
- assertDrop(program, packet.array(), lifetime/6);
- assertPass(program, packet.array(), lifetime/6 + 1);
+ assertDrop(program, packet.array(), ageLimit);
+ assertPass(program, packet.array(), ageLimit + 1);
assertPass(program, packet.array(), lifetime);
-
// Verify RA checksum is ignored
+ final short originalChecksum = packet.getShort(ICMP6_RA_CHECKSUM_OFFSET);
packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
assertDrop(program, packet.array());
packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
assertDrop(program, packet.array());
+ packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, originalChecksum);
// Verify other changes to RA make it not match filter
+ final byte originalFirstByte = packet.get(0);
packet.put(0, (byte)-1);
assertPass(program, packet.array());
packet.put(0, (byte)0);
assertDrop(program, packet.array());
+ packet.put(0, originalFirstByte);
}
// Test that when ApfFilter is shown the given packet, it generates a program to filter it
@@ -999,9 +1011,8 @@ public class ApfTest extends AndroidTestCase {
// Verify new program generated if ApfFilter witnesses RA
ipManagerCallback.resetApfProgramWait();
apfFilter.pretendPacketReceived(packet.array());
- ipManagerCallback.getApfProgram();
-
- verifyRaLifetime(ipManagerCallback, packet, lifetime);
+ byte[] program = ipManagerCallback.getApfProgram();
+ verifyRaLifetime(program, packet, lifetime);
}
private void verifyRaEvent(RaEvent expected) {
@@ -1046,18 +1057,26 @@ public class ApfTest extends AndroidTestCase {
TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
byte[] program = ipManagerCallback.getApfProgram();
+ final int ROUTER_LIFETIME = 1000;
+ final int PREFIX_VALID_LIFETIME = 200;
+ final int PREFIX_PREFERRED_LIFETIME = 100;
+ final int RDNSS_LIFETIME = 300;
+ final int ROUTE_LIFETIME = 400;
+ // Note that lifetime of 2000 will be ignored in favor of shorter route lifetime of 1000.
+ final int DNSSL_LIFETIME = 2000;
+
// Verify RA is passed the first time
ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT);
- basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)1000);
+ basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)ROUTER_LIFETIME);
basePacket.position(IPV6_DEST_ADDR_OFFSET);
basePacket.put(IPV6_ALL_NODES_ADDRESS);
assertPass(program, basePacket.array());
- testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000);
- verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, -1));
+ testRaLifetime(apfFilter, ipManagerCallback, basePacket, ROUTER_LIFETIME);
+ verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, -1));
// Ensure zero-length options cause the packet to be silently skipped.
// Do this before we test other packets. http://b/29586253
@@ -1079,11 +1098,14 @@ public class ApfTest extends AndroidTestCase {
prefixOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
prefixOptionPacket.put((byte)(ICMP6_PREFIX_OPTION_LEN / 8));
prefixOptionPacket.putInt(
- ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET, 100);
+ ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
+ PREFIX_PREFERRED_LIFETIME);
prefixOptionPacket.putInt(
- ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET, 200);
- testRaLifetime(apfFilter, ipManagerCallback, prefixOptionPacket, 100);
- verifyRaEvent(new RaEvent(1000, 200, 100, -1, -1, -1));
+ ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
+ PREFIX_VALID_LIFETIME);
+ testRaLifetime(apfFilter, ipManagerCallback, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
+ verifyRaEvent(new RaEvent(
+ ROUTER_LIFETIME, PREFIX_VALID_LIFETIME, PREFIX_PREFERRED_LIFETIME, -1, -1, -1));
ByteBuffer rdnssOptionPacket = ByteBuffer.wrap(
new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
@@ -1092,9 +1114,9 @@ public class ApfTest extends AndroidTestCase {
rdnssOptionPacket.put((byte)ICMP6_RDNSS_OPTION_TYPE);
rdnssOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
rdnssOptionPacket.putInt(
- ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 300);
- testRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, 300);
- verifyRaEvent(new RaEvent(1000, -1, -1, -1, 300, -1));
+ ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, RDNSS_LIFETIME);
+ testRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, RDNSS_LIFETIME);
+ verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, RDNSS_LIFETIME, -1));
ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap(
new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
@@ -1103,9 +1125,9 @@ public class ApfTest extends AndroidTestCase {
routeInfoOptionPacket.put((byte)ICMP6_ROUTE_INFO_OPTION_TYPE);
routeInfoOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
routeInfoOptionPacket.putInt(
- ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 400);
- testRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, 400);
- verifyRaEvent(new RaEvent(1000, -1, -1, 400, -1, -1));
+ ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, ROUTE_LIFETIME);
+ testRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, ROUTE_LIFETIME);
+ verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, ROUTE_LIFETIME, -1, -1));
ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(
new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
@@ -1114,18 +1136,17 @@ public class ApfTest extends AndroidTestCase {
dnsslOptionPacket.put((byte)ICMP6_DNSSL_OPTION_TYPE);
dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
dnsslOptionPacket.putInt(
- ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 2000);
- // Note that lifetime of 2000 will be ignored in favor of shorter
- // route lifetime of 1000.
- testRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, 1000);
- verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, 2000));
+ ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, DNSSL_LIFETIME);
+ testRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, ROUTER_LIFETIME);
+ verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, DNSSL_LIFETIME));
// Verify that current program filters all five RAs:
- verifyRaLifetime(ipManagerCallback, basePacket, 1000);
- verifyRaLifetime(ipManagerCallback, prefixOptionPacket, 100);
- verifyRaLifetime(ipManagerCallback, rdnssOptionPacket, 300);
- verifyRaLifetime(ipManagerCallback, routeInfoOptionPacket, 400);
- verifyRaLifetime(ipManagerCallback, dnsslOptionPacket, 1000);
+ program = ipManagerCallback.getApfProgram();
+ verifyRaLifetime(program, basePacket, ROUTER_LIFETIME);
+ verifyRaLifetime(program, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
+ verifyRaLifetime(program, rdnssOptionPacket, RDNSS_LIFETIME);
+ verifyRaLifetime(program, routeInfoOptionPacket, ROUTE_LIFETIME);
+ verifyRaLifetime(program, dnsslOptionPacket, ROUTER_LIFETIME);
apfFilter.shutdown();
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 46b64031ee8a..39406a117410 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -53,7 +53,7 @@ import android.net.NetworkMisc;
import android.net.NetworkRequest;
import android.net.RouteInfo;
import android.net.metrics.IpConnectivityLog;
-import android.net.util.AvoidBadWifiTracker;
+import android.net.util.MultinetworkPolicyTracker;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
@@ -68,7 +68,6 @@ import android.os.Process;
import android.os.SystemClock;
import android.provider.Settings;
import android.test.AndroidTestCase;
-import android.test.FlakyTest;
import android.test.mock.MockContentResolver;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
@@ -154,49 +153,20 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
/**
- * A subclass of HandlerThread that allows callers to wait for it to become idle. waitForIdle
- * will return immediately if the handler is already idle.
+ * Block until the given handler becomes idle, or until timeoutMs has passed.
*/
- private class IdleableHandlerThread extends HandlerThread {
- private IdleHandler mIdleHandler;
-
- public IdleableHandlerThread(String name) {
- super(name);
- }
-
- public void waitForIdle(int timeoutMs) {
- final ConditionVariable cv = new ConditionVariable();
- final MessageQueue queue = getLooper().getQueue();
-
- synchronized (queue) {
- if (queue.isIdle()) {
- return;
- }
-
- assertNull("BUG: only one idle handler allowed", mIdleHandler);
- mIdleHandler = new IdleHandler() {
- public boolean queueIdle() {
- synchronized (queue) {
- cv.open();
- mIdleHandler = null;
- return false; // Remove the handler.
- }
- }
- };
- queue.addIdleHandler(mIdleHandler);
- }
-
- if (!cv.block(timeoutMs)) {
- fail("HandlerThread " + getName() +
- " did not become idle after " + timeoutMs + " ms");
- queue.removeIdleHandler(mIdleHandler);
- }
+ private static void waitForIdleHandler(HandlerThread handlerThread, int timeoutMs) {
+ final ConditionVariable cv = new ConditionVariable();
+ final Handler handler = new Handler(handlerThread.getLooper());
+ handler.post(() -> cv.open());
+ if (!cv.block(timeoutMs)) {
+ fail("HandlerThread " + handlerThread.getName() +
+ " did not become idle after " + timeoutMs + " ms");
}
}
- // Tests that IdleableHandlerThread works as expected.
@SmallTest
- public void testIdleableHandlerThread() {
+ public void testWaitForIdle() {
final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng.
// Tests that waitForIdle returns immediately if the service is already idle.
@@ -220,9 +190,9 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
}
- @SmallTest
- @FlakyTest(tolerance = 3)
- public void testNotWaitingForIdleCausesRaceConditions() {
+ // This test has an inherent race condition in it, and cannot be enabled for continuous testing
+ // or presubmit tests. It is kept for manual runs and documentation purposes.
+ public void verifyThatNotWaitingForIdleCausesRaceConditions() {
// Bring up a network that we can use to send messages to ConnectivityService.
ConditionVariable cv = waitForConnectivityBroadcasts(1);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -249,7 +219,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
private final WrappedNetworkMonitor mWrappedNetworkMonitor;
private final NetworkInfo mNetworkInfo;
private final NetworkCapabilities mNetworkCapabilities;
- private final IdleableHandlerThread mHandlerThread;
+ private final HandlerThread mHandlerThread;
private final ConditionVariable mDisconnected = new ConditionVariable();
private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
@@ -281,7 +251,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
default:
throw new UnsupportedOperationException("unimplemented network type");
}
- mHandlerThread = new IdleableHandlerThread("Mock-" + typeName);
+ mHandlerThread = new HandlerThread("Mock-" + typeName);
mHandlerThread.start();
mNetworkAgent = new NetworkAgent(mHandlerThread.getLooper(), mServiceContext,
"Mock-" + typeName, mNetworkInfo, mNetworkCapabilities,
@@ -321,7 +291,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
public void waitForIdle(int timeoutMs) {
- mHandlerThread.waitForIdle(timeoutMs);
+ waitForIdleHandler(mHandlerThread, timeoutMs);
}
public void waitForIdle() {
@@ -623,10 +593,10 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
}
- private class WrappedAvoidBadWifiTracker extends AvoidBadWifiTracker {
+ private class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
public volatile boolean configRestrictsAvoidBadWifi;
- public WrappedAvoidBadWifiTracker(Context c, Handler h, Runnable r) {
+ public WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
super(c, h, r);
}
@@ -637,7 +607,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
private class WrappedConnectivityService extends ConnectivityService {
- public WrappedAvoidBadWifiTracker wrappedAvoidBadWifiTracker;
+ public WrappedMultinetworkPolicyTracker wrappedMultinetworkPolicyTracker;
private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
public WrappedConnectivityService(Context context, INetworkManagementService netManager,
@@ -648,11 +618,6 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
@Override
- protected HandlerThread createHandlerThread() {
- return new IdleableHandlerThread("WrappedConnectivityService");
- }
-
- @Override
protected int getDefaultTcpRwnd() {
// Prevent wrapped ConnectivityService from trying to write to SystemProperties.
return 0;
@@ -689,14 +654,14 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
@Override
- public AvoidBadWifiTracker createAvoidBadWifiTracker(
+ public MultinetworkPolicyTracker createMultinetworkPolicyTracker(
Context c, Handler h, Runnable r) {
- final WrappedAvoidBadWifiTracker tracker = new WrappedAvoidBadWifiTracker(c, h, r);
+ final WrappedMultinetworkPolicyTracker tracker = new WrappedMultinetworkPolicyTracker(c, h, r);
return tracker;
}
- public WrappedAvoidBadWifiTracker getAvoidBadWifiTracker() {
- return (WrappedAvoidBadWifiTracker) mAvoidBadWifiTracker;
+ public WrappedMultinetworkPolicyTracker getMultinetworkPolicyTracker() {
+ return (WrappedMultinetworkPolicyTracker) mMultinetworkPolicyTracker;
}
@Override
@@ -710,7 +675,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
public void waitForIdle(int timeoutMs) {
- ((IdleableHandlerThread) mHandlerThread).waitForIdle(timeoutMs);
+ waitForIdleHandler(mHandlerThread, timeoutMs);
}
public void waitForIdle() {
@@ -718,22 +683,6 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
}
- private interface Criteria {
- public boolean get();
- }
-
- /**
- * Wait up to 500ms for {@code criteria.get()} to become true, polling.
- * Fails if 500ms goes by before {@code criteria.get()} to become true.
- */
- static private void waitFor(Criteria criteria) {
- int delays = 0;
- while (!criteria.get()) {
- sleepFor(50);
- if (++delays == 10) fail();
- }
- }
-
/**
* Wait up to TIMEOUT_MS for {@code conditionVariable} to open.
* Fails if TIMEOUT_MS goes by before {@code conditionVariable} opens.
@@ -869,8 +818,9 @@ public class ConnectivityServiceTest extends AndroidTestCase {
assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) ||
mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork()));
// Test cellular linger timeout.
- waitFor(new Criteria() {
- public boolean get() { return mCm.getAllNetworks().length == 1; } });
+ waitFor(mCellNetworkAgent.getDisconnectedCV());
+ mService.waitForIdle();
+ assertEquals(1, mCm.getAllNetworks().length);
verifyActiveNetwork(TRANSPORT_WIFI);
assertEquals(1, mCm.getAllNetworks().length);
assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork());
@@ -1135,7 +1085,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Chosen to be much less than the linger timeout. This ensures that we can distinguish
// between a LOST callback that arrives immediately and a LOST callback that arrives after
// the linger timeout.
- private final static int TIMEOUT_MS = 50;
+ private final static int TIMEOUT_MS = 100;
private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>();
@@ -1487,8 +1437,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Let linger run its course.
callback.assertNoCallback();
- callback.expectCallback(CallbackState.LOST, mCellNetworkAgent,
- TEST_LINGER_DELAY_MS /* timeoutMs */);
+ final int lingerTimeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
+ callback.expectCallback(CallbackState.LOST, mCellNetworkAgent, lingerTimeoutMs);
// Clean up.
mWiFiNetworkAgent.disconnect();
@@ -1645,8 +1595,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
ConditionVariable cv = mCellNetworkAgent.getDisconnectedCV();
mCellNetworkAgent.connectWithoutInternet();
waitFor(cv);
- waitFor(new Criteria() {
- public boolean get() { return mCm.getAllNetworks().length == 0; } });
+ mService.waitForIdle();
+ assertEquals(0, mCm.getAllNetworks().length);
verifyNoNetwork();
// Test bringing up validated WiFi.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -1977,7 +1927,9 @@ public class ConnectivityServiceTest extends AndroidTestCase {
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
// When lingering is complete, cell is still there but is now in the background.
- fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, TEST_LINGER_DELAY_MS);
+ mService.waitForIdle();
+ int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
+ fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, timeoutMs);
callback.assertNoCallback();
assertFalse(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -2172,7 +2124,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
@SmallTest
public void testAvoidBadWifiSetting() throws Exception {
final ContentResolver cr = mServiceContext.getContentResolver();
- final WrappedAvoidBadWifiTracker tracker = mService.getAvoidBadWifiTracker();
+ final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
final String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
tracker.configRestrictsAvoidBadWifi = false;
@@ -2182,7 +2134,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
tracker.reevaluate();
mService.waitForIdle();
String msg = String.format("config=false, setting=%s", values[i]);
- assertEventuallyTrue(() -> mService.avoidBadWifi(), 50);
+ assertTrue(mService.avoidBadWifi());
assertFalse(msg, tracker.shouldNotifyWifiUnvalidated());
}
@@ -2191,26 +2143,26 @@ public class ConnectivityServiceTest extends AndroidTestCase {
Settings.Global.putInt(cr, settingName, 0);
tracker.reevaluate();
mService.waitForIdle();
- assertEventuallyTrue(() -> !mService.avoidBadWifi(), 50);
+ assertFalse(mService.avoidBadWifi());
assertFalse(tracker.shouldNotifyWifiUnvalidated());
Settings.Global.putInt(cr, settingName, 1);
tracker.reevaluate();
mService.waitForIdle();
- assertEventuallyTrue(() -> mService.avoidBadWifi(), 50);
+ assertTrue(mService.avoidBadWifi());
assertFalse(tracker.shouldNotifyWifiUnvalidated());
Settings.Global.putString(cr, settingName, null);
tracker.reevaluate();
mService.waitForIdle();
- assertEventuallyTrue(() -> !mService.avoidBadWifi(), 50);
+ assertFalse(mService.avoidBadWifi());
assertTrue(tracker.shouldNotifyWifiUnvalidated());
}
@SmallTest
public void testAvoidBadWifi() throws Exception {
final ContentResolver cr = mServiceContext.getContentResolver();
- final WrappedAvoidBadWifiTracker tracker = mService.getAvoidBadWifiTracker();
+ final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
// Pretend we're on a carrier that restricts switching away from bad wifi.
tracker.configRestrictsAvoidBadWifi = true;
@@ -2339,14 +2291,14 @@ public class ConnectivityServiceTest extends AndroidTestCase {
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(nr, networkCallback, 10);
+ final int timeoutMs = 150;
+ mCm.requestNetwork(nr, networkCallback, timeoutMs);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent, timeoutMs);
// pass timeout and validate that UNAVAILABLE is not called
- sleepFor(15);
networkCallback.assertNoCallback();
}
@@ -2359,17 +2311,19 @@ public class ConnectivityServiceTest extends AndroidTestCase {
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(nr, networkCallback, 500);
+ final int requestTimeoutMs = 100;
+ mCm.requestNetwork(nr, networkCallback, requestTimeoutMs);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ final int assertTimeoutMs = 150;
+ networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent, assertTimeoutMs);
sleepFor(20);
mWiFiNetworkAgent.disconnect();
networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// pass timeout and validate that UNAVAILABLE is not called
- sleepFor(600);
+ sleepFor(100);
networkCallback.assertNoCallback();
}
@@ -2383,7 +2337,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(nr, networkCallback, 10);
+ final int timeoutMs = 10;
+ mCm.requestNetwork(nr, networkCallback, timeoutMs);
// pass timeout and validate that UNAVAILABLE is called
networkCallback.expectCallback(CallbackState.UNAVAILABLE, null);
@@ -2403,7 +2358,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(nr, networkCallback, 10);
+ final int timeoutMs = 10;
+ mCm.requestNetwork(nr, networkCallback, timeoutMs);
// remove request
mCm.unregisterNetworkCallback(networkCallback);
@@ -2420,17 +2376,6 @@ public class ConnectivityServiceTest extends AndroidTestCase {
networkCallback.assertNoCallback();
}
- public void assertEventuallyTrue(BooleanSupplier fn, long maxWaitingTimeMs) throws Exception {
- long start = SystemClock.elapsedRealtime();
- while (SystemClock.elapsedRealtime() <= start + maxWaitingTimeMs) {
- if (fn.getAsBoolean()) {
- return;
- }
- Thread.sleep(10);
- }
- assertTrue(fn.getAsBoolean());
- }
-
private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
@@ -2591,10 +2536,13 @@ public class ConnectivityServiceTest extends AndroidTestCase {
ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
callback.expectStarted();
mWiFiNetworkAgent.disconnect();
+ waitFor(mWiFiNetworkAgent.getDisconnectedCV());
callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
// ... and that stopping it after that has no adverse effects.
- assertNull(mCm.getNetworkCapabilities(myNet));
+ mService.waitForIdle();
+ final Network myNetAlias = myNet;
+ assertNull(mCm.getNetworkCapabilities(myNetAlias));
ka.stop();
// Reconnect.
@@ -2606,6 +2554,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
callback.expectStarted();
ka.stop();
mWiFiNetworkAgent.disconnect();
+ waitFor(mWiFiNetworkAgent.getDisconnectedCV());
mService.waitForIdle();
callback.expectStopped();
@@ -2838,11 +2787,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
/* test utilities */
+ // TODO: eliminate all usages of sleepFor and replace by proper timeouts/waitForIdle.
static private void sleepFor(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
}
-
}
}
diff --git a/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java b/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java
deleted file mode 100644
index 5981f48e7ccd..000000000000
--- a/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import android.content.Context;
-import android.net.ConnectivityMetricsEvent;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.test.suitebuilder.annotation.SmallTest;
-import static android.net.ConnectivityMetricsEvent.Reference;
-
-import junit.framework.TestCase;
-import org.junit.Before;
-import org.junit.Test;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertArrayEquals;
-
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/*
- * TODO:
- * - allow overriding MetricsLoggerService constants in tests.
- * - test intents are correctly sent after the notification threshold.
- * - test oldest events are correctly pushed out when internal deque is full.
- * - test throttling triggers correctly.
- */
-public class MetricsLoggerServiceTest extends TestCase {
-
- static final int COMPONENT_TAG = 1;
- static final long N_EVENTS = 10L;
- static final ConnectivityMetricsEvent EVENTS[] = new ConnectivityMetricsEvent[(int)N_EVENTS];
- static {
- for (int i = 0; i < N_EVENTS; i++) {
- EVENTS[i] = new ConnectivityMetricsEvent(i, COMPONENT_TAG, i, new Bundle());
- }
- }
-
- static final ConnectivityMetricsEvent NO_EVENTS[] = new ConnectivityMetricsEvent[0];
-
- @Mock Context mContext;
- MetricsLoggerService mService;
-
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mService = new MetricsLoggerService(mContext);
- mService.onStart();
- }
-
- @SmallTest
- public void testGetNoEvents() throws Exception {
- Reference r = new Reference(0);
- assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
- assertEquals(0, r.getValue());
- }
-
- @SmallTest
- public void testLogAndGetEvents() throws Exception {
- mService.mBinder.logEvents(EVENTS);
-
- Reference r = new Reference(0);
-
- assertArrayEquals(EVENTS, mService.mBinder.getEvents(r));
- assertEquals(N_EVENTS, r.getValue());
-
- assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
- assertEquals(N_EVENTS, r.getValue());
- }
-
- @SmallTest
- public void testLogOneByOne() throws Exception {
- for (ConnectivityMetricsEvent ev : EVENTS) {
- mService.mBinder.logEvent(ev);
- }
-
- Reference r = new Reference(0);
-
- assertArrayEquals(EVENTS, mService.mBinder.getEvents(r));
- assertEquals(N_EVENTS, r.getValue());
-
- assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
- assertEquals(N_EVENTS, r.getValue());
- }
-
- @SmallTest
- public void testInterleavedLogAndGet() throws Exception {
- mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 0, 3));
-
- Reference r = new Reference(0);
-
- assertArrayEquals(Arrays.copyOfRange(EVENTS, 0, 3), mService.mBinder.getEvents(r));
- assertEquals(3, r.getValue());
-
- mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 3, 8));
- mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 8, 10));
-
- assertArrayEquals(Arrays.copyOfRange(EVENTS, 3, 10), mService.mBinder.getEvents(r));
- assertEquals(N_EVENTS, r.getValue());
-
- assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
- assertEquals(N_EVENTS, r.getValue());
- }
-
- @SmallTest
- public void testMultipleGetAll() throws Exception {
- mService.mBinder.logEvents(Arrays.copyOf(EVENTS, 3));
-
- Reference r1 = new Reference(0);
- assertArrayEquals(Arrays.copyOf(EVENTS, 3), mService.mBinder.getEvents(r1));
- assertEquals(3, r1.getValue());
-
- mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 3, 10));
-
- Reference r2 = new Reference(0);
- assertArrayEquals(EVENTS, mService.mBinder.getEvents(r2));
- assertEquals(N_EVENTS, r2.getValue());
- }
-
- @SmallTest
- public void testLogAndDumpConcurrently() throws Exception {
- for (int i = 0; i < 50; i++) {
- mContext = null;
- mService = null;
- setUp();
- logAndDumpConcurrently();
- }
- }
-
- public void logAndDumpConcurrently() throws Exception {
- final CountDownLatch latch = new CountDownLatch((int)N_EVENTS);
- final FileDescriptor fd = new FileOutputStream("/dev/null").getFD();
-
- for (ConnectivityMetricsEvent ev : EVENTS) {
- new Thread() {
- public void run() {
- mService.mBinder.logEvent(ev);
- latch.countDown();
- }
- }.start();
- }
-
- new Thread() {
- public void run() {
- while (latch.getCount() > 0) {
- mService.mBinder.dump(fd, new String[]{"--all"});
- }
- }
- }.start();
-
- latch.await(100, TimeUnit.MILLISECONDS);
-
- Reference r = new Reference(0);
- ConnectivityMetricsEvent[] got = mService.mBinder.getEvents(r);
- Arrays.sort(got, new EventComparator());
- assertArrayEquals(EVENTS, got);
- assertEquals(N_EVENTS, r.getValue());
- }
-
- static class EventComparator implements Comparator<ConnectivityMetricsEvent> {
- public int compare(ConnectivityMetricsEvent ev1, ConnectivityMetricsEvent ev2) {
- return Long.compare(ev1.timestamp, ev2.timestamp);
- }
- public boolean equal(Object o) {
- return o instanceof EventComparator;
- }
- };
-}
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
index 9f7261dc6019..32e1b96cf798 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -28,6 +28,9 @@ import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
+import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
+import static android.net.ConnectivityManager.TETHERING_USB;
+import static android.net.ConnectivityManager.TETHERING_WIFI;
import static com.android.server.connectivity.tethering.IControlsTethering.STATE_AVAILABLE;
import static com.android.server.connectivity.tethering.IControlsTethering.STATE_TETHERED;
import static com.android.server.connectivity.tethering.IControlsTethering.STATE_UNAVAILABLE;
@@ -92,7 +95,7 @@ public class TetherInterfaceStateMachineTest {
@Test
public void startsOutAvailable() {
mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
- ConnectivityManager.TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper,
+ TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper,
mIPv6TetheringInterfaceServices);
mTestedSm.start();
mLooper.dispatchAll();
@@ -103,7 +106,7 @@ public class TetherInterfaceStateMachineTest {
@Test
public void shouldDoNothingUntilRequested() throws Exception {
- initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH);
+ initStateMachine(TETHERING_BLUETOOTH);
final int [] NOOP_COMMANDS = {
TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED,
TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR,
@@ -123,7 +126,7 @@ public class TetherInterfaceStateMachineTest {
@Test
public void handlesImmediateInterfaceDown() throws Exception {
- initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH);
+ initStateMachine(TETHERING_BLUETOOTH);
dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
verify(mTetherHelper).notifyInterfaceStateChange(
@@ -133,7 +136,7 @@ public class TetherInterfaceStateMachineTest {
@Test
public void canBeTethered() throws Exception {
- initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH);
+ initStateMachine(TETHERING_BLUETOOTH);
dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
InOrder inOrder = inOrder(mTetherHelper, mNMService);
@@ -145,7 +148,7 @@ public class TetherInterfaceStateMachineTest {
@Test
public void canUnrequestTethering() throws Exception {
- initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, null);
+ initTetheredStateMachine(TETHERING_BLUETOOTH, null);
dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
@@ -157,7 +160,7 @@ public class TetherInterfaceStateMachineTest {
@Test
public void canBeTetheredAsUsb() throws Exception {
- initStateMachine(ConnectivityManager.TETHERING_USB);
+ initStateMachine(TETHERING_USB);
dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
InOrder inOrder = inOrder(mTetherHelper, mNMService);
@@ -171,7 +174,7 @@ public class TetherInterfaceStateMachineTest {
@Test
public void handlesFirstUpstreamChange() throws Exception {
- initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, null);
+ initTetheredStateMachine(TETHERING_BLUETOOTH, null);
// Telling the state machine about its upstream interface triggers a little more configuration.
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
@@ -183,7 +186,7 @@ public class TetherInterfaceStateMachineTest {
@Test
public void handlesChangingUpstream() throws Exception {
- initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, UPSTREAM_IFACE);
+ initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
InOrder inOrder = inOrder(mNMService, mStatsService);
@@ -196,8 +199,44 @@ public class TetherInterfaceStateMachineTest {
}
@Test
+ public void handlesChangingUpstreamNatFailure() throws Exception {
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
+
+ doThrow(RemoteException.class).when(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
+
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
+ InOrder inOrder = inOrder(mNMService, mStatsService);
+ inOrder.verify(mStatsService).forceUpdate();
+ inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mStatsService).forceUpdate();
+ inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2);
+ }
+
+ @Test
+ public void handlesChangingUpstreamInterfaceForwardingFailure() throws Exception {
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
+
+ doThrow(RemoteException.class).when(mNMService).startInterfaceForwarding(
+ IFACE_NAME, UPSTREAM_IFACE2);
+
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
+ InOrder inOrder = inOrder(mNMService, mStatsService);
+ inOrder.verify(mStatsService).forceUpdate();
+ inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mStatsService).forceUpdate();
+ inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2);
+ }
+
+ @Test
public void canUnrequestTetheringWithUpstream() throws Exception {
- initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, UPSTREAM_IFACE);
+ initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
@@ -213,7 +252,7 @@ public class TetherInterfaceStateMachineTest {
@Test
public void interfaceDownLeadsToUnavailable() throws Exception {
for (boolean shouldThrow : new boolean[]{true, false}) {
- initTetheredStateMachine(ConnectivityManager.TETHERING_USB, null);
+ initTetheredStateMachine(TETHERING_USB, null);
if (shouldThrow) {
doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME);
@@ -230,7 +269,7 @@ public class TetherInterfaceStateMachineTest {
@Test
public void usbShouldBeTornDownOnTetherError() throws Exception {
- initStateMachine(ConnectivityManager.TETHERING_USB);
+ initStateMachine(TETHERING_USB);
doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME);
dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
@@ -244,7 +283,7 @@ public class TetherInterfaceStateMachineTest {
@Test
public void shouldTearDownUsbOnUpstreamError() throws Exception {
- initTetheredStateMachine(ConnectivityManager.TETHERING_USB, null);
+ initTetheredStateMachine(TETHERING_USB, null);
doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString());
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
@@ -255,6 +294,18 @@ public class TetherInterfaceStateMachineTest {
IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
}
+ @Test
+ public void ignoresDuplicateUpstreamNotifications() throws Exception {
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
+
+ verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+
+ for (int i = 0; i < 5; i++) {
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE);
+ verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+ }
+ }
+
/**
* Send a command to the state machine under test, and run the event loop to idle.
*
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index 1e67769277da..c72efb0344d1 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -23,9 +23,17 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.IConnectivityManager;
@@ -36,12 +44,18 @@ import android.net.NetworkRequest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.junit.Test;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -56,6 +70,7 @@ public class UpstreamNetworkMonitorTest {
@Mock private Context mContext;
@Mock private IConnectivityManager mCS;
+ private TestStateMachine mSM;
private TestConnectivityManager mCM;
private UpstreamNetworkMonitor mUNM;
@@ -64,8 +79,16 @@ public class UpstreamNetworkMonitorTest {
reset(mContext);
reset(mCS);
- mCM = new TestConnectivityManager(mContext, mCS);
- mUNM = new UpstreamNetworkMonitor(null, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
+ mCM = spy(new TestConnectivityManager(mContext, mCS));
+ mSM = new TestStateMachine();
+ mUNM = new UpstreamNetworkMonitor(mSM, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
+ }
+
+ @After public void tearDown() throws Exception {
+ if (mSM != null) {
+ mSM.quit();
+ mSM = null;
+ }
}
@Test
@@ -91,12 +114,12 @@ public class UpstreamNetworkMonitorTest {
}
@Test
- public void testListensForDunNetworks() throws Exception {
+ public void testListensForAllNetworks() throws Exception {
assertTrue(mCM.listening.isEmpty());
mUNM.start();
assertFalse(mCM.listening.isEmpty());
- assertTrue(mCM.isListeningForDun());
+ assertTrue(mCM.isListeningForAll());
mUNM.stop();
assertTrue(mCM.hasNoCallbacks());
@@ -126,6 +149,44 @@ public class UpstreamNetworkMonitorTest {
}
@Test
+ public void testDuplicateMobileRequestsIgnored() throws Exception {
+ assertFalse(mUNM.mobileNetworkRequested());
+ assertEquals(0, mCM.requested.size());
+
+ mUNM.start();
+ verify(mCM, Mockito.times(1)).registerNetworkCallback(
+ any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
+ verify(mCM, Mockito.times(1)).registerDefaultNetworkCallback(
+ any(NetworkCallback.class), any(Handler.class));
+ assertFalse(mUNM.mobileNetworkRequested());
+ assertEquals(0, mCM.requested.size());
+
+ mUNM.updateMobileRequiresDun(true);
+ mUNM.registerMobileNetworkRequest();
+ verify(mCM, Mockito.times(1)).requestNetwork(
+ any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt(),
+ any(Handler.class));
+
+ assertTrue(mUNM.mobileNetworkRequested());
+ assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
+ assertTrue(mCM.isDunRequested());
+
+ // Try a few things that must not result in any state change.
+ mUNM.registerMobileNetworkRequest();
+ mUNM.updateMobileRequiresDun(true);
+ mUNM.registerMobileNetworkRequest();
+
+ assertTrue(mUNM.mobileNetworkRequested());
+ assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
+ assertTrue(mCM.isDunRequested());
+
+ mUNM.stop();
+ verify(mCM, times(3)).unregisterNetworkCallback(any(NetworkCallback.class));
+
+ verifyNoMoreInteractions(mCM);
+ }
+
+ @Test
public void testRequestsDunNetwork() throws Exception {
assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size());
@@ -149,7 +210,7 @@ public class UpstreamNetworkMonitorTest {
}
@Test
- public void testUpdateMobileRequiredDun() throws Exception {
+ public void testUpdateMobileRequiresDun() throws Exception {
mUNM.start();
// Test going from no-DUN to DUN correctly re-registers callbacks.
@@ -180,7 +241,8 @@ public class UpstreamNetworkMonitorTest {
mCM.legacyTypeMap.values().iterator().next());
}
- private static class TestConnectivityManager extends ConnectivityManager {
+ public static class TestConnectivityManager extends ConnectivityManager {
+ public Map<NetworkCallback, Handler> allCallbacks = new HashMap<>();
public Set<NetworkCallback> trackingDefault = new HashSet<>();
public Map<NetworkCallback, NetworkRequest> listening = new HashMap<>();
public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>();
@@ -191,15 +253,19 @@ public class UpstreamNetworkMonitorTest {
}
boolean hasNoCallbacks() {
- return trackingDefault.isEmpty() &&
+ return allCallbacks.isEmpty() &&
+ trackingDefault.isEmpty() &&
listening.isEmpty() &&
requested.isEmpty() &&
legacyTypeMap.isEmpty();
}
- boolean isListeningForDun() {
+ boolean isListeningForAll() {
+ final NetworkCapabilities empty = new NetworkCapabilities();
+ empty.clearAll();
+
for (NetworkRequest req : listening.values()) {
- if (req.networkCapabilities.hasCapability(NET_CAPABILITY_DUN)) {
+ if (req.networkCapabilities.equalRequestableCapabilities(empty)) {
return true;
}
}
@@ -216,14 +282,23 @@ public class UpstreamNetworkMonitorTest {
}
@Override
- public void requestNetwork(NetworkRequest req, NetworkCallback cb) {
+ public void requestNetwork(NetworkRequest req, NetworkCallback cb, Handler h) {
+ assertFalse(allCallbacks.containsKey(cb));
+ allCallbacks.put(cb, h);
assertFalse(requested.containsKey(cb));
requested.put(cb, req);
}
@Override
+ public void requestNetwork(NetworkRequest req, NetworkCallback cb) {
+ fail("Should never be called.");
+ }
+
+ @Override
public void requestNetwork(NetworkRequest req, NetworkCallback cb,
- int timeoutMs, int legacyType) {
+ int timeoutMs, int legacyType, Handler h) {
+ assertFalse(allCallbacks.containsKey(cb));
+ allCallbacks.put(cb, h);
assertFalse(requested.containsKey(cb));
requested.put(cb, req);
assertFalse(legacyTypeMap.containsKey(cb));
@@ -233,18 +308,32 @@ public class UpstreamNetworkMonitorTest {
}
@Override
- public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) {
+ public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb, Handler h) {
+ assertFalse(allCallbacks.containsKey(cb));
+ allCallbacks.put(cb, h);
assertFalse(listening.containsKey(cb));
listening.put(cb, req);
}
@Override
- public void registerDefaultNetworkCallback(NetworkCallback cb) {
+ public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) {
+ fail("Should never be called.");
+ }
+
+ @Override
+ public void registerDefaultNetworkCallback(NetworkCallback cb, Handler h) {
+ assertFalse(allCallbacks.containsKey(cb));
+ allCallbacks.put(cb, h);
assertFalse(trackingDefault.contains(cb));
trackingDefault.add(cb);
}
@Override
+ public void registerDefaultNetworkCallback(NetworkCallback cb) {
+ fail("Should never be called.");
+ }
+
+ @Override
public void unregisterNetworkCallback(NetworkCallback cb) {
if (trackingDefault.contains(cb)) {
trackingDefault.remove(cb);
@@ -256,10 +345,35 @@ public class UpstreamNetworkMonitorTest {
} else {
fail("Unexpected callback removed");
}
+ allCallbacks.remove(cb);
+ assertFalse(allCallbacks.containsKey(cb));
assertFalse(trackingDefault.contains(cb));
assertFalse(listening.containsKey(cb));
assertFalse(requested.containsKey(cb));
}
}
+
+ public static class TestStateMachine extends StateMachine {
+ public final ArrayList<Message> messages = new ArrayList<>();
+ private final State mLoggingState = new LoggingState();
+
+ class LoggingState extends State {
+ @Override public void enter() { messages.clear(); }
+
+ @Override public void exit() { messages.clear(); }
+
+ @Override public boolean processMessage(Message msg) {
+ messages.add(msg);
+ return true;
+ }
+ }
+
+ public TestStateMachine() {
+ super("UpstreamNetworkMonitor.TestStateMachine");
+ addState(mLoggingState);
+ setInitialState(mLoggingState);
+ super.start();
+ }
+ }
}
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index 7ec46a3ee86b..c5598f0d87ed 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -14,7 +14,9 @@ EMOJI_VS = 0xFE0F
LANG_TO_SCRIPT = {
'as': 'Beng',
+ 'bg': 'Cyrl',
'bn': 'Beng',
+ 'cu': 'Cyrl',
'cy': 'Latn',
'da': 'Latn',
'de': 'Latn',
diff --git a/tools/layoutlib/create/Android.mk b/tools/layoutlib/create/Android.mk
index c7f2c4137687..7611cde3f392 100644
--- a/tools/layoutlib/create/Android.mk
+++ b/tools/layoutlib/create/Android.mk
@@ -20,7 +20,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under,src)
LOCAL_JAR_MANIFEST := manifest.txt
LOCAL_STATIC_JAVA_LIBRARIES := \
- asm-5.0
+ asm-5.2
LOCAL_MODULE := layoutlib_create
diff --git a/tools/layoutlib/create/tests/Android.mk b/tools/layoutlib/create/tests/Android.mk
index 61e381d48b16..488d7d6cc18d 100644
--- a/tools/layoutlib/create/tests/Android.mk
+++ b/tools/layoutlib/create/tests/Android.mk
@@ -24,7 +24,7 @@ LOCAL_MODULE := layoutlib-create-tests
LOCAL_MODULE_TAGS := optional
LOCAL_JAVA_LIBRARIES := layoutlib_create junit-host
-LOCAL_STATIC_JAVA_LIBRARIES := asm-5.0
+LOCAL_STATIC_JAVA_LIBRARIES := asm-5.2
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 3a4567112704..2ba573c0cb3a 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -305,7 +305,9 @@ public class WifiConfiguration implements Parcelable {
/**
* Priority determines the preference given to a network by {@code wpa_supplicant}
* when choosing an access point with which to associate.
+ * @deprecated Priority is no longer used.
*/
+ @Deprecated
public int priority;
/**
@@ -373,6 +375,12 @@ public class WifiConfiguration implements Parcelable {
public String providerFriendlyName;
/**
+ * Flag indicating if this network is provided by a home Passpoint provider or a roaming
+ * Passpoint provider.
+ */
+ public boolean isHomeProviderNetwork;
+
+ /**
* Roaming Consortium Id list for passpoint credential; identifies a set of networks where
* passpoint credential will be considered valid
*/
@@ -837,6 +845,7 @@ public class WifiConfiguration implements Parcelable {
* This network is disabled because EAP-TLS failure
*/
public static final int DISABLED_TLS_VERSION_MISMATCH = 7;
+ // Values above are for temporary disablement; values below are for permanent disablement.
/**
* This network is disabled due to absence of user credentials
*/
@@ -961,6 +970,28 @@ public class WifiConfiguration implements Parcelable {
private boolean mHasEverConnected;
/**
+ * Boolean indicating whether {@link com.android.server.wifi.RecommendedNetworkEvaluator}
+ * chose not to connect to this network in the last qualified network selection process.
+ */
+ private boolean mNotRecommended;
+
+ /**
+ * Set whether {@link com.android.server.wifi.RecommendedNetworkEvaluator} does not
+ * recommend connecting to this network.
+ */
+ public void setNotRecommended(boolean notRecommended) {
+ mNotRecommended = notRecommended;
+ }
+
+ /**
+ * Returns whether {@link com.android.server.wifi.RecommendedNetworkEvaluator} does not
+ * recommend connecting to this network.
+ */
+ public boolean isNotRecommended() {
+ return mNotRecommended;
+ }
+
+ /**
* set whether this network is visible in latest Qualified Network Selection
* @param seen value set to candidate
*/
@@ -1264,6 +1295,7 @@ public class WifiConfiguration implements Parcelable {
setConnectChoice(source.getConnectChoice());
setConnectChoiceTimestamp(source.getConnectChoiceTimestamp());
setHasEverConnected(source.getHasEverConnected());
+ setNotRecommended(source.isNotRecommended());
}
public void writeToParcel(Parcel dest) {
@@ -1283,6 +1315,7 @@ public class WifiConfiguration implements Parcelable {
dest.writeInt(CONNECT_CHOICE_NOT_EXISTS);
}
dest.writeInt(getHasEverConnected() ? 1 : 0);
+ dest.writeInt(isNotRecommended() ? 1 : 0);
}
public void readFromParcel(Parcel in) {
@@ -1302,6 +1335,7 @@ public class WifiConfiguration implements Parcelable {
setConnectChoiceTimestamp(INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
}
setHasEverConnected(in.readInt() != 0);
+ setNotRecommended(in.readInt() != 0);
}
}
@@ -1881,6 +1915,7 @@ public class WifiConfiguration implements Parcelable {
FQDN = source.FQDN;
roamingConsortiumIds = source.roamingConsortiumIds.clone();
providerFriendlyName = source.providerFriendlyName;
+ isHomeProviderNetwork = source.isHomeProviderNetwork;
preSharedKey = source.preSharedKey;
mNetworkSelectionStatus.copy(source.getNetworkSelectionStatus());
@@ -1961,6 +1996,7 @@ public class WifiConfiguration implements Parcelable {
dest.writeInt(apChannel);
dest.writeString(FQDN);
dest.writeString(providerFriendlyName);
+ dest.writeInt(isHomeProviderNetwork ? 1 : 0);
dest.writeInt(roamingConsortiumIds.length);
for (long roamingConsortiumId : roamingConsortiumIds) {
dest.writeLong(roamingConsortiumId);
@@ -2026,6 +2062,7 @@ public class WifiConfiguration implements Parcelable {
config.apChannel = in.readInt();
config.FQDN = in.readString();
config.providerFriendlyName = in.readString();
+ config.isHomeProviderNetwork = in.readInt() != 0;
int numRoamingConsortiumIds = in.readInt();
config.roamingConsortiumIds = new long[numRoamingConsortiumIds];
for (int i = 0; i < numRoamingConsortiumIds; i++) {
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index e410a9cf917e..f79033200568 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -142,7 +142,7 @@ public class WifiEnterpriseConfig implements Parcelable {
private HashMap<String, String> mFields = new HashMap<String, String>();
private X509Certificate[] mCaCerts;
private PrivateKey mClientPrivateKey;
- private X509Certificate mClientCertificate;
+ private X509Certificate[] mClientCertificateChain;
private int mEapMethod = Eap.NONE;
private int mPhase2Method = Phase2.NONE;
@@ -161,9 +161,19 @@ public class WifiEnterpriseConfig implements Parcelable {
for (String key : source.mFields.keySet()) {
mFields.put(key, source.mFields.get(key));
}
- mCaCerts = source.mCaCerts;
+ if (source.mCaCerts != null) {
+ mCaCerts = Arrays.copyOf(source.mCaCerts, source.mCaCerts.length);
+ } else {
+ mCaCerts = null;
+ }
mClientPrivateKey = source.mClientPrivateKey;
- mClientCertificate = source.mClientCertificate;
+ if (source.mClientCertificateChain != null) {
+ mClientCertificateChain = Arrays.copyOf(
+ source.mClientCertificateChain,
+ source.mClientCertificateChain.length);
+ } else {
+ mClientCertificateChain = null;
+ }
mEapMethod = source.mEapMethod;
mPhase2Method = source.mPhase2Method;
}
@@ -185,7 +195,7 @@ public class WifiEnterpriseConfig implements Parcelable {
dest.writeInt(mPhase2Method);
ParcelUtil.writeCertificates(dest, mCaCerts);
ParcelUtil.writePrivateKey(dest, mClientPrivateKey);
- ParcelUtil.writeCertificate(dest, mClientCertificate);
+ ParcelUtil.writeCertificates(dest, mClientCertificateChain);
}
public static final Creator<WifiEnterpriseConfig> CREATOR =
@@ -204,7 +214,7 @@ public class WifiEnterpriseConfig implements Parcelable {
enterpriseConfig.mPhase2Method = in.readInt();
enterpriseConfig.mCaCerts = ParcelUtil.readCertificates(in);
enterpriseConfig.mClientPrivateKey = ParcelUtil.readPrivateKey(in);
- enterpriseConfig.mClientCertificate = ParcelUtil.readCertificate(in);
+ enterpriseConfig.mClientCertificateChain = ParcelUtil.readCertificates(in);
return enterpriseConfig;
}
@@ -253,11 +263,17 @@ public class WifiEnterpriseConfig implements Parcelable {
public static final int MSCHAPV2 = 3;
/** Generic Token Card */
public static final int GTC = 4;
+ /** EAP-Subscriber Identity Module */
+ public static final int SIM = 5;
+ /** EAP-Authentication and Key Agreement */
+ public static final int AKA = 6;
+ /** EAP-Authentication and Key Agreement Prime */
+ public static final int AKA_PRIME = 7;
private static final String AUTH_PREFIX = "auth=";
private static final String AUTHEAP_PREFIX = "autheap=";
/** @hide */
public static final String[] strings = {EMPTY_VALUE, "PAP", "MSCHAP",
- "MSCHAPV2", "GTC" };
+ "MSCHAPV2", "GTC", "SIM", "AKA", "AKA'" };
/** Prevent initialization */
private Phase2() {}
@@ -416,6 +432,9 @@ public class WifiEnterpriseConfig implements Parcelable {
case Phase2.MSCHAP:
case Phase2.MSCHAPV2:
case Phase2.GTC:
+ case Phase2.SIM:
+ case Phase2.AKA:
+ case Phase2.AKA_PRIME:
mPhase2Method = phase2Method;
break;
default:
@@ -742,10 +761,54 @@ public class WifiEnterpriseConfig implements Parcelable {
* @throws IllegalArgumentException for an invalid key or certificate.
*/
public void setClientKeyEntry(PrivateKey privateKey, X509Certificate clientCertificate) {
+ X509Certificate[] clientCertificates = null;
if (clientCertificate != null) {
- if (clientCertificate.getBasicConstraints() != -1) {
- throw new IllegalArgumentException("Cannot be a CA certificate");
+ clientCertificates = new X509Certificate[] {clientCertificate};
+ }
+ setClientKeyEntryWithCertificateChain(privateKey, clientCertificates);
+ }
+
+ /**
+ * Specify a private key and client certificate chain for client authorization.
+ *
+ * <p>A default name is automatically assigned to the key entry and used
+ * with this configuration. The framework takes care of installing the
+ * key entry when the config is saved and removing the key entry when
+ * the config is removed.
+
+ * @param privateKey
+ * @param clientCertificateChain
+ * @throws IllegalArgumentException for an invalid key or certificate.
+ */
+ public void setClientKeyEntryWithCertificateChain(PrivateKey privateKey,
+ X509Certificate[] clientCertificateChain) {
+ X509Certificate[] newCerts = null;
+ if (clientCertificateChain != null && clientCertificateChain.length > 0) {
+ // We validate that this is a well formed chain that starts
+ // with an end-certificate and is followed by CA certificates.
+ // We don't validate that each following certificate verifies
+ // the previous. https://en.wikipedia.org/wiki/Chain_of_trust
+ //
+ // Basic constraints is an X.509 extension type that defines
+ // whether a given certificate is allowed to sign additional
+ // certificates and what path length restrictions may exist.
+ // We use this to judge whether the certificate is an end
+ // certificate or a CA certificate.
+ // https://cryptography.io/en/latest/x509/reference/
+ if (clientCertificateChain[0].getBasicConstraints() != -1) {
+ throw new IllegalArgumentException(
+ "First certificate in the chain must be a client end certificate");
}
+
+ for (int i = 1; i < clientCertificateChain.length; i++) {
+ if (clientCertificateChain[i].getBasicConstraints() == -1) {
+ throw new IllegalArgumentException(
+ "All certificates following the first must be CA certificates");
+ }
+ }
+ newCerts = Arrays.copyOf(clientCertificateChain,
+ clientCertificateChain.length);
+
if (privateKey == null) {
throw new IllegalArgumentException("Client cert without a private key");
}
@@ -755,7 +818,7 @@ public class WifiEnterpriseConfig implements Parcelable {
}
mClientPrivateKey = privateKey;
- mClientCertificate = clientCertificate;
+ mClientCertificateChain = newCerts;
}
/**
@@ -764,7 +827,24 @@ public class WifiEnterpriseConfig implements Parcelable {
* @return X.509 client certificate
*/
public X509Certificate getClientCertificate() {
- return mClientCertificate;
+ if (mClientCertificateChain != null && mClientCertificateChain.length > 0) {
+ return mClientCertificateChain[0];
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the complete client certificate chain
+ *
+ * @return X.509 client certificates
+ */
+ @Nullable public X509Certificate[] getClientCertificateChain() {
+ if (mClientCertificateChain != null && mClientCertificateChain.length > 0) {
+ return mClientCertificateChain;
+ } else {
+ return null;
+ }
}
/**
@@ -772,7 +852,7 @@ public class WifiEnterpriseConfig implements Parcelable {
*/
public void resetClientKeyEntry() {
mClientPrivateKey = null;
- mClientCertificate = null;
+ mClientCertificateChain = null;
}
/**
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 3b6e76f76677..ed6a166d3fc6 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -120,11 +120,7 @@ public class WifiManager {
public static final String PASSPOINT_ICON_RECEIVED_ACTION =
"android.net.wifi.PASSPOINT_ICON_RECEIVED";
/** @hide */
- public static final String EXTRA_PASSPOINT_ICON_BSSID = "bssid";
- /** @hide */
public static final String EXTRA_PASSPOINT_ICON_FILE = "file";
- /** @hide */
- public static final String EXTRA_PASSPOINT_ICON_DATA = "icon";
/**
* Broadcast intent action indicating that the a Passpoint release
@@ -159,6 +155,127 @@ public class WifiManager {
public static final String EXTRA_PASSPOINT_WNM_DELAY = "delay";
/**
+ * Broadcast intent action indicating that a Passpoint provider icon has been received.
+ *
+ * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
+ */
+ public static final String ACTION_PASSPOINT_ICON =
+ "android.net.wifi.action.PASSPOINT_ICON";
+ /**
+ * BSSID of the sender.
+ *
+ * Type: long
+ */
+ public static final String EXTRA_PASSPOINT_ICON_BSSID =
+ "android.net.wifi.extra.PASSPOINT_ICON_BSSID";
+ /**
+ * Filename of the icon.
+ *
+ * Type: String
+ */
+ public static final String EXTRA_PASSPOINT_ICON_FILENAME =
+ "android.net.wifi.extra.PASSPOINT_ICON_FILENAME";
+ /**
+ * Binary blob of the icon.
+ *
+ * Type: byte[]
+ */
+ public static final String EXTRA_PASSPOINT_ICON_DATA =
+ "android.net.wifi.extra.PASSPOINT_ICON_DATA";
+
+ /**
+ * Broadcast intent action indicating a Passpoint OSU Providers List element has been received.
+ *
+ * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
+ */
+ public static final String ACTION_PASSPOINT_OSU_PROVIDERS_LIST =
+ "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST";
+ /**
+ * BSSID of the sender.
+ *
+ * Type: long
+ */
+ public static final String EXTRA_PASSPOINT_OSU_PROVIDERS_LIST_BSSID =
+ "android.net.wifi.extra.PASSPOINT_OSU_PROVIDERS_LIST_BSSID";
+ /**
+ * Raw data of OSU Providers List ANQP element. Refer to Section 4.8 of Hotspot 2.0 Release 2
+ * Technical Specification for the exact data format.
+ *
+ * Type: byte[]
+ */
+ public static final String EXTRA_PASSPOINT_OSU_PROVIDERS_LIST_DATA =
+ "android.net.wifi.extra.PASSPOINT_OSU_PROVIDERS_LIST_DATA";
+
+ /**
+ * Broadcast intent action indicating that a Passpoint Deauth Imminent frame has been received.
+ *
+ * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
+ */
+ public static final String ACTION_PASSPOINT_DEAUTH_IMMINENT =
+ "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT";
+ /**
+ * The BSSID of the sender.
+ *
+ * Type: long
+ */
+ public static final String EXTRA_PASSPOINT_DEAUTH_IMMINENT_BSSID =
+ "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_BSSID";
+ /**
+ * Flag indicating failure at BSS (Basic Service Set) or ESS (Extended Service Set) level.
+ *
+ * Type: boolean
+ */
+ public static final String EXTRA_PASSPOINT_DEAUTH_IMMINENT_ESS =
+ "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_ESS";
+ /**
+ * Delay in seconds that a device shall wait before attempting re-association to the same BSS
+ * or ESS (as indicated by {@link #EXTRA_PASSPOINT_DEAUTH_IMMINENT_ESS}.
+ *
+ * Type: int
+ */
+ public static final String EXTRA_PASSPOINT_DEAUTH_IMMINENT_REAUTH_DELAY =
+ "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_REAUTH_DELAY";
+ /**
+ * URL that provides a webpage explaining the deauth reason.
+ *
+ * Type: String
+ */
+ public static final String EXTRA_PASSPOINT_DEAUTH_IMMINENT_REASON_URL =
+ "android.net.wifi.extra.PASSPOINT_DEAUTH_IMMINENT_REASON_URL";
+
+ /**
+ * Broadcast intent action indicating a Passpoint subscription remediation frame has been
+ * received.
+ *
+ * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
+ */
+ public static final String ACTION_PASSPOINT_SUBSCRIPTION_REMEDIATION =
+ "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION";
+ /**
+ * The BSSID of the sender.
+ *
+ * Type: long
+ */
+ public static final String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_BSSID =
+ "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_BSSID";
+ /**
+ * The protocol supported by the subscription remediation server. The possible values are:
+ * 0 - OMA DM
+ * 1 - SOAP XML SPP
+ *
+ * Type: int
+ */
+ public static final String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_METHOD =
+ "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_METHOD";
+ /**
+ * URL of the subscription remediation server.
+ *
+ * Type: String
+ */
+ public static final String EXTRA_PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_URL =
+ "android.net.wifi.extra.PASSPOINT_SUBSCRIPTION_REMEDIATION_SERVER_URL";
+
+ /**
* Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
* enabling, disabling, or unknown. One extra provides this state as an int.
* Another extra provides the previous state, if available.
@@ -721,7 +838,8 @@ public class WifiManager {
}
/**
- * Return a list of all the networks configured in the supplicant.
+ * Return a list of all the networks configured for the current foreground
+ * user.
* Not all fields of WifiConfiguration are returned. Only the following
* fields are filled in:
* <ul>
@@ -856,7 +974,6 @@ public class WifiManager {
*
* @param config The Passpoint configuration to be added
* @return true on success
- * @hide
*/
public boolean addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
try {
@@ -871,7 +988,6 @@ public class WifiManager {
*
* @param fqdn The FQDN of the passpoint configuration to be removed
* @return true on success
- * @hide
*/
public boolean removePasspointConfiguration(String fqdn) {
try {
@@ -887,7 +1003,6 @@ public class WifiManager {
* An empty list will be returned when no configurations are installed.
*
* @return A list of {@link PasspointConfiguration}
- * @hide
*/
public List<PasspointConfiguration> getPasspointConfigurations() {
try {
@@ -898,10 +1013,10 @@ public class WifiManager {
}
/**
- * Query for a Hotspot 2.0 release 2 OSU icon
+ * Query for a Hotspot 2.0 release 2 OSU icon file.
+ *
* @param bssid The BSSID of the AP
- * @param fileName Icon file name
- * @hide
+ * @param fileName File name of the icon to query
*/
public void queryPasspointIcon(long bssid, String fileName) {
try {
@@ -943,8 +1058,12 @@ public class WifiManager {
* Remove the specified network from the list of configured networks.
* This may result in the asynchronous delivery of state change
* events.
- * @param netId the integer that identifies the network configuration
- * to the supplicant
+ *
+ * Applications are not allowed to remove networks created by other
+ * applications.
+ *
+ * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
+ * #getConfiguredNetworks}.
* @return {@code true} if the operation succeeded
*/
public boolean removeNetwork(int netId) {
@@ -957,8 +1076,7 @@ public class WifiManager {
/**
* Allow a previously configured network to be associated with. If
- * <code>disableOthers</code> is true, then all other configured
- * networks are disabled, and an attempt to connect to the selected
+ * <code>attemptConnect</code> is true, an attempt to connect to the selected
* network is initiated. This may result in the asynchronous delivery
* of state change events.
* <p>
@@ -975,14 +1093,17 @@ public class WifiManager {
* {@link Network#openConnection(java.net.URL)}, or
* {@link ConnectivityManager#bindProcessToNetwork} to do so.
*
- * @param netId the ID of the network in the list of configured networks
- * @param disableOthers if true, disable all other networks. The way to
- * select a particular network to connect to is specify {@code true}
- * for this parameter.
+ * Applications are not allowed to enable networks created by other
+ * applications.
+ *
+ * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
+ * #getConfiguredNetworks}.
+ * @param attemptConnect The way to select a particular network to connect to is specify
+ * {@code true} for this parameter.
* @return {@code true} if the operation succeeded
*/
- public boolean enableNetwork(int netId, boolean disableOthers) {
- final boolean pin = disableOthers && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
+ public boolean enableNetwork(int netId, boolean attemptConnect) {
+ final boolean pin = attemptConnect && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
if (pin) {
NetworkRequest request = new NetworkRequest.Builder()
.clearCapabilities()
@@ -993,7 +1114,7 @@ public class WifiManager {
boolean success;
try {
- success = mService.enableNetwork(netId, disableOthers);
+ success = mService.enableNetwork(netId, attemptConnect);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1009,7 +1130,12 @@ public class WifiManager {
* Disable a configured network. The specified network will not be
* a candidate for associating. This may result in the asynchronous
* delivery of state change events.
- * @param netId the ID of the network as returned by {@link #addNetwork}.
+ *
+ * Applications are not allowed to disable networks created by other
+ * applications.
+ *
+ * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
+ * #getConfiguredNetworks}.
* @return {@code true} if the operation succeeded
*/
public boolean disableNetwork(int netId) {
@@ -1068,15 +1194,11 @@ public class WifiManager {
* Check that the supplicant daemon is responding to requests.
* @return {@code true} if we were able to communicate with the supplicant and
* it returned the expected response to the PING message.
+ * @deprecated Will return the output of {@link #isWifiEnabled()} instead.
*/
+ @Deprecated
public boolean pingSupplicant() {
- if (mService == null)
- return false;
- try {
- return mService.pingSupplicant();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return isWifiEnabled();
}
/** @hide */
@@ -1395,14 +1517,18 @@ public class WifiManager {
}
/**
- * Tell the supplicant to persist the current list of configured networks.
+ * Tell the device to persist the current list of configured networks.
* <p>
* Note: It is possible for this method to change the network IDs of
* existing networks. You should assume the network IDs can be different
* after calling this method.
*
* @return {@code true} if the operation succeeded
+ * @deprecated There is no need to call this method -
+ * {@link #addNetwork(WifiConfiguration)}, {@link #updateNetwork(WifiConfiguration)}
+ * and {@link #removeNetwork(int)} already persist the configurations automatically.
*/
+ @Deprecated
public boolean saveConfiguration() {
try {
return mService.saveConfiguration();
@@ -1981,7 +2107,7 @@ public class WifiManager {
/**
* Connect to a network with the given configuration. The network also
- * gets added to the supplicant configuration.
+ * gets added to the list of configured networks for the foreground user.
*
* For a new network, this function is used instead of a
* sequence of addNetwork(), enableNetwork(), saveConfiguration() and
@@ -2010,8 +2136,8 @@ public class WifiManager {
* This function is used instead of a enableNetwork(), saveConfiguration() and
* reconnect()
*
- * @param networkId the network id identifiying the network in the
- * supplicant configuration list
+ * @param networkId the ID of the network as returned by {@link #addNetwork} or {@link
+ * getConfiguredNetworks}.
* @param listener for callbacks on success or failure. Can be null.
* @throws IllegalStateException if the WifiManager instance needs to be
* initialized again
@@ -2023,9 +2149,9 @@ public class WifiManager {
}
/**
- * Save the given network in the supplicant config. If the network already
- * exists, the configuration is updated. A new network is enabled
- * by default.
+ * Save the given network to the list of configured networks for the
+ * foreground user. If the network already exists, the configuration
+ * is updated. Any new network is enabled by default.
*
* For a new network, this function is used instead of a
* sequence of addNetwork(), enableNetwork() and saveConfiguration().
@@ -2046,7 +2172,8 @@ public class WifiManager {
}
/**
- * Delete the network in the supplicant config.
+ * Delete the network from the list of configured networks for the
+ * foreground user.
*
* This function is used instead of a sequence of removeNetwork()
* and saveConfiguration().
@@ -2737,7 +2864,8 @@ public class WifiManager {
/**
* Restore state from the older version of back up data.
- * The old backup data was essentially a backup of wpa_supplicant.conf & ipconfig.txt file.
+ * The old backup data was essentially a backup of wpa_supplicant.conf
+ * and ipconfig.txt file.
* @hide
*/
public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
diff --git a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
index 9dd118bdbc55..35d7a12ccd79 100755
--- a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
+++ b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
@@ -19,16 +19,16 @@ package android.net.wifi;
import android.Manifest.permission;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.content.Context;
-import android.os.Handler;
import android.net.INetworkScoreCache;
import android.net.NetworkKey;
import android.net.ScoredNetwork;
+import android.os.Handler;
+import android.os.Process;
import android.util.Log;
-import com.android.internal.util.Preconditions;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -76,7 +76,7 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
public WifiNetworkScoreCache(Context context, @Nullable CacheListener listener) {
mContext = context.getApplicationContext();
mListener = listener;
- mNetworkCache = new HashMap<String, ScoredNetwork>();
+ mNetworkCache = new HashMap<>();
}
@Override public final void updateScores(List<ScoredNetwork> networks) {
@@ -210,7 +210,9 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
@Override protected final void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
- writer.println("WifiNetworkScoreCache");
+ String header = String.format("WifiNetworkScoreCache (%s/%d)",
+ mContext.getPackageName(), Process.myUid());
+ writer.println(header);
writer.println(" All score curves:");
for (Map.Entry<String, ScoredNetwork> entry : mNetworkCache.entrySet()) {
ScoredNetwork scoredNetwork = entry.getValue();
diff --git a/wifi/java/android/net/wifi/WifiSsid.java b/wifi/java/android/net/wifi/WifiSsid.java
index c53cd3c6454e..7a3cddfb8d58 100644
--- a/wifi/java/android/net/wifi/WifiSsid.java
+++ b/wifi/java/android/net/wifi/WifiSsid.java
@@ -49,6 +49,14 @@ public class WifiSsid implements Parcelable {
private WifiSsid() {
}
+ public static WifiSsid createFromByteArray(byte ssid[]) {
+ WifiSsid wifiSsid = new WifiSsid();
+ if (ssid != null) {
+ wifiSsid.octets.write(ssid, 0/* the start offset */, ssid.length);;
+ }
+ return wifiSsid;
+ }
+
public static WifiSsid createFromAsciiEncoded(String asciiEncoded) {
WifiSsid a = new WifiSsid();
a.convertToBytes(asciiEncoded);
diff --git a/wifi/java/android/net/wifi/aware/ConfigRequest.java b/wifi/java/android/net/wifi/aware/ConfigRequest.java
index 6a5957badafb..cc14ab2fa722 100644
--- a/wifi/java/android/net/wifi/aware/ConfigRequest.java
+++ b/wifi/java/android/net/wifi/aware/ConfigRequest.java
@@ -19,6 +19,8 @@ package android.net.wifi.aware;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Arrays;
+
/**
* Defines a request object to configure a Wi-Fi Aware network. Built using
* {@link ConfigRequest.Builder}. Configuration is requested using
@@ -41,6 +43,18 @@ public final class ConfigRequest implements Parcelable {
public static final int CLUSTER_ID_MAX = 0xFFFF;
/**
+ * Indices for configuration variables which are specified per band.
+ */
+ public static final int NAN_BAND_24GHZ = 0;
+ public static final int NAN_BAND_5GHZ = 1;
+
+ /**
+ * Magic values for Discovery Window (DW) interval configuration
+ */
+ public static final int DW_INTERVAL_NOT_INIT = -1;
+ public static final int DW_DISABLE = 0; // only valid for 5GHz
+
+ /**
* Indicates whether 5G band support is requested.
*/
public final boolean mSupport5gBand;
@@ -62,19 +76,26 @@ public final class ConfigRequest implements Parcelable {
*/
public final int mClusterHigh;
+ /**
+ * Specifies the discovery window interval for the device on NAN_BAND_*.
+ */
+ public final int mDiscoveryWindowInterval[];
+
private ConfigRequest(boolean support5gBand, int masterPreference, int clusterLow,
- int clusterHigh) {
+ int clusterHigh, int discoveryWindowInterval[]) {
mSupport5gBand = support5gBand;
mMasterPreference = masterPreference;
mClusterLow = clusterLow;
mClusterHigh = clusterHigh;
+ mDiscoveryWindowInterval = discoveryWindowInterval;
}
@Override
public String toString() {
return "ConfigRequest [mSupport5gBand=" + mSupport5gBand + ", mMasterPreference="
+ mMasterPreference + ", mClusterLow=" + mClusterLow + ", mClusterHigh="
- + mClusterHigh + "]";
+ + mClusterHigh + ", mDiscoveryWindowInterval="
+ + Arrays.toString(mDiscoveryWindowInterval) + "]";
}
@Override
@@ -88,6 +109,7 @@ public final class ConfigRequest implements Parcelable {
dest.writeInt(mMasterPreference);
dest.writeInt(mClusterLow);
dest.writeInt(mClusterHigh);
+ dest.writeIntArray(mDiscoveryWindowInterval);
}
public static final Creator<ConfigRequest> CREATOR = new Creator<ConfigRequest>() {
@@ -102,7 +124,10 @@ public final class ConfigRequest implements Parcelable {
int masterPreference = in.readInt();
int clusterLow = in.readInt();
int clusterHigh = in.readInt();
- return new ConfigRequest(support5gBand, masterPreference, clusterLow, clusterHigh);
+ int discoveryWindowInterval[] = in.createIntArray();
+
+ return new ConfigRequest(support5gBand, masterPreference, clusterLow, clusterHigh,
+ discoveryWindowInterval);
}
};
@@ -119,17 +144,8 @@ public final class ConfigRequest implements Parcelable {
ConfigRequest lhs = (ConfigRequest) o;
return mSupport5gBand == lhs.mSupport5gBand && mMasterPreference == lhs.mMasterPreference
- && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh;
- }
-
- /**
- * Checks whether the configuration's settings are non-default.
- *
- * @return true if any of the settings are non-default.
- */
- public boolean isNonDefault() {
- return mSupport5gBand || mMasterPreference != 0 || mClusterLow != CLUSTER_ID_MIN
- || mClusterHigh != CLUSTER_ID_MAX;
+ && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh
+ && Arrays.equals(mDiscoveryWindowInterval, lhs.mDiscoveryWindowInterval);
}
@Override
@@ -140,6 +156,7 @@ public final class ConfigRequest implements Parcelable {
result = 31 * result + mMasterPreference;
result = 31 * result + mClusterLow;
result = 31 * result + mClusterHigh;
+ result = 31 * result + Arrays.hashCode(mDiscoveryWindowInterval);
return result;
}
@@ -173,6 +190,23 @@ public final class ConfigRequest implements Parcelable {
throw new IllegalArgumentException(
"Invalid argument combination - must have Cluster Low <= Cluster High");
}
+ if (mDiscoveryWindowInterval.length != 2) {
+ throw new IllegalArgumentException(
+ "Invalid discovery window interval: must have 2 elements (2.4 & 5");
+ }
+ if (mDiscoveryWindowInterval[NAN_BAND_24GHZ] != DW_INTERVAL_NOT_INIT &&
+ (mDiscoveryWindowInterval[NAN_BAND_24GHZ] < 1 // valid for 2.4GHz: [1-5]
+ || mDiscoveryWindowInterval[NAN_BAND_24GHZ] > 5)) {
+ throw new IllegalArgumentException(
+ "Invalid discovery window interval for 2.4GHz: valid is UNSET or [1,5]");
+ }
+ if (mDiscoveryWindowInterval[NAN_BAND_5GHZ] != DW_INTERVAL_NOT_INIT &&
+ (mDiscoveryWindowInterval[NAN_BAND_5GHZ] < 0 // valid for 5GHz: [0-5]
+ || mDiscoveryWindowInterval[NAN_BAND_5GHZ] > 5)) {
+ throw new IllegalArgumentException(
+ "Invalid discovery window interval for 5GHz: valid is UNSET or [0,5]");
+ }
+
}
/**
@@ -183,6 +217,7 @@ public final class ConfigRequest implements Parcelable {
private int mMasterPreference = 0;
private int mClusterLow = CLUSTER_ID_MIN;
private int mClusterHigh = CLUSTER_ID_MAX;
+ private int mDiscoveryWindowInterval[] = {DW_INTERVAL_NOT_INIT, DW_INTERVAL_NOT_INIT};
/**
* Specify whether 5G band support is required in this request. Disabled by default.
@@ -271,6 +306,33 @@ public final class ConfigRequest implements Parcelable {
}
/**
+ * The discovery window interval specifies the discovery windows in which the device will be
+ * awake. The configuration enables trading off latency vs. power (higher interval means
+ * higher discovery latency but lower power).
+ *
+ * @param band Either {@link #NAN_BAND_24GHZ} or {@link #NAN_BAND_5GHZ}.
+ * @param interval A value of 1, 2, 3, 4, or 5 indicating an interval of 2^(interval-1). For
+ * the 5GHz band a value of 0 indicates that the device will not be awake
+ * for any discovery windows.
+ *
+ * @return The builder itself to facilitate chaining operations
+ * {@code builder.setDiscoveryWindowInterval(...).setMasterPreference(...)}.
+ */
+ public Builder setDiscoveryWindowInterval(int band, int interval) {
+ if (band != NAN_BAND_24GHZ && band != NAN_BAND_5GHZ) {
+ throw new IllegalArgumentException("Invalid band value");
+ }
+ if ((band == NAN_BAND_24GHZ && (interval < 1 || interval > 5))
+ || (band == NAN_BAND_5GHZ && (interval < 0 || interval > 5))) {
+ throw new IllegalArgumentException(
+ "Invalid interval value: 2.4 GHz [1,5] or 5GHz [0,5]");
+ }
+
+ mDiscoveryWindowInterval[band] = interval;
+ return this;
+ }
+
+ /**
* Build {@link ConfigRequest} given the current requests made on the
* builder.
*/
@@ -280,7 +342,8 @@ public final class ConfigRequest implements Parcelable {
"Invalid argument combination - must have Cluster Low <= Cluster High");
}
- return new ConfigRequest(mSupport5gBand, mMasterPreference, mClusterLow, mClusterHigh);
+ return new ConfigRequest(mSupport5gBand, mMasterPreference, mClusterLow, mClusterHigh,
+ mDiscoveryWindowInterval);
}
}
}
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
index adf189b64544..57b98e984f17 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -31,8 +31,7 @@ import java.lang.ref.WeakReference;
* {@link PublishDiscoverySession} and {@link SubscribeDiscoverySession}. This
* class provides functionality common to both publish and subscribe discovery sessions:
* <ul>
- * <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])} or
- * {@link #sendMessage(PeerHandle, int, byte[], int)} methods.
+ * <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])}.
* <li>Creating a network-specifier when requesting a Aware connection:
* {@link #createNetworkSpecifier(PeerHandle, byte[])}.
* </ul>
@@ -62,6 +61,8 @@ public class DiscoverySession {
* {@link #sendMessage(PeerHandle, int, byte[], int)}.
*
* @return Maximum retry count when sending messages.
+ *
+ * @hide
*/
public static int getMaxSendRetryCount() {
return MAX_SEND_RETRY_COUNT;
@@ -163,6 +164,8 @@ public class DiscoverySession {
* or MAC level) retries should be attempted if there is no ACK from the receiver
* (note: no retransmissions are attempted in other failure cases). A value of 0
* indicates no retries. Max permitted value is {@link #getMaxSendRetryCount()}.
+ *
+ * @hide
*/
public void sendMessage(@NonNull PeerHandle peerHandle, int messageId,
@Nullable byte[] message, int retryCount) {
@@ -195,8 +198,6 @@ public class DiscoverySession {
* The peer will get a callback indicating a message was received using
* {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
* byte[])}.
- * Equivalent to {@link #sendMessage(PeerHandle, int, byte[], int)}
- * with a {@code retryCount} of 0.
*
* @param peerHandle The peer's handle for the message. Must be a result of an
* {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
index 33da1823c8b8..9645b1d32a34 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
@@ -124,10 +124,9 @@ public class DiscoverySessionCallback {
}
/**
- * Called when message transmission fails - when no ACK is received from the peer.
- * Retries when ACKs are not received are done by hardware, MAC, and in the Aware stack (using
- * the {@link DiscoverySession#sendMessage(PeerHandle, int,
- * byte[], int)} method) - this event is received after all retries are exhausted.
+ * Called when message transmission initiated with
+ * {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])} fails. E.g. when no ACK is
+ * received from the peer.
* <p>
* Note that either this callback or
* {@link DiscoverySessionCallback#onMessageSendSucceeded(int)} will be received
@@ -141,9 +140,7 @@ public class DiscoverySessionCallback {
/**
* Called when a message is received from a discovery session peer - in response to the
- * peer's {@link DiscoverySession#sendMessage(PeerHandle, int,
- * byte[])} or {@link DiscoverySession#sendMessage(PeerHandle,
- * int, byte[], int)}.
+ * peer's {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])}.
*
* @param peerHandle An opaque handle to the peer matching our discovery operation.
* @param message A byte array containing the message.
diff --git a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
index 794c142775f3..0f4910f0c29f 100644
--- a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
+++ b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
@@ -34,8 +34,6 @@ import android.net.wifi.RttManager;
interface IWifiAwareManager
{
// Aware API
- void enableUsage();
- void disableUsage();
boolean isUsageEnabled();
Characteristics getCharacteristics();
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 043925edc5f0..0eb6a3d157c3 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -253,36 +253,6 @@ public class WifiAwareManager {
}
/**
- * Enable the usage of the Aware API. Doesn't actually turn on Aware cluster formation - that
- * only happens when an attach is attempted. {@link #ACTION_WIFI_AWARE_STATE_CHANGED} broadcast
- * will be triggered.
- *
- * @hide
- */
- public void enableUsage() {
- try {
- mService.enableUsage();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Disable the usage of the Aware API. All attempts to attach() will be rejected. All open
- * connections and sessions will be terminated. {@link #ACTION_WIFI_AWARE_STATE_CHANGED}
- * broadcast will be triggered.
- *
- * @hide
- */
- public void disableUsage() {
- try {
- mService.disableUsage();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Returns the current status of Aware API: whether or not Aware is available. To track
* changes in the state of Aware API register for the
* {@link #ACTION_WIFI_AWARE_STATE_CHANGED} broadcast.
@@ -706,7 +676,11 @@ public class WifiAwareManager {
attachCallback.onAttachFailed();
break;
case CALLBACK_IDENTITY_CHANGED:
- identityChangedListener.onIdentityChanged((byte[]) msg.obj);
+ if (identityChangedListener == null) {
+ Log.e(TAG, "CALLBACK_IDENTITY_CHANGED: null listener.");
+ } else {
+ identityChangedListener.onIdentityChanged((byte[]) msg.obj);
+ }
break;
case CALLBACK_RANGING_SUCCESS: {
RttManager.RttListener listener = getAndRemoveRangingListener(msg.arg1);
diff --git a/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java b/wifi/java/android/net/wifi/hotspot2/ConfigParser.java
index 96db5d02679e..027b049a68c9 100644
--- a/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java
+++ b/wifi/java/android/net/wifi/hotspot2/ConfigParser.java
@@ -16,7 +16,7 @@
package android.net.wifi.hotspot2;
-import android.net.wifi.hotspot2.omadm.PPSMOParser;
+import android.net.wifi.hotspot2.omadm.PpsMoParser;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
@@ -41,11 +41,9 @@ import java.util.Map;
/**
* Utility class for building PasspointConfiguration from an installation file.
- *
- * @hide
*/
-public final class ConfigBuilder {
- private static final String TAG = "ConfigBuilder";
+public final class ConfigParser {
+ private static final String TAG = "ConfigParser";
// Header names.
private static final String CONTENT_TYPE = "Content-Type";
@@ -101,6 +99,10 @@ public final class ConfigBuilder {
public String encodingType = null;
}
+ /**
+ * @hide
+ */
+ public ConfigParser() {}
/**
* Parse the Hotspot 2.0 Release 1 configuration data into a {@link PasspointConfiguration}
@@ -133,7 +135,7 @@ public final class ConfigBuilder {
* certificate chain (optional).
* @return {@link PasspointConfiguration}
*/
- public static PasspointConfiguration buildPasspointConfig(String mimeType, byte[] data) {
+ public static PasspointConfiguration parsePasspointConfig(String mimeType, byte[] data) {
// Verify MIME type.
if (!TextUtils.equals(mimeType, TYPE_WIFI_CONFIG)) {
Log.e(TAG, "Unexpected MIME type: " + mimeType);
@@ -169,13 +171,13 @@ public final class ConfigBuilder {
throw new IOException("Missing Passpoint Profile");
}
- PasspointConfiguration config = PPSMOParser.parseMOText(new String(profileData));
+ PasspointConfiguration config = PpsMoParser.parseMoText(new String(profileData));
if (config == null) {
throw new IOException("Failed to parse Passpoint profile");
}
// Credential is needed for storing the certificates and private client key.
- if (config.credential == null) {
+ if (config.getCredential() == null) {
throw new IOException("Passpoint profile missing credential");
}
@@ -183,7 +185,7 @@ public final class ConfigBuilder {
byte[] caCertData = mimeParts.get(TYPE_CA_CERT);
if (caCertData != null) {
try {
- config.credential.caCertificate = parseCACert(caCertData);
+ config.getCredential().setCaCertificate(parseCACert(caCertData));
} catch (CertificateException e) {
throw new IOException("Failed to parse CA Certificate");
}
@@ -194,9 +196,9 @@ public final class ConfigBuilder {
if (pkcs12Data != null) {
try {
Pair<PrivateKey, List<X509Certificate>> clientKey = parsePkcs12(pkcs12Data);
- config.credential.clientPrivateKey = clientKey.first;
- config.credential.clientCertificateChain =
- clientKey.second.toArray(new X509Certificate[clientKey.second.size()]);
+ config.getCredential().setClientPrivateKey(clientKey.first);
+ config.getCredential().setClientCertificateChain(
+ clientKey.second.toArray(new X509Certificate[clientKey.second.size()]));
} catch(GeneralSecurityException | IOException e) {
throw new IOException("Failed to parse PCKS12 string");
}
@@ -470,4 +472,4 @@ public final class ConfigBuilder {
}
return new Pair<PrivateKey, List<X509Certificate>>(clientKey, clientCertificateChain);
}
-} \ No newline at end of file
+}
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 643753abf5dc..1f661c4580af 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -17,24 +17,218 @@
package android.net.wifi.hotspot2;
import android.net.wifi.hotspot2.pps.Credential;
-import android.net.wifi.hotspot2.pps.HomeSP;
+import android.net.wifi.hotspot2.pps.HomeSp;
+import android.net.wifi.hotspot2.pps.Policy;
+import android.net.wifi.hotspot2.pps.UpdateParameter;
import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
import android.os.Parcel;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
/**
* Class representing Passpoint configuration. This contains configurations specified in
* PerProviderSubscription (PPS) Management Object (MO) tree.
*
* For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
* Release 2 Technical Specification.
- *
- * Currently, only HomeSP and Credential subtrees are supported.
- *
- * @hide
*/
public final class PasspointConfiguration implements Parcelable {
- public HomeSP homeSp = null;
- public Credential credential = null;
+ private static final String TAG = "PasspointConfiguration";
+
+ /**
+ * Number of bytes for certificate SHA-256 fingerprint byte array.
+ */
+ private static final int CERTIFICATE_SHA256_BYTES = 32;
+
+ /**
+ * Maximum bytes for URL string.
+ */
+ private static final int MAX_URL_BYTES = 1023;
+
+ /**
+ * Integer value used for indicating null value in the Parcel.
+ */
+ private static final int NULL_VALUE = -1;
+
+ /**
+ * Configurations under HomeSp subtree.
+ */
+ private HomeSp mHomeSp = null;
+ public void setHomeSp(HomeSp homeSp) { mHomeSp = homeSp; }
+ public HomeSp getHomeSp() { return mHomeSp; }
+
+ /**
+ * Configurations under Credential subtree.
+ */
+ private Credential mCredential = null;
+ public void setCredential(Credential credential) {
+ mCredential = credential;
+ }
+ public Credential getCredential() {
+ return mCredential;
+ }
+
+ /**
+ * Configurations under Policy subtree.
+ */
+ private Policy mPolicy = null;
+ public void setPolicy(Policy policy) {
+ mPolicy = policy;
+ }
+ public Policy getPolicy() {
+ return mPolicy;
+ }
+
+ /**
+ * Meta data for performing subscription update.
+ */
+ private UpdateParameter mSubscriptionUpdate = null;
+ public void setSubscriptionUpdate(UpdateParameter subscriptionUpdate) {
+ mSubscriptionUpdate = subscriptionUpdate;
+ }
+ public UpdateParameter getSubscriptionUpdate() {
+ return mSubscriptionUpdate;
+ }
+
+ /**
+ * List of HTTPS URL for retrieving trust root certificate and the corresponding SHA-256
+ * fingerprint of the certificate. The certificates are used for verifying AAA server's
+ * identity during EAP authentication.
+ */
+ private Map<String, byte[]> mTrustRootCertList = null;
+ public void setTrustRootCertList(Map<String, byte[]> trustRootCertList) {
+ mTrustRootCertList = trustRootCertList;
+ }
+ public Map<String, byte[]> getTrustRootCertList() {
+ return mTrustRootCertList;
+ }
+
+ /**
+ * Set by the subscription server, updated every time the configuration is updated by
+ * the subscription server.
+ *
+ * Use Integer.MIN_VALUE to indicate unset value.
+ */
+ private int mUpdateIdentifier = Integer.MIN_VALUE;
+ public void setUpdateIdentifier(int updateIdentifier) {
+ mUpdateIdentifier = updateIdentifier;
+ }
+ public int getUpdateIdentifier() {
+ return mUpdateIdentifier;
+ }
+
+ /**
+ * The priority of the credential.
+ *
+ * Use Integer.MIN_VALUE to indicate unset value.
+ */
+ private int mCredentialPriority = Integer.MIN_VALUE;
+ public void setCredentialPriority(int credentialPriority) {
+ mCredentialPriority = credentialPriority;
+ }
+ public int getCredentialPriority() {
+ return mCredentialPriority;
+ }
+
+ /**
+ * The time this subscription is created. It is in the format of number
+ * of milliseconds since January 1, 1970, 00:00:00 GMT.
+ *
+ * Use Long.MIN_VALUE to indicate unset value.
+ */
+ private long mSubscriptionCreationTimeInMs = Long.MIN_VALUE;
+ public void setSubscriptionCreationTimeInMs(long subscriptionCreationTimeInMs) {
+ mSubscriptionCreationTimeInMs = subscriptionCreationTimeInMs;
+ }
+ public long getSubscriptionCreationTimeInMs() {
+ return mSubscriptionCreationTimeInMs;
+ }
+
+ /**
+ * The time this subscription will expire. It is in the format of number
+ * of milliseconds since January 1, 1970, 00:00:00 GMT.
+ *
+ * Use Long.MIN_VALUE to indicate unset value.
+ */
+ private long mSubscriptionExpirationTimeInMs = Long.MIN_VALUE;
+ public void setSubscriptionExpirationTimeInMs(long subscriptionExpirationTimeInMs) {
+ mSubscriptionExpirationTimeInMs = subscriptionExpirationTimeInMs;
+ }
+ public long getSubscriptionExpirationTimeInMs() {
+ return mSubscriptionExpirationTimeInMs;
+ }
+
+ /**
+ * The type of the subscription. This is defined by the provider and the value is provider
+ * specific.
+ */
+ private String mSubscriptionType = null;
+ public void setSubscriptionType(String subscriptionType) {
+ mSubscriptionType = subscriptionType;
+ }
+ public String getSubscriptionType() {
+ return mSubscriptionType;
+ }
+
+ /**
+ * The time period for usage statistics accumulation. A value of zero means that usage
+ * statistics are not accumulated on a periodic basis (e.g., a one-time limit for
+ * “pay as you go” - PAYG service). A non-zero value specifies the usage interval in minutes.
+ */
+ private long mUsageLimitUsageTimePeriodInMinutes = Long.MIN_VALUE;
+ public void setUsageLimitUsageTimePeriodInMinutes(long usageLimitUsageTimePeriodInMinutes) {
+ mUsageLimitUsageTimePeriodInMinutes = usageLimitUsageTimePeriodInMinutes;
+ }
+ public long getUsageLimitUsageTimePeriodInMinutes() {
+ return mUsageLimitUsageTimePeriodInMinutes;
+ }
+
+ /**
+ * The time at which usage statistic accumulation begins. It is in the format of number
+ * of milliseconds since January 1, 1970, 00:00:00 GMT.
+ *
+ * Use Long.MIN_VALUE to indicate unset value.
+ */
+ private long mUsageLimitStartTimeInMs = Long.MIN_VALUE;
+ public void setUsageLimitStartTimeInMs(long usageLimitStartTimeInMs) {
+ mUsageLimitStartTimeInMs = usageLimitStartTimeInMs;
+ }
+ public long getUsageLimitStartTimeInMs() {
+ return mUsageLimitStartTimeInMs;
+ }
+
+ /**
+ * The cumulative data limit in megabytes for the {@link #usageLimitUsageTimePeriodInMinutes}.
+ * A value of zero indicate unlimited data usage.
+ *
+ * Use Long.MIN_VALUE to indicate unset value.
+ */
+ private long mUsageLimitDataLimit = Long.MIN_VALUE;
+ public void setUsageLimitDataLimit(long usageLimitDataLimit) {
+ mUsageLimitDataLimit = usageLimitDataLimit;
+ }
+ public long getUsageLimitDataLimit() {
+ return mUsageLimitDataLimit;
+ }
+
+ /**
+ * The cumulative time limit in minutes for the {@link #usageLimitUsageTimePeriodInMinutes}.
+ * A value of zero indicate unlimited time usage.
+ */
+ private long mUsageLimitTimeLimitInMinutes = Long.MIN_VALUE;
+ public void setUsageLimitTimeLimitInMinutes(long usageLimitTimeLimitInMinutes) {
+ mUsageLimitTimeLimitInMinutes = usageLimitTimeLimitInMinutes;
+ }
+ public long getUsageLimitTimeLimitInMinutes() {
+ return mUsageLimitTimeLimitInMinutes;
+ }
/**
* Constructor for creating PasspointConfiguration with default values.
@@ -47,14 +241,34 @@ public final class PasspointConfiguration implements Parcelable {
* @param source The source to copy from
*/
public PasspointConfiguration(PasspointConfiguration source) {
- if (source != null) {
- if (source.homeSp != null) {
- homeSp = new HomeSP(source.homeSp);
- }
- if (source.credential != null) {
- credential = new Credential(source.credential);
- }
+ if (source == null) {
+ return;
+ }
+
+ if (source.mHomeSp != null) {
+ mHomeSp = new HomeSp(source.mHomeSp);
+ }
+ if (source.mCredential != null) {
+ mCredential = new Credential(source.mCredential);
+ }
+ if (source.mPolicy != null) {
+ mPolicy = new Policy(source.mPolicy);
+ }
+ if (source.mTrustRootCertList != null) {
+ mTrustRootCertList = Collections.unmodifiableMap(source.mTrustRootCertList);
+ }
+ if (source.mSubscriptionUpdate != null) {
+ mSubscriptionUpdate = new UpdateParameter(source.mSubscriptionUpdate);
}
+ mUpdateIdentifier = source.mUpdateIdentifier;
+ mCredentialPriority = source.mCredentialPriority;
+ mSubscriptionCreationTimeInMs = source.mSubscriptionCreationTimeInMs;
+ mSubscriptionExpirationTimeInMs = source.mSubscriptionExpirationTimeInMs;
+ mSubscriptionType = source.mSubscriptionType;
+ mUsageLimitDataLimit = source.mUsageLimitDataLimit;
+ mUsageLimitStartTimeInMs = source.mUsageLimitStartTimeInMs;
+ mUsageLimitTimeLimitInMinutes = source.mUsageLimitTimeLimitInMinutes;
+ mUsageLimitUsageTimePeriodInMinutes = source.mUsageLimitUsageTimePeriodInMinutes;
}
@Override
@@ -64,8 +278,20 @@ public final class PasspointConfiguration implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeParcelable(homeSp, flags);
- dest.writeParcelable(credential, flags);
+ dest.writeParcelable(mHomeSp, flags);
+ dest.writeParcelable(mCredential, flags);
+ dest.writeParcelable(mPolicy, flags);
+ dest.writeParcelable(mSubscriptionUpdate, flags);
+ writeTrustRootCerts(dest, mTrustRootCertList);
+ dest.writeInt(mUpdateIdentifier);
+ dest.writeInt(mCredentialPriority);
+ dest.writeLong(mSubscriptionCreationTimeInMs);
+ dest.writeLong(mSubscriptionExpirationTimeInMs);
+ dest.writeString(mSubscriptionType);
+ dest.writeLong(mUsageLimitUsageTimePeriodInMinutes);
+ dest.writeLong(mUsageLimitStartTimeInMs);
+ dest.writeLong(mUsageLimitDataLimit);
+ dest.writeLong(mUsageLimitTimeLimitInMinutes);
}
@Override
@@ -77,9 +303,30 @@ public final class PasspointConfiguration implements Parcelable {
return false;
}
PasspointConfiguration that = (PasspointConfiguration) thatObject;
- return (homeSp == null ? that.homeSp == null : homeSp.equals(that.homeSp)) &&
- (credential == null ? that.credential == null :
- credential.equals(that.credential));
+ return (mHomeSp == null ? that.mHomeSp == null : mHomeSp.equals(that.mHomeSp))
+ && (mCredential == null ? that.mCredential == null
+ : mCredential.equals(that.mCredential))
+ && (mPolicy == null ? that.mPolicy == null : mPolicy.equals(that.mPolicy))
+ && (mSubscriptionUpdate == null ? that.mSubscriptionUpdate == null
+ : mSubscriptionUpdate.equals(that.mSubscriptionUpdate))
+ && isTrustRootCertListEquals(mTrustRootCertList, that.mTrustRootCertList)
+ && mUpdateIdentifier == that.mUpdateIdentifier
+ && mCredentialPriority == that.mCredentialPriority
+ && mSubscriptionCreationTimeInMs == that.mSubscriptionCreationTimeInMs
+ && mSubscriptionExpirationTimeInMs == that.mSubscriptionExpirationTimeInMs
+ && TextUtils.equals(mSubscriptionType, that.mSubscriptionType)
+ && mUsageLimitUsageTimePeriodInMinutes == that.mUsageLimitUsageTimePeriodInMinutes
+ && mUsageLimitStartTimeInMs == that.mUsageLimitStartTimeInMs
+ && mUsageLimitDataLimit == that.mUsageLimitDataLimit
+ && mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mHomeSp, mCredential, mPolicy, mSubscriptionUpdate, mTrustRootCertList,
+ mUpdateIdentifier, mCredentialPriority, mSubscriptionCreationTimeInMs,
+ mSubscriptionExpirationTimeInMs, mUsageLimitUsageTimePeriodInMinutes,
+ mUsageLimitStartTimeInMs, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes);
}
/**
@@ -88,12 +335,43 @@ public final class PasspointConfiguration implements Parcelable {
* @return true on success or false on failure
*/
public boolean validate() {
- if (homeSp == null || !homeSp.validate()) {
+ if (mHomeSp == null || !mHomeSp.validate()) {
+ return false;
+ }
+ if (mCredential == null || !mCredential.validate()) {
+ return false;
+ }
+ if (mPolicy != null && !mPolicy.validate()) {
return false;
}
- if (credential == null || !credential.validate()) {
+ if (mSubscriptionUpdate != null && !mSubscriptionUpdate.validate()) {
return false;
}
+ if (mTrustRootCertList != null) {
+ for (Map.Entry<String, byte[]> entry : mTrustRootCertList.entrySet()) {
+ String url = entry.getKey();
+ byte[] certFingerprint = entry.getValue();
+ if (TextUtils.isEmpty(url)) {
+ Log.d(TAG, "Empty URL");
+ return false;
+ }
+ if (url.getBytes(StandardCharsets.UTF_8).length > MAX_URL_BYTES) {
+ Log.d(TAG, "URL bytes exceeded the max: "
+ + url.getBytes(StandardCharsets.UTF_8).length);
+ return false;
+ }
+
+ if (certFingerprint == null) {
+ Log.d(TAG, "Fingerprint not specified");
+ return false;
+ }
+ if (certFingerprint.length != CERTIFICATE_SHA256_BYTES) {
+ Log.d(TAG, "Incorrect size of trust root certificate SHA-256 fingerprint: "
+ + certFingerprint.length);
+ return false;
+ }
+ }
+ }
return true;
}
@@ -102,13 +380,90 @@ public final class PasspointConfiguration implements Parcelable {
@Override
public PasspointConfiguration createFromParcel(Parcel in) {
PasspointConfiguration config = new PasspointConfiguration();
- config.homeSp = in.readParcelable(null);
- config.credential = in.readParcelable(null);
+ config.setHomeSp(in.readParcelable(null));
+ config.setCredential(in.readParcelable(null));
+ config.setPolicy(in.readParcelable(null));
+ config.setSubscriptionUpdate(in.readParcelable(null));
+ config.setTrustRootCertList(readTrustRootCerts(in));
+ config.setUpdateIdentifier(in.readInt());
+ config.setCredentialPriority(in.readInt());
+ config.setSubscriptionCreationTimeInMs(in.readLong());
+ config.setSubscriptionExpirationTimeInMs(in.readLong());
+ config.setSubscriptionType(in.readString());
+ config.setUsageLimitUsageTimePeriodInMinutes(in.readLong());
+ config.setUsageLimitStartTimeInMs(in.readLong());
+ config.setUsageLimitDataLimit(in.readLong());
+ config.setUsageLimitTimeLimitInMinutes(in.readLong());
return config;
}
+
@Override
public PasspointConfiguration[] newArray(int size) {
return new PasspointConfiguration[size];
}
+
+ /**
+ * Helper function for reading trust root certificate info list from a Parcel.
+ *
+ * @param in The Parcel to read from
+ * @return The list of trust root certificate URL with the corresponding certificate
+ * fingerprint
+ */
+ private Map<String, byte[]> readTrustRootCerts(Parcel in) {
+ int size = in.readInt();
+ if (size == NULL_VALUE) {
+ return null;
+ }
+ Map<String, byte[]> trustRootCerts = new HashMap<>(size);
+ for (int i = 0; i < size; i++) {
+ String key = in.readString();
+ byte[] value = in.createByteArray();
+ trustRootCerts.put(key, value);
+ }
+ return trustRootCerts;
+ }
};
+
+ /**
+ * Helper function for writing trust root certificate information list.
+ *
+ * @param dest The Parcel to write to
+ * @param trustRootCerts The list of trust root certificate URL with the corresponding
+ * certificate fingerprint
+ */
+ private static void writeTrustRootCerts(Parcel dest, Map<String, byte[]> trustRootCerts) {
+ if (trustRootCerts == null) {
+ dest.writeInt(NULL_VALUE);
+ return;
+ }
+ dest.writeInt(trustRootCerts.size());
+ for (Map.Entry<String, byte[]> entry : trustRootCerts.entrySet()) {
+ dest.writeString(entry.getKey());
+ dest.writeByteArray(entry.getValue());
+ }
+ }
+
+ /**
+ * Helper function for comparing two trust root certificate list. Cannot use Map#equals
+ * method since the value type (byte[]) doesn't override equals method.
+ *
+ * @param list1 The first trust root certificate list
+ * @param list2 The second trust root certificate list
+ * @return true if the two list are equal
+ */
+ private static boolean isTrustRootCertListEquals(Map<String, byte[]> list1,
+ Map<String, byte[]> list2) {
+ if (list1 == null || list2 == null) {
+ return list1 == list2;
+ }
+ if (list1.size() != list2.size()) {
+ return false;
+ }
+ for (Map.Entry<String, byte[]> entry : list1.entrySet()) {
+ if (!Arrays.equals(entry.getValue(), list2.get(entry.getKey()))) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java b/wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java
deleted file mode 100644
index 65a49ea6cecc..000000000000
--- a/wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java
+++ /dev/null
@@ -1,786 +0,0 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.hotspot2.omadm;
-
-import android.net.wifi.hotspot2.PasspointConfiguration;
-import android.net.wifi.hotspot2.pps.Credential;
-import android.net.wifi.hotspot2.pps.HomeSP;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.xml.sax.SAXException;
-
-/**
- * Utility class for converting OMA-DM (Open Mobile Alliance's Device Management)
- * PPS-MO (PerProviderSubscription Management Object) XML tree to a
- * {@link PasspointConfiguration} object.
- *
- * Currently this only supports PerProviderSubscription/HomeSP and
- * PerProviderSubscription/Credential subtree for Hotspot 2.0 Release 1 support.
- *
- * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
- * Release 2 Technical Specification.
- *
- * Below is a sample XML string for a Release 1 PPS MO tree:
- *
- * <MgmtTree xmlns="syncml:dmddf1.2">
- * <VerDTD>1.2</VerDTD>
- * <Node>
- * <NodeName>PerProviderSubscription</NodeName>
- * <RTProperties>
- * <Type>
- * <DDFName>urn:wfa:mo:hotspot2dot0­perprovidersubscription:1.0</DDFName>
- * </Type>
- * </RTProperties>
- * <Node>
- * <NodeName>i001</NodeName>
- * <Node>
- * <NodeName>HomeSP</NodeName>
- * <Node>
- * <NodeName>FriendlyName</NodeName>
- * <Value>Century House</Value>
- * </Node>
- * <Node>
- * <NodeName>FQDN</NodeName>
- * <Value>mi6.co.uk</Value>
- * </Node>
- * <Node>
- * <NodeName>RoamingConsortiumOI</NodeName>
- * <Value>112233,445566</Value>
- * </Node>
- * </Node>
- * <Node>
- * <NodeName>Credential</NodeName>
- * <Node>
- * <NodeName>Realm</NodeName>
- * <Value>shaken.stirred.com</Value>
- * </Node>
- * <Node>
- * <NodeName>UsernamePassword</NodeName>
- * <Node>
- * <NodeName>Username</NodeName>
- * <Value>james</Value>
- * </Node>
- * <Node>
- * <NodeName>Password</NodeName>
- * <Value>Ym9uZDAwNw==</Value>
- * </Node>
- * <Node>
- * <NodeName>EAPMethod</NodeName>
- * <Node>
- * <NodeName>EAPType</NodeName>
- * <Value>21</Value>
- * </Node>
- * <Node>
- * <NodeName>InnerMethod</NodeName>
- * <Value>MS-CHAP-V2</Value>
- * </Node>
- * </Node>
- * </Node>
- * </Node>
- * </Node>
- * </Node>
- * </MgmtTree>
- *
- * @hide
- */
-public final class PPSMOParser {
- private static final String TAG = "PPSMOParser";
-
- /**
- * XML tags expected in the PPS MO (PerProviderSubscription Management Object) XML tree.
- */
- private static final String TAG_MANAGEMENT_TREE = "MgmtTree";
- private static final String TAG_VER_DTD = "VerDTD";
- private static final String TAG_NODE = "Node";
- private static final String TAG_NODE_NAME = "NodeName";
- private static final String TAG_RT_PROPERTIES = "RTProperties";
- private static final String TAG_TYPE = "Type";
- private static final String TAG_DDF_NAME = "DDFName";
- private static final String TAG_VALUE = "Value";
-
- /**
- * Name for PerProviderSubscription node.
- */
- private static final String NODE_PER_PROVIDER_SUBSCRIPTION = "PerProviderSubscription";
-
- /**
- * Fields under HomeSP subtree.
- */
- private static final String NODE_HOMESP = "HomeSP";
- private static final String NODE_FQDN = "FQDN";
- private static final String NODE_FRIENDLY_NAME = "FriendlyName";
- private static final String NODE_ROAMING_CONSORTIUM_OI = "RoamingConsortiumOI";
-
- /**
- * Fields under Credential subtree.
- */
- private static final String NODE_CREDENTIAL = "Credential";
- private static final String NODE_USERNAME_PASSWORD = "UsernamePassword";
- private static final String NODE_USERNAME = "Username";
- private static final String NODE_PASSWORD = "Password";
- private static final String NODE_EAP_METHOD = "EAPMethod";
- private static final String NODE_EAP_TYPE = "EAPType";
- private static final String NODE_INNER_METHOD = "InnerMethod";
- private static final String NODE_DIGITAL_CERTIFICATE = "DigitalCertificate";
- private static final String NODE_CERTIFICATE_TYPE = "CertificateType";
- private static final String NODE_CERT_SHA256_FINGERPRINT = "CertSHA256FingerPrint";
- private static final String NODE_REALM = "Realm";
- private static final String NODE_SIM = "SIM";
- private static final String NODE_SIM_IMSI = "IMSI";
-
- /**
- * URN (Unique Resource Name) for PerProviderSubscription Management Object Tree.
- */
- private static final String PPS_MO_URN =
- "urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0";
-
- /**
- * Exception for generic parsing errors.
- */
- private static class ParsingException extends Exception {
- public ParsingException(String message) {
- super(message);
- }
- }
-
- /**
- * Class representing a node within the PerProviderSubscription tree.
- * This is used to flatten out and eliminate the extra layering in the XMLNode tree,
- * to make the data parsing easier and cleaner.
- *
- * A PPSNode can be an internal or a leaf node, but not both.
- *
- */
- private static abstract class PPSNode {
- private final String mName;
- public PPSNode(String name) {
- mName = name;
- }
-
- /**
- * @return the name of the node
- */
- public String getName() {
- return mName;
- }
-
- /**
- * Applies for internal node only.
- *
- * @return the list of children nodes.
- */
- public abstract List<PPSNode> getChildren();
-
- /**
- * Applies for leaf node only.
- *
- * @return the string value of the node
- */
- public abstract String getValue();
-
- /**
- * @return a flag indicating if this is a leaf or an internal node
- */
- public abstract boolean isLeaf();
- }
-
- /**
- * Class representing a leaf node in a PPS (PerProviderSubscription) tree.
- */
- private static class LeafNode extends PPSNode {
- private final String mValue;
- public LeafNode(String nodeName, String value) {
- super(nodeName);
- mValue = value;
- }
-
- @Override
- public String getValue() {
- return mValue;
- }
-
- @Override
- public List<PPSNode> getChildren() {
- return null;
- }
-
- @Override
- public boolean isLeaf() {
- return true;
- }
- }
-
- /**
- * Class representing an internal node in a PPS (PerProviderSubscription) tree.
- */
- private static class InternalNode extends PPSNode {
- private final List<PPSNode> mChildren;
- public InternalNode(String nodeName, List<PPSNode> children) {
- super(nodeName);
- mChildren = children;
- }
-
- @Override
- public String getValue() {
- return null;
- }
-
- @Override
- public List<PPSNode> getChildren() {
- return mChildren;
- }
-
- @Override
- public boolean isLeaf() {
- return false;
- }
- }
-
- /**
- * Convert a XML string representation of a PPS MO (PerProviderSubscription
- * Management Object) tree to a {@link PasspointConfiguration} object.
- *
- * @param xmlString XML string representation of a PPS MO tree
- * @return {@link PasspointConfiguration} or null
- */
- public static PasspointConfiguration parseMOText(String xmlString) {
- // Convert the XML string to a XML tree.
- XMLParser xmlParser = new XMLParser();
- XMLNode root = null;
- try {
- root = xmlParser.parse(xmlString);
- } catch(IOException | SAXException e) {
- return null;
- }
- if (root == null) {
- return null;
- }
-
- // Verify root node is a "MgmtTree" node.
- if (root.getTag() != TAG_MANAGEMENT_TREE) {
- Log.e(TAG, "Root is not a MgmtTree");
- return null;
- }
-
- String verDtd = null; // Used for detecting duplicate VerDTD element.
- PasspointConfiguration config = null;
- for (XMLNode child : root.getChildren()) {
- switch(child.getTag()) {
- case TAG_VER_DTD:
- if (verDtd != null) {
- Log.e(TAG, "Duplicate VerDTD element");
- return null;
- }
- verDtd = child.getText();
- break;
- case TAG_NODE:
- if (config != null) {
- Log.e(TAG, "Unexpected multiple Node element under MgmtTree");
- return null;
- }
- try {
- config = parsePpsNode(child);
- } catch (ParsingException e) {
- Log.e(TAG, e.getMessage());
- return null;
- }
- break;
- default:
- Log.e(TAG, "Unknown node: " + child.getTag());
- return null;
- }
- }
- return config;
- }
-
- /**
- * Parse a PerProviderSubscription node. Below is the format of the XML tree (with
- * each XML element represent a node in the tree):
- *
- * <Node>
- * <NodeName>PerProviderSubscription</NodeName>
- * <RTProperties>
- * ...
- * </RTPProperties>
- * <Node>
- * ...
- * </Node>
- * </Node>
- *
- * @param node XMLNode that contains PerProviderSubscription node.
- * @return PasspointConfiguration or null
- * @throws ParsingException
- */
- private static PasspointConfiguration parsePpsNode(XMLNode node)
- throws ParsingException {
- PasspointConfiguration config = null;
- String nodeName = null;
- for (XMLNode child : node.getChildren()) {
- switch (child.getTag()) {
- case TAG_NODE_NAME:
- if (nodeName != null) {
- throw new ParsingException("Duplicant NodeName: " + child.getText());
- }
- nodeName = child.getText();
- if (!TextUtils.equals(nodeName, NODE_PER_PROVIDER_SUBSCRIPTION)) {
- throw new ParsingException("Unexpected NodeName: " + nodeName);
- }
- break;
- case TAG_NODE:
- // Only one PerProviderSubscription instance is expected and allowed.
- if (config != null) {
- throw new ParsingException("Multiple PPS instance");
- }
- // Convert the XML tree to a PPS tree.
- PPSNode ppsInstanceRoot = buildPpsNode(child);
- config = parsePpsInstance(ppsInstanceRoot);
- break;
- case TAG_RT_PROPERTIES:
- // Parse and verify URN stored in the RT (Run Time) Properties.
- String urn = parseUrn(child);
- if (!TextUtils.equals(urn, PPS_MO_URN)) {
- throw new ParsingException("Unknown URN: " + urn);
- }
- break;
- default:
- throw new ParsingException("Unknown tag under PPS node: " + child.getTag());
- }
- }
- return config;
- }
-
- /**
- * Parse the URN stored in the RTProperties. Below is the format of the RTPProperties node:
- *
- * <RTProperties>
- * <Type>
- * <DDFName>urn:...</DDFName>
- * </Type>
- * </RTProperties>
- *
- * @param node XMLNode that contains RTProperties node.
- * @return URN String of URN.
- * @throws ParsingException
- */
- private static String parseUrn(XMLNode node) throws ParsingException {
- if (node.getChildren().size() != 1)
- throw new ParsingException("Expect RTPProperties node to only have one child");
-
- XMLNode typeNode = node.getChildren().get(0);
- if (typeNode.getChildren().size() != 1) {
- throw new ParsingException("Expect Type node to only have one child");
- }
- if (!TextUtils.equals(typeNode.getTag(), TAG_TYPE)) {
- throw new ParsingException("Unexpected tag for Type: " + typeNode.getTag());
- }
-
- XMLNode ddfNameNode = typeNode.getChildren().get(0);
- if (!ddfNameNode.getChildren().isEmpty()) {
- throw new ParsingException("Expect DDFName node to have no child");
- }
- if (!TextUtils.equals(ddfNameNode.getTag(), TAG_DDF_NAME)) {
- throw new ParsingException("Unexpected tag for DDFName: " + ddfNameNode.getTag());
- }
-
- return ddfNameNode.getText();
- }
-
- /**
- * Convert a XML tree represented by XMLNode to a PPS (PerProviderSubscription) instance tree
- * represented by PPSNode. This flattens out the XML tree to allow easier and cleaner parsing
- * of the PPS configuration data. Only three types of XML tag are expected: "NodeName",
- * "Node", and "Value".
- *
- * The original XML tree (each XML element represent a node):
- *
- * <Node>
- * <NodeName>root</NodeName>
- * <Node>
- * <NodeName>child1</NodeName>
- * <Value>value1</Value>
- * </Node>
- * <Node>
- * <NodeName>child2</NodeName>
- * <Node>
- * <NodeName>grandchild1</NodeName>
- * ...
- * </Node>
- * </Node>
- * ...
- * </Node>
- *
- * The converted PPS tree:
- *
- * [root] --- [child1, value1]
- * |
- * ---------[child2] --------[grandchild1] --- ...
- *
- * @param node XMLNode pointed to the root of a XML tree
- * @return PPSNode pointing to the root of a PPS tree
- * @throws ParsingException
- */
- private static PPSNode buildPpsNode(XMLNode node) throws ParsingException {
- String nodeName = null;
- String nodeValue = null;
- List<PPSNode> childNodes = new ArrayList<PPSNode>();
- // Names of parsed child nodes, use for detecting multiple child nodes with the same name.
- Set<String> parsedNodes = new HashSet<String>();
-
- for (XMLNode child : node.getChildren()) {
- String tag = child.getTag();
- if (TextUtils.equals(tag, TAG_NODE_NAME)) {
- if (nodeName != null) {
- throw new ParsingException("Duplicate NodeName node");
- }
- nodeName = child.getText();
- } else if (TextUtils.equals(tag, TAG_NODE)) {
- PPSNode ppsNode = buildPpsNode(child);
- if (parsedNodes.contains(ppsNode.getName())) {
- throw new ParsingException("Duplicate node: " + ppsNode.getName());
- }
- parsedNodes.add(ppsNode.getName());
- childNodes.add(ppsNode);
- } else if (TextUtils.equals(tag, TAG_VALUE)) {
- if (nodeValue != null) {
- throw new ParsingException("Duplicate Value node");
- }
- nodeValue = child.getText();
- } else {
- throw new ParsingException("Unknown tag: " + tag);
- }
- }
-
- if (nodeName == null) {
- throw new ParsingException("Invalid node: missing NodeName");
- }
- if (nodeValue == null && childNodes.size() == 0) {
- throw new ParsingException("Invalid node: " + nodeName +
- " missing both value and children");
- }
- if (nodeValue != null && childNodes.size() > 0) {
- throw new ParsingException("Invalid node: " + nodeName +
- " contained both value and children");
- }
-
- if (nodeValue != null) {
- return new LeafNode(nodeName, nodeValue);
- }
- return new InternalNode(nodeName, childNodes);
- }
-
- /**
- * Return the value of a PPSNode. An exception will be thrown if the given node
- * is not a leaf node.
- *
- * @param node PPSNode to retrieve the value from
- * @return String representing the value of the node
- * @throws ParsingException
- */
- private static String getPpsNodeValue(PPSNode node) throws ParsingException {
- if (!node.isLeaf()) {
- throw new ParsingException("Cannot get value from a non-leaf node: " + node.getName());
- }
- return node.getValue();
- }
-
- /**
- * Parse a PPS (PerProviderSubscription) configurations from a PPS tree.
- *
- * @param root PPSNode representing the root of the PPS tree
- * @return PasspointConfiguration
- * @throws ParsingException
- */
- private static PasspointConfiguration parsePpsInstance(PPSNode root)
- throws ParsingException {
- if (root.isLeaf()) {
- throw new ParsingException("Leaf node not expected for PPS instance");
- }
-
- PasspointConfiguration config = new PasspointConfiguration();
- for (PPSNode child : root.getChildren()) {
- switch(child.getName()) {
- case NODE_HOMESP:
- config.homeSp = parseHomeSP(child);
- break;
- case NODE_CREDENTIAL:
- config.credential = parseCredential(child);
- break;
- default:
- throw new ParsingException("Unknown node: " + child.getName());
- }
- }
- return config;
- }
-
- /**
- * Parse configurations under PerProviderSubscription/HomeSP subtree.
- *
- * @param node PPSNode representing the root of the PerProviderSubscription/HomeSP subtree
- * @return HomeSP
- * @throws ParsingException
- */
- private static HomeSP parseHomeSP(PPSNode node) throws ParsingException {
- if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for HomeSP");
- }
-
- HomeSP homeSp = new HomeSP();
- for (PPSNode child : node.getChildren()) {
- switch (child.getName()) {
- case NODE_FQDN:
- homeSp.fqdn = getPpsNodeValue(child);
- break;
- case NODE_FRIENDLY_NAME:
- homeSp.friendlyName = getPpsNodeValue(child);
- break;
- case NODE_ROAMING_CONSORTIUM_OI:
- homeSp.roamingConsortiumOIs =
- parseRoamingConsortiumOI(getPpsNodeValue(child));
- break;
- default:
- throw new ParsingException("Unknown node under HomeSP: " + child.getName());
- }
- }
- return homeSp;
- }
-
- /**
- * Parse the roaming consortium OI string, which contains a list of OIs separated by ",".
- *
- * @param oiStr string containing list of OIs (Organization Identifiers) separated by ","
- * @return long[]
- * @throws ParsingException
- */
- private static long[] parseRoamingConsortiumOI(String oiStr)
- throws ParsingException {
- String[] oiStrArray = oiStr.split(",");
- long[] oiArray = new long[oiStrArray.length];
- for (int i = 0; i < oiStrArray.length; i++) {
- try {
- oiArray[i] = Long.parseLong(oiStrArray[i], 16);
- } catch (NumberFormatException e) {
- throw new ParsingException("Invalid OI: " + oiStrArray[i]);
- }
- }
- return oiArray;
- }
-
- /**
- * Parse configurations under PerProviderSubscription/Credential subtree.
- *
- * @param node PPSNode representing the root of the PerProviderSubscription/Credential subtree
- * @return Credential
- * @throws ParsingException
- */
- private static Credential parseCredential(PPSNode node) throws ParsingException {
- if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for HomeSP");
- }
-
- Credential credential = new Credential();
- for (PPSNode child: node.getChildren()) {
- switch (child.getName()) {
- case NODE_USERNAME_PASSWORD:
- credential.userCredential = parseUserCredential(child);
- break;
- case NODE_DIGITAL_CERTIFICATE:
- credential.certCredential = parseCertificateCredential(child);
- break;
- case NODE_REALM:
- credential.realm = getPpsNodeValue(child);
- break;
- case NODE_SIM:
- credential.simCredential = parseSimCredential(child);
- break;
- default:
- throw new ParsingException("Unknown node under Credential: " +
- child.getName());
- }
- }
- return credential;
- }
-
- /**
- * Parse configurations under PerProviderSubscription/Credential/UsernamePassword subtree.
- *
- * @param node PPSNode representing the root of the
- * PerProviderSubscription/Credential/UsernamePassword subtree
- * @return Credential.UserCredential
- * @throws ParsingException
- */
- private static Credential.UserCredential parseUserCredential(PPSNode node)
- throws ParsingException {
- if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for UsernamePassword");
- }
-
- Credential.UserCredential userCred = new Credential.UserCredential();
- for (PPSNode child : node.getChildren()) {
- switch (child.getName()) {
- case NODE_USERNAME:
- userCred.username = getPpsNodeValue(child);
- break;
- case NODE_PASSWORD:
- userCred.password = getPpsNodeValue(child);
- break;
- case NODE_EAP_METHOD:
- parseEAPMethod(child, userCred);
- break;
- default:
- throw new ParsingException("Unknown node under UsernamPassword: " +
- child.getName());
- }
- }
- return userCred;
- }
-
- /**
- * Parse configurations under PerProviderSubscription/Credential/UsernamePassword/EAPMethod
- * subtree.
- *
- * @param node PPSNode representing the root of the
- * PerProviderSubscription/Credential/UsernamePassword/EAPMethod subtree
- * @param userCred UserCredential to be updated with EAP method values.
- * @throws ParsingException
- */
- private static void parseEAPMethod(PPSNode node, Credential.UserCredential userCred)
- throws ParsingException {
- if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for EAPMethod");
- }
-
- for (PPSNode child : node.getChildren()) {
- switch(child.getName()) {
- case NODE_EAP_TYPE:
- userCred.eapType = parseInteger(getPpsNodeValue(child));
- break;
- case NODE_INNER_METHOD:
- userCred.nonEapInnerMethod = getPpsNodeValue(child);
- break;
- default:
- throw new ParsingException("Unknown node under EAPMethod: " + child.getName());
- }
- }
- }
-
- /**
- * Parse configurations under PerProviderSubscription/Credential/DigitalCertificate subtree.
- *
- * @param node PPSNode representing the root of the
- * PerProviderSubscription/Credential/DigitalCertificate subtree
- * @return Credential.CertificateCredential
- * @throws ParsingException
- */
- private static Credential.CertificateCredential parseCertificateCredential(PPSNode node)
- throws ParsingException {
- if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for DigitalCertificate");
- }
-
- Credential.CertificateCredential certCred = new Credential.CertificateCredential();
- for (PPSNode child : node.getChildren()) {
- switch (child.getName()) {
- case NODE_CERTIFICATE_TYPE:
- certCred.certType = getPpsNodeValue(child);
- break;
- case NODE_CERT_SHA256_FINGERPRINT:
- certCred.certSha256FingerPrint = parseHexString(getPpsNodeValue(child));
- break;
- default:
- throw new ParsingException("Unknown node under DigitalCertificate: " +
- child.getName());
- }
- }
- return certCred;
- }
-
- /**
- * Parse configurations under PerProviderSubscription/Credential/SIM subtree.
- *
- * @param node PPSNode representing the root of the PerProviderSubscription/Credential/SIM
- * subtree
- * @return Credential.SimCredential
- * @throws ParsingException
- */
- private static Credential.SimCredential parseSimCredential(PPSNode node)
- throws ParsingException {
- if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for SIM");
- }
-
- Credential.SimCredential simCred = new Credential.SimCredential();
- for (PPSNode child : node.getChildren()) {
- switch (child.getName()) {
- case NODE_SIM_IMSI:
- simCred.imsi = getPpsNodeValue(child);
- break;
- case NODE_EAP_TYPE:
- simCred.eapType = parseInteger(getPpsNodeValue(child));
- break;
- default:
- throw new ParsingException("Unknown node under SIM: " + child.getName());
- }
- }
- return simCred;
- }
-
- /**
- * Convert a hex string to a byte array.
- *
- * @param str String containing hex values
- * @return byte[]
- * @throws ParsingException
- */
- private static byte[] parseHexString(String str) throws ParsingException {
- if ((str.length() & 1) == 1) {
- throw new ParsingException("Odd length hex string: " + str.length());
- }
-
- byte[] result = new byte[str.length() / 2];
- for (int i = 0; i < result.length; i++) {
- int index = i * 2;
- try {
- result[i] = (byte) Integer.parseInt(str.substring(index, index + 2), 16);
- } catch (NumberFormatException e) {
- throw new ParsingException("Invalid hex string: " + str);
- }
- }
- return result;
- }
-
- /**
- * Parse an integer string.
- *
- * @param value String of integer value
- * @return int
- * @throws ParsingException
- */
- private static int parseInteger(String value) throws ParsingException {
- try {
- return Integer.parseInt(value);
- } catch (NumberFormatException e) {
- throw new ParsingException("Invalid integer value: " + value);
- }
- }
-}
diff --git a/wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java b/wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java
new file mode 100644
index 000000000000..2ffe42859fc8
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java
@@ -0,0 +1,1652 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.hotspot2.omadm;
+
+import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.pps.Credential;
+import android.net.wifi.hotspot2.pps.HomeSp;
+import android.net.wifi.hotspot2.pps.Policy;
+import android.net.wifi.hotspot2.pps.UpdateParameter;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.xml.sax.SAXException;
+
+/**
+ * Utility class for converting OMA-DM (Open Mobile Alliance's Device Management)
+ * PPS-MO (PerProviderSubscription Management Object) XML tree to a
+ * {@link PasspointConfiguration} object.
+ *
+ * Currently this only supports PerProviderSubscription/HomeSP and
+ * PerProviderSubscription/Credential subtree for Hotspot 2.0 Release 1 support.
+ *
+ * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
+ * Release 2 Technical Specification.
+ *
+ * Below is a sample XML string for a Release 1 PPS MO tree:
+ *
+ * <MgmtTree xmlns="syncml:dmddf1.2">
+ * <VerDTD>1.2</VerDTD>
+ * <Node>
+ * <NodeName>PerProviderSubscription</NodeName>
+ * <RTProperties>
+ * <Type>
+ * <DDFName>urn:wfa:mo:hotspot2dot0­perprovidersubscription:1.0</DDFName>
+ * </Type>
+ * </RTProperties>
+ * <Node>
+ * <NodeName>i001</NodeName>
+ * <Node>
+ * <NodeName>HomeSP</NodeName>
+ * <Node>
+ * <NodeName>FriendlyName</NodeName>
+ * <Value>Century House</Value>
+ * </Node>
+ * <Node>
+ * <NodeName>FQDN</NodeName>
+ * <Value>mi6.co.uk</Value>
+ * </Node>
+ * <Node>
+ * <NodeName>RoamingConsortiumOI</NodeName>
+ * <Value>112233,445566</Value>
+ * </Node>
+ * </Node>
+ * <Node>
+ * <NodeName>Credential</NodeName>
+ * <Node>
+ * <NodeName>Realm</NodeName>
+ * <Value>shaken.stirred.com</Value>
+ * </Node>
+ * <Node>
+ * <NodeName>UsernamePassword</NodeName>
+ * <Node>
+ * <NodeName>Username</NodeName>
+ * <Value>james</Value>
+ * </Node>
+ * <Node>
+ * <NodeName>Password</NodeName>
+ * <Value>Ym9uZDAwNw==</Value>
+ * </Node>
+ * <Node>
+ * <NodeName>EAPMethod</NodeName>
+ * <Node>
+ * <NodeName>EAPType</NodeName>
+ * <Value>21</Value>
+ * </Node>
+ * <Node>
+ * <NodeName>InnerMethod</NodeName>
+ * <Value>MS-CHAP-V2</Value>
+ * </Node>
+ * </Node>
+ * </Node>
+ * </Node>
+ * </Node>
+ * </Node>
+ * </MgmtTree>
+ */
+public final class PpsMoParser {
+ private static final String TAG = "PpsMoParser";
+
+ /**
+ * XML tags expected in the PPS MO (PerProviderSubscription Management Object) XML tree.
+ */
+ private static final String TAG_MANAGEMENT_TREE = "MgmtTree";
+ private static final String TAG_VER_DTD = "VerDTD";
+ private static final String TAG_NODE = "Node";
+ private static final String TAG_NODE_NAME = "NodeName";
+ private static final String TAG_RT_PROPERTIES = "RTProperties";
+ private static final String TAG_TYPE = "Type";
+ private static final String TAG_DDF_NAME = "DDFName";
+ private static final String TAG_VALUE = "Value";
+
+ /**
+ * Name for PerProviderSubscription node.
+ */
+ private static final String NODE_PER_PROVIDER_SUBSCRIPTION = "PerProviderSubscription";
+
+ /**
+ * Fields under PerProviderSubscription.
+ */
+ private static final String NODE_UPDATE_IDENTIFIER = "UpdateIdentifier";
+ private static final String NODE_AAA_SERVER_TRUST_ROOT = "AAAServerTrustRoot";
+ private static final String NODE_SUBSCRIPTION_UPDATE = "SubscriptionUpdate";
+ private static final String NODE_SUBSCRIPTION_PARAMETER = "SubscriptionParameter";
+ private static final String NODE_TYPE_OF_SUBSCRIPTION = "TypeOfSubscription";
+ private static final String NODE_USAGE_LIMITS = "UsageLimits";
+ private static final String NODE_DATA_LIMIT = "DataLimit";
+ private static final String NODE_START_DATE = "StartDate";
+ private static final String NODE_TIME_LIMIT = "TimeLimit";
+ private static final String NODE_USAGE_TIME_PERIOD = "UsageTimePeriod";
+ private static final String NODE_CREDENTIAL_PRIORITY = "CredentialPriority";
+ /**
+ * Fields under HomeSP subtree.
+ */
+ private static final String NODE_HOMESP = "HomeSP";
+ private static final String NODE_FQDN = "FQDN";
+ private static final String NODE_FRIENDLY_NAME = "FriendlyName";
+ private static final String NODE_ROAMING_CONSORTIUM_OI = "RoamingConsortiumOI";
+ private static final String NODE_NETWORK_ID = "NetworkID";
+ private static final String NODE_SSID = "SSID";
+ private static final String NODE_HESSID = "HESSID";
+ private static final String NODE_ICON_URL = "IconURL";
+ private static final String NODE_HOME_OI_LIST = "HomeOIList";
+ private static final String NODE_HOME_OI = "HomeOI";
+ private static final String NODE_HOME_OI_REQUIRED = "HomeOIRequired";
+ private static final String NODE_OTHER_HOME_PARTNERS = "OtherHomePartners";
+
+ /**
+ * Fields under Credential subtree.
+ */
+ private static final String NODE_CREDENTIAL = "Credential";
+ private static final String NODE_CREATION_DATE = "CreationDate";
+ private static final String NODE_EXPIRATION_DATE = "ExpirationDate";
+ private static final String NODE_USERNAME_PASSWORD = "UsernamePassword";
+ private static final String NODE_USERNAME = "Username";
+ private static final String NODE_PASSWORD = "Password";
+ private static final String NODE_MACHINE_MANAGED = "MachineManaged";
+ private static final String NODE_SOFT_TOKEN_APP = "SoftTokenApp";
+ private static final String NODE_ABLE_TO_SHARE = "AbleToShare";
+ private static final String NODE_EAP_METHOD = "EAPMethod";
+ private static final String NODE_EAP_TYPE = "EAPType";
+ private static final String NODE_VENDOR_ID = "VendorId";
+ private static final String NODE_VENDOR_TYPE = "VendorType";
+ private static final String NODE_INNER_EAP_TYPE = "InnerEAPType";
+ private static final String NODE_INNER_VENDOR_ID = "InnerVendorID";
+ private static final String NODE_INNER_VENDOR_TYPE = "InnerVendorType";
+ private static final String NODE_INNER_METHOD = "InnerMethod";
+ private static final String NODE_DIGITAL_CERTIFICATE = "DigitalCertificate";
+ private static final String NODE_CERTIFICATE_TYPE = "CertificateType";
+ private static final String NODE_CERT_SHA256_FINGERPRINT = "CertSHA256Fingerprint";
+ private static final String NODE_REALM = "Realm";
+ private static final String NODE_SIM = "SIM";
+ private static final String NODE_SIM_IMSI = "IMSI";
+ private static final String NODE_CHECK_AAA_SERVER_CERT_STATUS = "CheckAAAServerCertStatus";
+
+ /**
+ * Fields under Policy subtree.
+ */
+ private static final String NODE_POLICY = "Policy";
+ private static final String NODE_PREFERRED_ROAMING_PARTNER_LIST =
+ "PreferredRoamingPartnerList";
+ private static final String NODE_FQDN_MATCH = "FQDN_Match";
+ private static final String NODE_PRIORITY = "Priority";
+ private static final String NODE_COUNTRY = "Country";
+ private static final String NODE_MIN_BACKHAUL_THRESHOLD = "MinBackhaulThreshold";
+ private static final String NODE_NETWORK_TYPE = "NetworkType";
+ private static final String NODE_DOWNLINK_BANDWIDTH = "DLBandwidth";
+ private static final String NODE_UPLINK_BANDWIDTH = "ULBandwidth";
+ private static final String NODE_POLICY_UPDATE = "PolicyUpdate";
+ private static final String NODE_UPDATE_INTERVAL = "UpdateInterval";
+ private static final String NODE_UPDATE_METHOD = "UpdateMethod";
+ private static final String NODE_RESTRICTION = "Restriction";
+ private static final String NODE_URI = "URI";
+ private static final String NODE_TRUST_ROOT = "TrustRoot";
+ private static final String NODE_CERT_URL = "CertURL";
+ private static final String NODE_SP_EXCLUSION_LIST = "SPExclusionList";
+ private static final String NODE_REQUIRED_PROTO_PORT_TUPLE = "RequiredProtoPortTuple";
+ private static final String NODE_IP_PROTOCOL = "IPProtocol";
+ private static final String NODE_PORT_NUMBER = "PortNumber";
+ private static final String NODE_MAXIMUM_BSS_LOAD_VALUE = "MaximumBSSLoadValue";
+ private static final String NODE_OTHER = "Other";
+
+ /**
+ * URN (Unique Resource Name) for PerProviderSubscription Management Object Tree.
+ */
+ private static final String PPS_MO_URN =
+ "urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0";
+
+ /**
+ * Exception for generic parsing errors.
+ */
+ private static class ParsingException extends Exception {
+ public ParsingException(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * Class representing a node within the PerProviderSubscription tree.
+ * This is used to flatten out and eliminate the extra layering in the XMLNode tree,
+ * to make the data parsing easier and cleaner.
+ *
+ * A PPSNode can be an internal or a leaf node, but not both.
+ *
+ */
+ private static abstract class PPSNode {
+ private final String mName;
+ public PPSNode(String name) {
+ mName = name;
+ }
+
+ /**
+ * @return the name of the node
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Applies for internal node only.
+ *
+ * @return the list of children nodes.
+ */
+ public abstract List<PPSNode> getChildren();
+
+ /**
+ * Applies for leaf node only.
+ *
+ * @return the string value of the node
+ */
+ public abstract String getValue();
+
+ /**
+ * @return a flag indicating if this is a leaf or an internal node
+ */
+ public abstract boolean isLeaf();
+ }
+
+ /**
+ * Class representing a leaf node in a PPS (PerProviderSubscription) tree.
+ */
+ private static class LeafNode extends PPSNode {
+ private final String mValue;
+ public LeafNode(String nodeName, String value) {
+ super(nodeName);
+ mValue = value;
+ }
+
+ @Override
+ public String getValue() {
+ return mValue;
+ }
+
+ @Override
+ public List<PPSNode> getChildren() {
+ return null;
+ }
+
+ @Override
+ public boolean isLeaf() {
+ return true;
+ }
+ }
+
+ /**
+ * Class representing an internal node in a PPS (PerProviderSubscription) tree.
+ */
+ private static class InternalNode extends PPSNode {
+ private final List<PPSNode> mChildren;
+ public InternalNode(String nodeName, List<PPSNode> children) {
+ super(nodeName);
+ mChildren = children;
+ }
+
+ @Override
+ public String getValue() {
+ return null;
+ }
+
+ @Override
+ public List<PPSNode> getChildren() {
+ return mChildren;
+ }
+
+ @Override
+ public boolean isLeaf() {
+ return false;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public PpsMoParser() {}
+
+ /**
+ * Convert a XML string representation of a PPS MO (PerProviderSubscription
+ * Management Object) tree to a {@link PasspointConfiguration} object.
+ *
+ * @param xmlString XML string representation of a PPS MO tree
+ * @return {@link PasspointConfiguration} or null
+ */
+ public static PasspointConfiguration parseMoText(String xmlString) {
+ // Convert the XML string to a XML tree.
+ XMLParser xmlParser = new XMLParser();
+ XMLNode root = null;
+ try {
+ root = xmlParser.parse(xmlString);
+ } catch(IOException | SAXException e) {
+ return null;
+ }
+ if (root == null) {
+ return null;
+ }
+
+ // Verify root node is a "MgmtTree" node.
+ if (root.getTag() != TAG_MANAGEMENT_TREE) {
+ Log.e(TAG, "Root is not a MgmtTree");
+ return null;
+ }
+
+ String verDtd = null; // Used for detecting duplicate VerDTD element.
+ PasspointConfiguration config = null;
+ for (XMLNode child : root.getChildren()) {
+ switch(child.getTag()) {
+ case TAG_VER_DTD:
+ if (verDtd != null) {
+ Log.e(TAG, "Duplicate VerDTD element");
+ return null;
+ }
+ verDtd = child.getText();
+ break;
+ case TAG_NODE:
+ if (config != null) {
+ Log.e(TAG, "Unexpected multiple Node element under MgmtTree");
+ return null;
+ }
+ try {
+ config = parsePpsNode(child);
+ } catch (ParsingException e) {
+ Log.e(TAG, e.getMessage());
+ return null;
+ }
+ break;
+ default:
+ Log.e(TAG, "Unknown node: " + child.getTag());
+ return null;
+ }
+ }
+ return config;
+ }
+
+ /**
+ * Parse a PerProviderSubscription node. Below is the format of the XML tree (with
+ * each XML element represent a node in the tree):
+ *
+ * <Node>
+ * <NodeName>PerProviderSubscription</NodeName>
+ * <RTProperties>
+ * ...
+ * </RTPProperties>
+ * <Node>
+ * <NodeName>UpdateIdentifier</NodeName>
+ * <Value>...</Value>
+ * </Node>
+ * <Node>
+ * ...
+ * </Node>
+ * </Node>
+ *
+ * @param node XMLNode that contains PerProviderSubscription node.
+ * @return PasspointConfiguration or null
+ * @throws ParsingException
+ */
+ private static PasspointConfiguration parsePpsNode(XMLNode node)
+ throws ParsingException {
+ PasspointConfiguration config = null;
+ String nodeName = null;
+ int updateIdentifier = Integer.MIN_VALUE;
+ for (XMLNode child : node.getChildren()) {
+ switch (child.getTag()) {
+ case TAG_NODE_NAME:
+ if (nodeName != null) {
+ throw new ParsingException("Duplicate NodeName: " + child.getText());
+ }
+ nodeName = child.getText();
+ if (!TextUtils.equals(nodeName, NODE_PER_PROVIDER_SUBSCRIPTION)) {
+ throw new ParsingException("Unexpected NodeName: " + nodeName);
+ }
+ break;
+ case TAG_NODE:
+ // A node can be either an UpdateIdentifier node or a PerProviderSubscription
+ // instance node. Flatten out the XML tree first by converting it to a PPS
+ // tree to reduce the complexity of the parsing code.
+ PPSNode ppsNodeRoot = buildPpsNode(child);
+ if (TextUtils.equals(ppsNodeRoot.getName(), NODE_UPDATE_IDENTIFIER)) {
+ if (updateIdentifier != Integer.MIN_VALUE) {
+ throw new ParsingException("Multiple node for UpdateIdentifier");
+ }
+ updateIdentifier = parseInteger(getPpsNodeValue(ppsNodeRoot));
+ } else {
+ // Only one PerProviderSubscription instance is expected and allowed.
+ if (config != null) {
+ throw new ParsingException("Multiple PPS instance");
+ }
+ config = parsePpsInstance(ppsNodeRoot);
+ }
+ break;
+ case TAG_RT_PROPERTIES:
+ // Parse and verify URN stored in the RT (Run Time) Properties.
+ String urn = parseUrn(child);
+ if (!TextUtils.equals(urn, PPS_MO_URN)) {
+ throw new ParsingException("Unknown URN: " + urn);
+ }
+ break;
+ default:
+ throw new ParsingException("Unknown tag under PPS node: " + child.getTag());
+ }
+ }
+ if (config != null && updateIdentifier != Integer.MIN_VALUE) {
+ config.setUpdateIdentifier(updateIdentifier);
+ }
+ return config;
+ }
+
+ /**
+ * Parse the URN stored in the RTProperties. Below is the format of the RTPProperties node:
+ *
+ * <RTProperties>
+ * <Type>
+ * <DDFName>urn:...</DDFName>
+ * </Type>
+ * </RTProperties>
+ *
+ * @param node XMLNode that contains RTProperties node.
+ * @return URN String of URN.
+ * @throws ParsingException
+ */
+ private static String parseUrn(XMLNode node) throws ParsingException {
+ if (node.getChildren().size() != 1)
+ throw new ParsingException("Expect RTPProperties node to only have one child");
+
+ XMLNode typeNode = node.getChildren().get(0);
+ if (typeNode.getChildren().size() != 1) {
+ throw new ParsingException("Expect Type node to only have one child");
+ }
+ if (!TextUtils.equals(typeNode.getTag(), TAG_TYPE)) {
+ throw new ParsingException("Unexpected tag for Type: " + typeNode.getTag());
+ }
+
+ XMLNode ddfNameNode = typeNode.getChildren().get(0);
+ if (!ddfNameNode.getChildren().isEmpty()) {
+ throw new ParsingException("Expect DDFName node to have no child");
+ }
+ if (!TextUtils.equals(ddfNameNode.getTag(), TAG_DDF_NAME)) {
+ throw new ParsingException("Unexpected tag for DDFName: " + ddfNameNode.getTag());
+ }
+
+ return ddfNameNode.getText();
+ }
+
+ /**
+ * Convert a XML tree represented by XMLNode to a PPS (PerProviderSubscription) instance tree
+ * represented by PPSNode. This flattens out the XML tree to allow easier and cleaner parsing
+ * of the PPS configuration data. Only three types of XML tag are expected: "NodeName",
+ * "Node", and "Value".
+ *
+ * The original XML tree (each XML element represent a node):
+ *
+ * <Node>
+ * <NodeName>root</NodeName>
+ * <Node>
+ * <NodeName>child1</NodeName>
+ * <Value>value1</Value>
+ * </Node>
+ * <Node>
+ * <NodeName>child2</NodeName>
+ * <Node>
+ * <NodeName>grandchild1</NodeName>
+ * ...
+ * </Node>
+ * </Node>
+ * ...
+ * </Node>
+ *
+ * The converted PPS tree:
+ *
+ * [root] --- [child1, value1]
+ * |
+ * ---------[child2] --------[grandchild1] --- ...
+ *
+ * @param node XMLNode pointed to the root of a XML tree
+ * @return PPSNode pointing to the root of a PPS tree
+ * @throws ParsingException
+ */
+ private static PPSNode buildPpsNode(XMLNode node) throws ParsingException {
+ String nodeName = null;
+ String nodeValue = null;
+ List<PPSNode> childNodes = new ArrayList<PPSNode>();
+ // Names of parsed child nodes, use for detecting multiple child nodes with the same name.
+ Set<String> parsedNodes = new HashSet<String>();
+
+ for (XMLNode child : node.getChildren()) {
+ String tag = child.getTag();
+ if (TextUtils.equals(tag, TAG_NODE_NAME)) {
+ if (nodeName != null) {
+ throw new ParsingException("Duplicate NodeName node");
+ }
+ nodeName = child.getText();
+ } else if (TextUtils.equals(tag, TAG_NODE)) {
+ PPSNode ppsNode = buildPpsNode(child);
+ if (parsedNodes.contains(ppsNode.getName())) {
+ throw new ParsingException("Duplicate node: " + ppsNode.getName());
+ }
+ parsedNodes.add(ppsNode.getName());
+ childNodes.add(ppsNode);
+ } else if (TextUtils.equals(tag, TAG_VALUE)) {
+ if (nodeValue != null) {
+ throw new ParsingException("Duplicate Value node");
+ }
+ nodeValue = child.getText();
+ } else {
+ throw new ParsingException("Unknown tag: " + tag);
+ }
+ }
+
+ if (nodeName == null) {
+ throw new ParsingException("Invalid node: missing NodeName");
+ }
+ if (nodeValue == null && childNodes.size() == 0) {
+ throw new ParsingException("Invalid node: " + nodeName +
+ " missing both value and children");
+ }
+ if (nodeValue != null && childNodes.size() > 0) {
+ throw new ParsingException("Invalid node: " + nodeName +
+ " contained both value and children");
+ }
+
+ if (nodeValue != null) {
+ return new LeafNode(nodeName, nodeValue);
+ }
+ return new InternalNode(nodeName, childNodes);
+ }
+
+ /**
+ * Return the value of a PPSNode. An exception will be thrown if the given node
+ * is not a leaf node.
+ *
+ * @param node PPSNode to retrieve the value from
+ * @return String representing the value of the node
+ * @throws ParsingException
+ */
+ private static String getPpsNodeValue(PPSNode node) throws ParsingException {
+ if (!node.isLeaf()) {
+ throw new ParsingException("Cannot get value from a non-leaf node: " + node.getName());
+ }
+ return node.getValue();
+ }
+
+ /**
+ * Parse a PPS (PerProviderSubscription) configurations from a PPS tree.
+ *
+ * @param root PPSNode representing the root of the PPS tree
+ * @return PasspointConfiguration
+ * @throws ParsingException
+ */
+ private static PasspointConfiguration parsePpsInstance(PPSNode root)
+ throws ParsingException {
+ if (root.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for PPS instance");
+ }
+
+ PasspointConfiguration config = new PasspointConfiguration();
+ for (PPSNode child : root.getChildren()) {
+ switch(child.getName()) {
+ case NODE_HOMESP:
+ config.setHomeSp(parseHomeSP(child));
+ break;
+ case NODE_CREDENTIAL:
+ config.setCredential(parseCredential(child));
+ break;
+ case NODE_POLICY:
+ config.setPolicy(parsePolicy(child));
+ break;
+ case NODE_AAA_SERVER_TRUST_ROOT:
+ config.setTrustRootCertList(parseAAAServerTrustRootList(child));
+ break;
+ case NODE_SUBSCRIPTION_UPDATE:
+ config.setSubscriptionUpdate(parseUpdateParameter(child));
+ break;
+ case NODE_SUBSCRIPTION_PARAMETER:
+ parseSubscriptionParameter(child, config);
+ break;
+ case NODE_CREDENTIAL_PRIORITY:
+ config.setCredentialPriority(parseInteger(getPpsNodeValue(child)));
+ break;
+ default:
+ throw new ParsingException("Unknown node: " + child.getName());
+ }
+ }
+ return config;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP subtree.
+ *
+ * @param node PPSNode representing the root of the PerProviderSubscription/HomeSP subtree
+ * @return HomeSP
+ * @throws ParsingException
+ */
+ private static HomeSp parseHomeSP(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for HomeSP");
+ }
+
+ HomeSp homeSp = new HomeSp();
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_FQDN:
+ homeSp.setFqdn(getPpsNodeValue(child));
+ break;
+ case NODE_FRIENDLY_NAME:
+ homeSp.setFriendlyName(getPpsNodeValue(child));
+ break;
+ case NODE_ROAMING_CONSORTIUM_OI:
+ homeSp.setRoamingConsortiumOis(
+ parseRoamingConsortiumOI(getPpsNodeValue(child)));
+ break;
+ case NODE_ICON_URL:
+ homeSp.setIconUrl(getPpsNodeValue(child));
+ break;
+ case NODE_NETWORK_ID:
+ homeSp.setHomeNetworkIds(parseNetworkIds(child));
+ break;
+ case NODE_HOME_OI_LIST:
+ Pair<List<Long>, List<Long>> homeOIs = parseHomeOIList(child);
+ homeSp.setMatchAllOis(convertFromLongList(homeOIs.first));
+ homeSp.setMatchAnyOis(convertFromLongList(homeOIs.second));
+ break;
+ case NODE_OTHER_HOME_PARTNERS:
+ homeSp.setOtherHomePartners(parseOtherHomePartners(child));
+ break;
+ default:
+ throw new ParsingException("Unknown node under HomeSP: " + child.getName());
+ }
+ }
+ return homeSp;
+ }
+
+ /**
+ * Parse the roaming consortium OI string, which contains a list of OIs separated by ",".
+ *
+ * @param oiStr string containing list of OIs (Organization Identifiers) separated by ","
+ * @return long[]
+ * @throws ParsingException
+ */
+ private static long[] parseRoamingConsortiumOI(String oiStr)
+ throws ParsingException {
+ String[] oiStrArray = oiStr.split(",");
+ long[] oiArray = new long[oiStrArray.length];
+ for (int i = 0; i < oiStrArray.length; i++) {
+ oiArray[i] = parseLong(oiStrArray[i], 16);
+ }
+ return oiArray;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP/NetworkID subtree.
+ *
+ * @param node PPSNode representing the root of the PerProviderSubscription/HomeSP/NetworkID
+ * subtree
+ * @return HashMap<String, Long> representing list of <SSID, HESSID> pair.
+ * @throws ParsingException
+ */
+ static private Map<String, Long> parseNetworkIds(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for NetworkID");
+ }
+
+ Map<String, Long> networkIds = new HashMap<>();
+ for (PPSNode child : node.getChildren()) {
+ Pair<String, Long> networkId = parseNetworkIdInstance(child);
+ networkIds.put(networkId.first, networkId.second);
+ }
+ return networkIds;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP/NetworkID/<X+> subtree.
+ * The instance name (<X+>) is irrelevant and must be unique for each instance, which
+ * is verified when the PPS tree is constructed {@link #buildPpsNode}.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/HomeSP/NetworkID/<X+> subtree
+ * @return Pair<String, Long> representing <SSID, HESSID> pair.
+ * @throws ParsingException
+ */
+ static private Pair<String, Long> parseNetworkIdInstance(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for NetworkID instance");
+ }
+
+ String ssid = null;
+ Long hessid = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_SSID:
+ ssid = getPpsNodeValue(child);
+ break;
+ case NODE_HESSID:
+ hessid = parseLong(getPpsNodeValue(child), 16);
+ break;
+ default:
+ throw new ParsingException("Unknown node under NetworkID instance: " +
+ child.getName());
+ }
+ }
+ if (ssid == null)
+ throw new ParsingException("NetworkID instance missing SSID");
+
+ return new Pair<String, Long>(ssid, hessid);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP/HomeOIList subtree.
+ *
+ * @param node PPSNode representing the root of the PerProviderSubscription/HomeSP/HomeOIList
+ * subtree
+ * @return Pair<List<Long>, List<Long>> containing both MatchAllOIs and MatchAnyOIs list.
+ * @throws ParsingException
+ */
+ private static Pair<List<Long>, List<Long>> parseHomeOIList(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for HomeOIList");
+ }
+
+ List<Long> matchAllOIs = new ArrayList<Long>();
+ List<Long> matchAnyOIs = new ArrayList<Long>();
+ for (PPSNode child : node.getChildren()) {
+ Pair<Long, Boolean> homeOI = parseHomeOIInstance(child);
+ if (homeOI.second.booleanValue()) {
+ matchAllOIs.add(homeOI.first);
+ } else {
+ matchAnyOIs.add(homeOI.first);
+ }
+ }
+ return new Pair<List<Long>, List<Long>>(matchAllOIs, matchAnyOIs);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP/HomeOIList/<X+> subtree.
+ * The instance name (<X+>) is irrelevant and must be unique for each instance, which
+ * is verified when the PPS tree is constructed {@link #buildPpsNode}.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/HomeSP/HomeOIList/<X+> subtree
+ * @return Pair<Long, Boolean> containing a HomeOI and a HomeOIRequired flag
+ * @throws ParsingException
+ */
+ private static Pair<Long, Boolean> parseHomeOIInstance(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for HomeOI instance");
+ }
+
+ Long oi = null;
+ Boolean required = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_HOME_OI:
+ try {
+ oi = Long.valueOf(getPpsNodeValue(child), 16);
+ } catch (NumberFormatException e) {
+ throw new ParsingException("Invalid HomeOI: " + getPpsNodeValue(child));
+ }
+ break;
+ case NODE_HOME_OI_REQUIRED:
+ required = Boolean.valueOf(getPpsNodeValue(child));
+ break;
+ default:
+ throw new ParsingException("Unknown node under NetworkID instance: " +
+ child.getName());
+ }
+ }
+ if (oi == null) {
+ throw new ParsingException("HomeOI instance missing OI field");
+ }
+ if (required == null) {
+ throw new ParsingException("HomeOI instance missing required field");
+ }
+ return new Pair<Long, Boolean>(oi, required);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP/OtherHomePartners subtree.
+ * This contains a list of FQDN (Fully Qualified Domain Name) that are considered
+ * home partners.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/HomeSP/OtherHomePartners subtree
+ * @return String[] list of partner's FQDN
+ * @throws ParsingException
+ */
+ private static String[] parseOtherHomePartners(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for OtherHomePartners");
+ }
+ List<String> otherHomePartners = new ArrayList<String>();
+ for (PPSNode child : node.getChildren()) {
+ String fqdn = parseOtherHomePartnerInstance(child);
+ otherHomePartners.add(fqdn);
+ }
+ return otherHomePartners.toArray(new String[otherHomePartners.size()]);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/HomeSP/OtherHomePartners/<X+> subtree.
+ * The instance name (<X+>) is irrelevant and must be unique for each instance, which
+ * is verified when the PPS tree is constructed {@link #buildPpsNode}.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/HomeSP/OtherHomePartners/<X+> subtree
+ * @return String FQDN of the partner
+ * @throws ParsingException
+ */
+ private static String parseOtherHomePartnerInstance(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for OtherHomePartner instance");
+ }
+ String fqdn = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_FQDN:
+ fqdn = getPpsNodeValue(child);
+ break;
+ default:
+ throw new ParsingException(
+ "Unknown node under OtherHomePartner instance: " + child.getName());
+ }
+ }
+ if (fqdn == null) {
+ throw new ParsingException("OtherHomePartner instance missing FQDN field");
+ }
+ return fqdn;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Credential subtree.
+ *
+ * @param node PPSNode representing the root of the PerProviderSubscription/Credential subtree
+ * @return Credential
+ * @throws ParsingException
+ */
+ private static Credential parseCredential(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for HomeSP");
+ }
+
+ Credential credential = new Credential();
+ for (PPSNode child: node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_CREATION_DATE:
+ credential.setCreationTimeInMs(parseDate(getPpsNodeValue(child)));
+ break;
+ case NODE_EXPIRATION_DATE:
+ credential.setExpirationTimeInMs(parseDate(getPpsNodeValue(child)));
+ break;
+ case NODE_USERNAME_PASSWORD:
+ credential.setUserCredential(parseUserCredential(child));
+ break;
+ case NODE_DIGITAL_CERTIFICATE:
+ credential.setCertCredential(parseCertificateCredential(child));
+ break;
+ case NODE_REALM:
+ credential.setRealm(getPpsNodeValue(child));
+ break;
+ case NODE_CHECK_AAA_SERVER_CERT_STATUS:
+ credential.setCheckAaaServerCertStatus(
+ Boolean.parseBoolean(getPpsNodeValue(child)));
+ break;
+ case NODE_SIM:
+ credential.setSimCredential(parseSimCredential(child));
+ break;
+ default:
+ throw new ParsingException("Unknown node under Credential: " +
+ child.getName());
+ }
+ }
+ return credential;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Credential/UsernamePassword subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Credential/UsernamePassword subtree
+ * @return Credential.UserCredential
+ * @throws ParsingException
+ */
+ private static Credential.UserCredential parseUserCredential(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for UsernamePassword");
+ }
+
+ Credential.UserCredential userCred = new Credential.UserCredential();
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_USERNAME:
+ userCred.setUsername(getPpsNodeValue(child));
+ break;
+ case NODE_PASSWORD:
+ userCred.setPassword(getPpsNodeValue(child));
+ break;
+ case NODE_MACHINE_MANAGED:
+ userCred.setMachineManaged(Boolean.parseBoolean(getPpsNodeValue(child)));
+ break;
+ case NODE_SOFT_TOKEN_APP:
+ userCred.setSoftTokenApp(getPpsNodeValue(child));
+ break;
+ case NODE_ABLE_TO_SHARE:
+ userCred.setAbleToShare(Boolean.parseBoolean(getPpsNodeValue(child)));
+ break;
+ case NODE_EAP_METHOD:
+ parseEAPMethod(child, userCred);
+ break;
+ default:
+ throw new ParsingException("Unknown node under UsernamPassword: " +
+ child.getName());
+ }
+ }
+ return userCred;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Credential/UsernamePassword/EAPMethod
+ * subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Credential/UsernamePassword/EAPMethod subtree
+ * @param userCred UserCredential to be updated with EAP method values.
+ * @throws ParsingException
+ */
+ private static void parseEAPMethod(PPSNode node, Credential.UserCredential userCred)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for EAPMethod");
+ }
+
+ for (PPSNode child : node.getChildren()) {
+ switch(child.getName()) {
+ case NODE_EAP_TYPE:
+ userCred.setEapType(parseInteger(getPpsNodeValue(child)));
+ break;
+ case NODE_INNER_METHOD:
+ userCred.setNonEapInnerMethod(getPpsNodeValue(child));
+ break;
+ case NODE_VENDOR_ID:
+ case NODE_VENDOR_TYPE:
+ case NODE_INNER_EAP_TYPE:
+ case NODE_INNER_VENDOR_ID:
+ case NODE_INNER_VENDOR_TYPE:
+ // Only EAP-TTLS is currently supported for user credential, which doesn't
+ // use any of these parameters.
+ Log.d(TAG, "Ignore unsupported EAP method parameter: " + child.getName());
+ break;
+ default:
+ throw new ParsingException("Unknown node under EAPMethod: " + child.getName());
+ }
+ }
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Credential/DigitalCertificate subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Credential/DigitalCertificate subtree
+ * @return Credential.CertificateCredential
+ * @throws ParsingException
+ */
+ private static Credential.CertificateCredential parseCertificateCredential(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for DigitalCertificate");
+ }
+
+ Credential.CertificateCredential certCred = new Credential.CertificateCredential();
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_CERTIFICATE_TYPE:
+ certCred.setCertType(getPpsNodeValue(child));
+ break;
+ case NODE_CERT_SHA256_FINGERPRINT:
+ certCred.setCertSha256Fingerprint(parseHexString(getPpsNodeValue(child)));
+ break;
+ default:
+ throw new ParsingException("Unknown node under DigitalCertificate: " +
+ child.getName());
+ }
+ }
+ return certCred;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Credential/SIM subtree.
+ *
+ * @param node PPSNode representing the root of the PerProviderSubscription/Credential/SIM
+ * subtree
+ * @return Credential.SimCredential
+ * @throws ParsingException
+ */
+ private static Credential.SimCredential parseSimCredential(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for SIM");
+ }
+
+ Credential.SimCredential simCred = new Credential.SimCredential();
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_SIM_IMSI:
+ simCred.setImsi(getPpsNodeValue(child));
+ break;
+ case NODE_EAP_TYPE:
+ simCred.setEapType(parseInteger(getPpsNodeValue(child)));
+ break;
+ default:
+ throw new ParsingException("Unknown node under SIM: " + child.getName());
+ }
+ }
+ return simCred;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy subtree.
+ *
+ * @param node PPSNode representing the root of the PerProviderSubscription/Policy subtree
+ * @return {@link Policy}
+ * @throws ParsingException
+ */
+ private static Policy parsePolicy(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for Policy");
+ }
+
+ Policy policy = new Policy();
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_PREFERRED_ROAMING_PARTNER_LIST:
+ policy.setPreferredRoamingPartnerList(parsePreferredRoamingPartnerList(child));
+ break;
+ case NODE_MIN_BACKHAUL_THRESHOLD:
+ parseMinBackhaulThreshold(child, policy);
+ break;
+ case NODE_POLICY_UPDATE:
+ policy.setPolicyUpdate(parseUpdateParameter(child));
+ break;
+ case NODE_SP_EXCLUSION_LIST:
+ policy.setExcludedSsidList(parseSpExclusionList(child));
+ break;
+ case NODE_REQUIRED_PROTO_PORT_TUPLE:
+ policy.setRequiredProtoPortMap(parseRequiredProtoPortTuple(child));
+ break;
+ case NODE_MAXIMUM_BSS_LOAD_VALUE:
+ policy.setMaximumBssLoadValue(parseInteger(getPpsNodeValue(child)));
+ break;
+ default:
+ throw new ParsingException("Unknown node under Policy: " + child.getName());
+ }
+ }
+ return policy;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy/PreferredRoamingPartnerList
+ * subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Policy/PreferredRoamingPartnerList subtree
+ * @return List of {@link Policy#RoamingPartner}
+ * @throws ParsingException
+ */
+ private static List<Policy.RoamingPartner> parsePreferredRoamingPartnerList(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for PreferredRoamingPartnerList");
+ }
+ List<Policy.RoamingPartner> partnerList = new ArrayList<>();
+ for (PPSNode child : node.getChildren()) {
+ partnerList.add(parsePreferredRoamingPartner(child));
+ }
+ return partnerList;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy/PreferredRoamingPartnerList/<X+>
+ * subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Policy/PreferredRoamingPartnerList/<X+> subtree
+ * @return {@link Policy#RoamingPartner}
+ * @throws ParsingException
+ */
+ private static Policy.RoamingPartner parsePreferredRoamingPartner(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for PreferredRoamingPartner "
+ + "instance");
+ }
+
+ Policy.RoamingPartner roamingPartner = new Policy.RoamingPartner();
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_FQDN_MATCH:
+ // FQDN_Match field is in the format of "[FQDN],[MatchInfo]", where [MatchInfo]
+ // is either "exactMatch" for exact match of FQDN or "includeSubdomains" for
+ // matching all FQDNs with the same sub-domain.
+ String fqdnMatch = getPpsNodeValue(child);
+ String[] fqdnMatchArray = fqdnMatch.split(",");
+ if (fqdnMatchArray.length != 2) {
+ throw new ParsingException("Invalid FQDN_Match: " + fqdnMatch);
+ }
+ roamingPartner.setFqdn(fqdnMatchArray[0]);
+ if (TextUtils.equals(fqdnMatchArray[1], "exactMatch")) {
+ roamingPartner.setFqdnExactMatch(true);
+ } else if (TextUtils.equals(fqdnMatchArray[1], "includeSubdomains")) {
+ roamingPartner.setFqdnExactMatch(false);
+ } else {
+ throw new ParsingException("Invalid FQDN_Match: " + fqdnMatch);
+ }
+ break;
+ case NODE_PRIORITY:
+ roamingPartner.setPriority(parseInteger(getPpsNodeValue(child)));
+ break;
+ case NODE_COUNTRY:
+ roamingPartner.setCountries(getPpsNodeValue(child));
+ break;
+ default:
+ throw new ParsingException("Unknown node under PreferredRoamingPartnerList "
+ + "instance " + child.getName());
+ }
+ }
+ return roamingPartner;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy/MinBackhaulThreshold subtree
+ * into the given policy.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Policy/MinBackhaulThreshold subtree
+ * @param policy The policy to store the MinBackhualThreshold configuration
+ * @throws ParsingException
+ */
+ private static void parseMinBackhaulThreshold(PPSNode node, Policy policy)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for MinBackhaulThreshold");
+ }
+ for (PPSNode child : node.getChildren()) {
+ parseMinBackhaulThresholdInstance(child, policy);
+ }
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy/MinBackhaulThreshold/<X+> subtree
+ * into the given policy.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Policy/MinBackhaulThreshold/<X+> subtree
+ * @param policy The policy to store the MinBackhaulThreshold configuration
+ * @throws ParsingException
+ */
+ private static void parseMinBackhaulThresholdInstance(PPSNode node, Policy policy)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for MinBackhaulThreshold instance");
+ }
+ String networkType = null;
+ long downlinkBandwidth = Long.MIN_VALUE;
+ long uplinkBandwidth = Long.MIN_VALUE;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_NETWORK_TYPE:
+ networkType = getPpsNodeValue(child);
+ break;
+ case NODE_DOWNLINK_BANDWIDTH:
+ downlinkBandwidth = parseLong(getPpsNodeValue(child), 10);
+ break;
+ case NODE_UPLINK_BANDWIDTH:
+ uplinkBandwidth = parseLong(getPpsNodeValue(child), 10);
+ break;
+ default:
+ throw new ParsingException("Unknown node under MinBackhaulThreshold instance "
+ + child.getName());
+ }
+ }
+ if (networkType == null) {
+ throw new ParsingException("Missing NetworkType field");
+ }
+
+ if (TextUtils.equals(networkType, "home")) {
+ policy.setMinHomeDownlinkBandwidth(downlinkBandwidth);
+ policy.setMinHomeUplinkBandwidth(uplinkBandwidth);
+ } else if (TextUtils.equals(networkType, "roaming")) {
+ policy.setMinRoamingDownlinkBandwidth(downlinkBandwidth);
+ policy.setMinRoamingUplinkBandwidth(uplinkBandwidth);
+ } else {
+ throw new ParsingException("Invalid network type: " + networkType);
+ }
+ }
+
+ /**
+ * Parse update parameters. This contained configurations from either
+ * PerProviderSubscription/Policy/PolicyUpdate or PerProviderSubscription/SubscriptionUpdate
+ * subtree.
+ *
+ * @param node PPSNode representing the root of the PerProviderSubscription/Policy/PolicyUpdate
+ * or PerProviderSubscription/SubscriptionUpdate subtree
+ * @return {@link UpdateParameter}
+ * @throws ParsingException
+ */
+ private static UpdateParameter parseUpdateParameter(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for Update Parameters");
+ }
+
+ UpdateParameter updateParam = new UpdateParameter();
+ for (PPSNode child : node.getChildren()) {
+ switch(child.getName()) {
+ case NODE_UPDATE_INTERVAL:
+ updateParam.setUpdateIntervalInMinutes(parseLong(getPpsNodeValue(child), 10));
+ break;
+ case NODE_UPDATE_METHOD:
+ updateParam.setUpdateMethod(getPpsNodeValue(child));
+ break;
+ case NODE_RESTRICTION:
+ updateParam.setRestriction(getPpsNodeValue(child));
+ break;
+ case NODE_URI:
+ updateParam.setServerUri(getPpsNodeValue(child));
+ break;
+ case NODE_USERNAME_PASSWORD:
+ Pair<String, String> usernamePassword = parseUpdateUserCredential(child);
+ updateParam.setUsername(usernamePassword.first);
+ updateParam.setBase64EncodedPassword(usernamePassword.second);
+ break;
+ case NODE_TRUST_ROOT:
+ Pair<String, byte[]> trustRoot = parseTrustRoot(child);
+ updateParam.setTrustRootCertUrl(trustRoot.first);
+ updateParam.setTrustRootCertSha256Fingerprint(trustRoot.second);
+ break;
+ case NODE_OTHER:
+ Log.d(TAG, "Ignore unsupported paramter: " + child.getName());
+ break;
+ default:
+ throw new ParsingException("Unknown node under Update Parameters: "
+ + child.getName());
+ }
+ }
+ return updateParam;
+ }
+
+ /**
+ * Parse username and password parameters associated with policy or subscription update.
+ * This contained configurations under either
+ * PerProviderSubscription/Policy/PolicyUpdate/UsernamePassword or
+ * PerProviderSubscription/SubscriptionUpdate/UsernamePassword subtree.
+ *
+ * @param node PPSNode representing the root of the UsernamePassword subtree
+ * @return Pair of username and password
+ * @throws ParsingException
+ */
+ private static Pair<String, String> parseUpdateUserCredential(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for UsernamePassword");
+ }
+
+ String username = null;
+ String password = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_USERNAME:
+ username = getPpsNodeValue(child);
+ break;
+ case NODE_PASSWORD:
+ password = getPpsNodeValue(child);
+ break;
+ default:
+ throw new ParsingException("Unknown node under UsernamePassword: "
+ + child.getName());
+ }
+ }
+ return Pair.create(username, password);
+ }
+
+ /**
+ * Parse the trust root parameters associated with policy update, subscription update, or AAA
+ * server trust root.
+ *
+ * This contained configurations under either
+ * PerProviderSubscription/Policy/PolicyUpdate/TrustRoot or
+ * PerProviderSubscription/SubscriptionUpdate/TrustRoot or
+ * PerProviderSubscription/AAAServerTrustRoot/<X+> subtree.
+ *
+ * @param node PPSNode representing the root of the TrustRoot subtree
+ * @return Pair of Certificate URL and fingerprint
+ * @throws ParsingException
+ */
+ private static Pair<String, byte[]> parseTrustRoot(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for TrustRoot");
+ }
+
+ String certUrl = null;
+ byte[] certFingerprint = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_CERT_URL:
+ certUrl = getPpsNodeValue(child);
+ break;
+ case NODE_CERT_SHA256_FINGERPRINT:
+ certFingerprint = parseHexString(getPpsNodeValue(child));
+ break;
+ default:
+ throw new ParsingException("Unknown node under TrustRoot: "
+ + child.getName());
+ }
+ }
+ return Pair.create(certUrl, certFingerprint);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy/SPExclusionList subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Policy/SPExclusionList subtree
+ * @return Array of excluded SSIDs
+ * @throws ParsingException
+ */
+ private static String[] parseSpExclusionList(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for SPExclusionList");
+ }
+ List<String> ssidList = new ArrayList<>();
+ for (PPSNode child : node.getChildren()) {
+ ssidList.add(parseSpExclusionInstance(child));
+ }
+ return ssidList.toArray(new String[ssidList.size()]);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy/SPExclusionList/<X+> subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Policy/SPExclusionList/<X+> subtree
+ * @return String
+ * @throws ParsingException
+ */
+ private static String parseSpExclusionInstance(PPSNode node) throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for SPExclusion instance");
+ }
+ String ssid = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_SSID:
+ ssid = getPpsNodeValue(child);
+ break;
+ default:
+ throw new ParsingException("Unknown node under SPExclusion instance");
+ }
+ }
+ return ssid;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy/RequiredProtoPortTuple subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Policy/RequiredProtoPortTuple subtree
+ * @return Map of IP Protocol to Port Number tuples
+ * @throws ParsingException
+ */
+ private static Map<Integer, String> parseRequiredProtoPortTuple(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for RequiredProtoPortTuple");
+ }
+ Map<Integer, String> protoPortTupleMap = new HashMap<>();
+ for (PPSNode child : node.getChildren()) {
+ Pair<Integer, String> protoPortTuple = parseProtoPortTuple(child);
+ protoPortTupleMap.put(protoPortTuple.first, protoPortTuple.second);
+ }
+ return protoPortTupleMap;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/Policy/RequiredProtoPortTuple/<X+>
+ * subtree.
+ *
+ * @param node PPSNode representing the root of the
+ * PerProviderSubscription/Policy/RequiredProtoPortTuple/<X+> subtree
+ * @return Pair of IP Protocol to Port Number tuple
+ * @throws ParsingException
+ */
+ private static Pair<Integer, String> parseProtoPortTuple(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for RequiredProtoPortTuple "
+ + "instance");
+ }
+ int proto = Integer.MIN_VALUE;
+ String ports = null;
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_IP_PROTOCOL:
+ proto = parseInteger(getPpsNodeValue(child));
+ break;
+ case NODE_PORT_NUMBER:
+ ports = getPpsNodeValue(child);
+ break;
+ default:
+ throw new ParsingException("Unknown node under RequiredProtoPortTuple instance"
+ + child.getName());
+ }
+ }
+ if (proto == Integer.MIN_VALUE) {
+ throw new ParsingException("Missing IPProtocol field");
+ }
+ if (ports == null) {
+ throw new ParsingException("Missing PortNumber field");
+ }
+ return Pair.create(proto, ports);
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/AAAServerTrustRoot subtree.
+ *
+ * @param node PPSNode representing the root of PerProviderSubscription/AAAServerTrustRoot
+ * subtree
+ * @return Map of certificate URL with the corresponding certificate fingerprint
+ * @throws ParsingException
+ */
+ private static Map<String, byte[]> parseAAAServerTrustRootList(PPSNode node)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for AAAServerTrustRoot");
+ }
+ Map<String, byte[]> certList = new HashMap<>();
+ for (PPSNode child : node.getChildren()) {
+ Pair<String, byte[]> certTuple = parseTrustRoot(child);
+ certList.put(certTuple.first, certTuple.second);
+ }
+ return certList;
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/SubscriptionParameter subtree.
+ *
+ * @param node PPSNode representing the root of PerProviderSubscription/SubscriptionParameter
+ * subtree
+ * @param config Instance of {@link PasspointConfiguration}
+ * @throws ParsingException
+ */
+ private static void parseSubscriptionParameter(PPSNode node, PasspointConfiguration config)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for SubscriptionParameter");
+ }
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_CREATION_DATE:
+ config.setSubscriptionCreationTimeInMs(parseDate(getPpsNodeValue(child)));
+ break;
+ case NODE_EXPIRATION_DATE:
+ config.setSubscriptionExpirationTimeInMs(parseDate(getPpsNodeValue(child)));
+ break;
+ case NODE_TYPE_OF_SUBSCRIPTION:
+ config.setSubscriptionType(getPpsNodeValue(child));
+ break;
+ case NODE_USAGE_LIMITS:
+ parseUsageLimits(child, config);
+ break;
+ default:
+ throw new ParsingException("Unknown node under SubscriptionParameter"
+ + child.getName());
+ }
+ }
+ }
+
+ /**
+ * Parse configurations under PerProviderSubscription/SubscriptionParameter/UsageLimits
+ * subtree.
+ *
+ * @param node PPSNode representing the root of
+ * PerProviderSubscription/SubscriptionParameter/UsageLimits subtree
+ * @param config Instance of {@link PasspointConfiguration}
+ * @throws ParsingException
+ */
+ private static void parseUsageLimits(PPSNode node, PasspointConfiguration config)
+ throws ParsingException {
+ if (node.isLeaf()) {
+ throw new ParsingException("Leaf node not expected for UsageLimits");
+ }
+ for (PPSNode child : node.getChildren()) {
+ switch (child.getName()) {
+ case NODE_DATA_LIMIT:
+ config.setUsageLimitDataLimit(parseLong(getPpsNodeValue(child), 10));
+ break;
+ case NODE_START_DATE:
+ config.setUsageLimitStartTimeInMs(parseDate(getPpsNodeValue(child)));
+ break;
+ case NODE_TIME_LIMIT:
+ config.setUsageLimitTimeLimitInMinutes(parseLong(getPpsNodeValue(child), 10));
+ break;
+ case NODE_USAGE_TIME_PERIOD:
+ config.setUsageLimitUsageTimePeriodInMinutes(
+ parseLong(getPpsNodeValue(child), 10));
+ break;
+ default:
+ throw new ParsingException("Unknown node under UsageLimits"
+ + child.getName());
+ }
+ }
+ }
+
+ /**
+ * Convert a hex string to a byte array.
+ *
+ * @param str String containing hex values
+ * @return byte[]
+ * @throws ParsingException
+ */
+ private static byte[] parseHexString(String str) throws ParsingException {
+ if ((str.length() & 1) == 1) {
+ throw new ParsingException("Odd length hex string: " + str.length());
+ }
+
+ byte[] result = new byte[str.length() / 2];
+ for (int i = 0; i < result.length; i++) {
+ int index = i * 2;
+ try {
+ result[i] = (byte) Integer.parseInt(str.substring(index, index + 2), 16);
+ } catch (NumberFormatException e) {
+ throw new ParsingException("Invalid hex string: " + str);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Convert a date string to the number of milliseconds since January 1, 1970, 00:00:00 GMT.
+ *
+ * @param dateStr String in the format of yyyy-MM-dd'T'HH:mm:ss'Z'
+ * @return number of milliseconds
+ * @throws ParsingException
+ */
+ private static long parseDate(String dateStr) throws ParsingException {
+ try {
+ DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+ return format.parse(dateStr).getTime();
+ } catch (ParseException pe) {
+ throw new ParsingException("Badly formatted time: " + dateStr);
+ }
+ }
+
+ /**
+ * Parse an integer string.
+ *
+ * @param value String of integer value
+ * @return int
+ * @throws ParsingException
+ */
+ private static int parseInteger(String value) throws ParsingException {
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new ParsingException("Invalid integer value: " + value);
+ }
+ }
+
+ /**
+ * Parse a string representing a long integer.
+ *
+ * @param value String of long integer value
+ * @return long
+ * @throws ParsingException
+ */
+ private static long parseLong(String value, int radix) throws ParsingException {
+ try {
+ return Long.parseLong(value, radix);
+ } catch (NumberFormatException e) {
+ throw new ParsingException("Invalid long integer value: " + value);
+ }
+ }
+
+ /**
+ * Convert a List<Long> to a primitive long array long[].
+ *
+ * @param list List to be converted
+ * @return long[]
+ */
+ private static long[] convertFromLongList(List<Long> list) {
+ Long[] objectArray = list.toArray(new Long[list.size()]);
+ long[] primitiveArray = new long[objectArray.length];
+ for (int i = 0; i < objectArray.length; i++) {
+ primitiveArray[i] = objectArray[i].longValue();
+ }
+ return primitiveArray;
+ }
+}
diff --git a/wifi/java/android/net/wifi/hotspot2/omadm/XMLNode.java b/wifi/java/android/net/wifi/hotspot2/omadm/XMLNode.java
index e87698cb7ed1..959d5057e257 100644
--- a/wifi/java/android/net/wifi/hotspot2/omadm/XMLNode.java
+++ b/wifi/java/android/net/wifi/hotspot2/omadm/XMLNode.java
@@ -20,6 +20,7 @@ import android.text.TextUtils;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* A class represent a node in an XML tree. Each node is an XML element.
@@ -100,4 +101,9 @@ public class XMLNode {
TextUtils.equals(mText, that.mText) &&
mChildren.equals(that.mChildren);
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTag, mText, mChildren);
+ }
}
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
index 790dfaf643ca..620759df8f1d 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
@@ -23,6 +23,7 @@ import android.os.Parcel;
import android.text.TextUtils;
import android.util.Log;
+import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
@@ -30,6 +31,7 @@ import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.Objects;
import java.util.Set;
/**
@@ -40,10 +42,6 @@ import java.util.Set;
*
* In addition to the fields in the Credential subtree, this will also maintain necessary
* information for the private key and certificates associated with this credential.
- *
- * Currently we only support the nodes that are used by Hotspot 2.0 Release 1.
- *
- * @hide
*/
public final class Credential implements Parcelable {
private static final String TAG = "Credential";
@@ -52,14 +50,59 @@ public final class Credential implements Parcelable {
* Max string length for realm. Refer to Credential/Realm node in Hotspot 2.0 Release 2
* Technical Specification Section 9.1 for more info.
*/
- private static final int MAX_REALM_LENGTH = 253;
+ private static final int MAX_REALM_BYTES = 253;
+
+ /**
+ * The time this credential is created. It is in the format of number
+ * of milliseconds since January 1, 1970, 00:00:00 GMT.
+ * Using Long.MIN_VALUE to indicate unset value.
+ */
+ private long mCreationTimeInMs = Long.MIN_VALUE;
+ public void setCreationTimeInMs(long creationTimeInMs) {
+ mCreationTimeInMs = creationTimeInMs;
+ }
+ public long getCreationTimeInMs() {
+ return mCreationTimeInMs;
+ }
+
+ /**
+ * The time this credential will expire. It is in the format of number
+ * of milliseconds since January 1, 1970, 00:00:00 GMT.
+ * Using Long.MIN_VALUE to indicate unset value.
+ */
+ private long mExpirationTimeInMs = Long.MIN_VALUE;
+ public void setExpirationTimeInMs(long expirationTimeInMs) {
+ mExpirationTimeInMs = expirationTimeInMs;
+ }
+ public long getExpirationTimeInMs() {
+ return mExpirationTimeInMs;
+ }
/**
* The realm associated with this credential. It will be used to determine
* if this credential can be used to authenticate with a given hotspot by
* comparing the realm specified in that hotspot's ANQP element.
*/
- public String realm = null;
+ private String mRealm = null;
+ public void setRealm(String realm) {
+ mRealm = realm;
+ }
+ public String getRealm() {
+ return mRealm;
+ }
+
+ /**
+ * When set to true, the device should check AAA (Authentication, Authorization,
+ * and Accounting) server's certificate during EAP (Extensible Authentication
+ * Protocol) authentication.
+ */
+ private boolean mCheckAaaServerCertStatus = false;
+ public void setCheckAaaServerCertStatus(boolean checkAaaServerCertStatus) {
+ mCheckAaaServerCertStatus = checkAaaServerCertStatus;
+ }
+ public boolean getCheckAaaServerCertStatus() {
+ return mCheckAaaServerCertStatus;
+ }
/**
* Username-password based credential.
@@ -70,13 +113,13 @@ public final class Credential implements Parcelable {
* Maximum string length for username. Refer to Credential/UsernamePassword/Username
* node in Hotspot 2.0 Release 2 Technical Specification Section 9.1 for more info.
*/
- private static final int MAX_USERNAME_LENGTH = 63;
+ private static final int MAX_USERNAME_BYTES = 63;
/**
* Maximum string length for password. Refer to Credential/UsernamePassword/Password
* in Hotspot 2.0 Release 2 Technical Specification Section 9.1 for more info.
*/
- private static final int MAX_PASSWORD_LENGTH = 255;
+ private static final int MAX_PASSWORD_BYTES = 255;
/**
* Supported Non-EAP inner methods. Refer to
@@ -89,12 +132,57 @@ public final class Credential implements Parcelable {
/**
* Username of the credential.
*/
- public String username = null;
+ private String mUsername = null;
+ public void setUsername(String username) {
+ mUsername = username;
+ }
+ public String getUsername() {
+ return mUsername;
+ }
/**
* Base64-encoded password.
*/
- public String password = null;
+ private String mPassword = null;
+ public void setPassword(String password) {
+ mPassword = password;
+ }
+ public String getPassword() {
+ return mPassword;
+ }
+
+ /**
+ * Flag indicating if the password is machine managed.
+ */
+ private boolean mMachineManaged = false;
+ public void setMachineManaged(boolean machineManaged) {
+ mMachineManaged = machineManaged;
+ }
+ public boolean getMachineManaged() {
+ return mMachineManaged;
+ }
+
+ /**
+ * The name of the application used to generate the password.
+ */
+ private String mSoftTokenApp = null;
+ public void setSoftTokenApp(String softTokenApp) {
+ mSoftTokenApp = softTokenApp;
+ }
+ public String getSoftTokenApp() {
+ return mSoftTokenApp;
+ }
+
+ /**
+ * Flag indicating if this credential is usable on other mobile devices as well.
+ */
+ private boolean mAbleToShare = false;
+ public void setAbleToShare(boolean ableToShare) {
+ mAbleToShare = ableToShare;
+ }
+ public boolean getAbleToShare() {
+ return mAbleToShare;
+ }
/**
* EAP (Extensible Authentication Protocol) method type.
@@ -102,12 +190,24 @@ public final class Credential implements Parcelable {
* for valid values.
* Using Integer.MIN_VALUE to indicate unset value.
*/
- public int eapType = Integer.MIN_VALUE;
+ private int mEapType = Integer.MIN_VALUE;
+ public void setEapType(int eapType) {
+ mEapType = eapType;
+ }
+ public int getEapType() {
+ return mEapType;
+ }
/**
* Non-EAP inner authentication method.
*/
- public String nonEapInnerMethod = null;
+ private String mNonEapInnerMethod = null;
+ public void setNonEapInnerMethod(String nonEapInnerMethod) {
+ mNonEapInnerMethod = nonEapInnerMethod;
+ }
+ public String getNonEapInnerMethod() {
+ return mNonEapInnerMethod;
+ }
/**
* Constructor for creating UserCredential with default values.
@@ -121,10 +221,13 @@ public final class Credential implements Parcelable {
*/
public UserCredential(UserCredential source) {
if (source != null) {
- username = source.username;
- password = source.password;
- eapType = source.eapType;
- nonEapInnerMethod = source.nonEapInnerMethod;
+ mUsername = source.mUsername;
+ mPassword = source.mPassword;
+ mMachineManaged = source.mMachineManaged;
+ mSoftTokenApp = source.mSoftTokenApp;
+ mAbleToShare = source.mAbleToShare;
+ mEapType = source.mEapType;
+ mNonEapInnerMethod = source.mNonEapInnerMethod;
}
}
@@ -135,10 +238,13 @@ public final class Credential implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(username);
- dest.writeString(password);
- dest.writeInt(eapType);
- dest.writeString(nonEapInnerMethod);
+ dest.writeString(mUsername);
+ dest.writeString(mPassword);
+ dest.writeInt(mMachineManaged ? 1 : 0);
+ dest.writeString(mSoftTokenApp);
+ dest.writeInt(mAbleToShare ? 1 : 0);
+ dest.writeInt(mEapType);
+ dest.writeString(mNonEapInnerMethod);
}
@Override
@@ -151,10 +257,19 @@ public final class Credential implements Parcelable {
}
UserCredential that = (UserCredential) thatObject;
- return TextUtils.equals(username, that.username) &&
- TextUtils.equals(password, that.password) &&
- eapType == that.eapType &&
- TextUtils.equals(nonEapInnerMethod, that.nonEapInnerMethod);
+ return TextUtils.equals(mUsername, that.mUsername)
+ && TextUtils.equals(mPassword, that.mPassword)
+ && mMachineManaged == that.mMachineManaged
+ && TextUtils.equals(mSoftTokenApp, that.mSoftTokenApp)
+ && mAbleToShare == that.mAbleToShare
+ && mEapType == that.mEapType
+ && TextUtils.equals(mNonEapInnerMethod, that.mNonEapInnerMethod);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUsername, mPassword, mMachineManaged, mSoftTokenApp,
+ mAbleToShare, mEapType, mNonEapInnerMethod);
}
/**
@@ -163,33 +278,35 @@ public final class Credential implements Parcelable {
* @return true on success or false on failure
*/
public boolean validate() {
- if (TextUtils.isEmpty(username)) {
+ if (TextUtils.isEmpty(mUsername)) {
Log.d(TAG, "Missing username");
return false;
}
- if (username.length() > MAX_USERNAME_LENGTH) {
- Log.d(TAG, "username exceeding maximum length: " + username.length());
+ if (mUsername.getBytes(StandardCharsets.UTF_8).length > MAX_USERNAME_BYTES) {
+ Log.d(TAG, "username exceeding maximum length: "
+ + mUsername.getBytes(StandardCharsets.UTF_8).length);
return false;
}
- if (TextUtils.isEmpty(password)) {
+ if (TextUtils.isEmpty(mPassword)) {
Log.d(TAG, "Missing password");
return false;
}
- if (password.length() > MAX_PASSWORD_LENGTH) {
- Log.d(TAG, "password exceeding maximum length: " + password.length());
+ if (mPassword.getBytes(StandardCharsets.UTF_8).length > MAX_PASSWORD_BYTES) {
+ Log.d(TAG, "password exceeding maximum length: "
+ + mPassword.getBytes(StandardCharsets.UTF_8).length);
return false;
}
// Only supports EAP-TTLS for user credential.
- if (eapType != EAPConstants.EAP_TTLS) {
- Log.d(TAG, "Invalid EAP Type for user credential: " + eapType);
+ if (mEapType != EAPConstants.EAP_TTLS) {
+ Log.d(TAG, "Invalid EAP Type for user credential: " + mEapType);
return false;
}
// Verify Non-EAP inner method for EAP-TTLS.
- if (!SUPPORTED_AUTH.contains(nonEapInnerMethod)) {
- Log.d(TAG, "Invalid non-EAP inner method for EAP-TTLS: " + nonEapInnerMethod);
+ if (!SUPPORTED_AUTH.contains(mNonEapInnerMethod)) {
+ Log.d(TAG, "Invalid non-EAP inner method for EAP-TTLS: " + mNonEapInnerMethod);
return false;
}
return true;
@@ -200,10 +317,13 @@ public final class Credential implements Parcelable {
@Override
public UserCredential createFromParcel(Parcel in) {
UserCredential userCredential = new UserCredential();
- userCredential.username = in.readString();
- userCredential.password = in.readString();
- userCredential.eapType = in.readInt();
- userCredential.nonEapInnerMethod = in.readString();
+ userCredential.setUsername(in.readString());
+ userCredential.setPassword(in.readString());
+ userCredential.setMachineManaged(in.readInt() != 0);
+ userCredential.setSoftTokenApp(in.readString());
+ userCredential.setAbleToShare(in.readInt() != 0);
+ userCredential.setEapType(in.readInt());
+ userCredential.setNonEapInnerMethod(in.readString());
return userCredential;
}
@@ -213,7 +333,13 @@ public final class Credential implements Parcelable {
}
};
}
- public UserCredential userCredential = null;
+ private UserCredential mUserCredential = null;
+ public void setUserCredential(UserCredential userCredential) {
+ mUserCredential = userCredential;
+ }
+ public UserCredential getUserCredential() {
+ return mUserCredential;
+ }
/**
* Certificate based credential. This is used for EAP-TLS.
@@ -233,12 +359,24 @@ public final class Credential implements Parcelable {
/**
* Certificate type.
*/
- public String certType = null;
+ private String mCertType = null;
+ public void setCertType(String certType) {
+ mCertType = certType;
+ }
+ public String getCertType() {
+ return mCertType;
+ }
/**
* The SHA-256 fingerprint of the certificate.
*/
- public byte[] certSha256FingerPrint = null;
+ private byte[] mCertSha256Fingerprint = null;
+ public void setCertSha256Fingerprint(byte[] certSha256Fingerprint) {
+ mCertSha256Fingerprint = certSha256Fingerprint;
+ }
+ public byte[] getCertSha256Fingerprint() {
+ return mCertSha256Fingerprint;
+ }
/**
* Constructor for creating CertificateCredential with default values.
@@ -252,10 +390,10 @@ public final class Credential implements Parcelable {
*/
public CertificateCredential(CertificateCredential source) {
if (source != null) {
- certType = source.certType;
- if (source.certSha256FingerPrint != null) {
- certSha256FingerPrint = Arrays.copyOf(source.certSha256FingerPrint,
- source.certSha256FingerPrint.length);
+ mCertType = source.mCertType;
+ if (source.mCertSha256Fingerprint != null) {
+ mCertSha256Fingerprint = Arrays.copyOf(source.mCertSha256Fingerprint,
+ source.mCertSha256Fingerprint.length);
}
}
}
@@ -267,8 +405,8 @@ public final class Credential implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(certType);
- dest.writeByteArray(certSha256FingerPrint);
+ dest.writeString(mCertType);
+ dest.writeByteArray(mCertSha256Fingerprint);
}
@Override
@@ -281,8 +419,13 @@ public final class Credential implements Parcelable {
}
CertificateCredential that = (CertificateCredential) thatObject;
- return TextUtils.equals(certType, that.certType) &&
- Arrays.equals(certSha256FingerPrint, that.certSha256FingerPrint);
+ return TextUtils.equals(mCertType, that.mCertType)
+ && Arrays.equals(mCertSha256Fingerprint, that.mCertSha256Fingerprint);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mCertType, mCertSha256Fingerprint);
}
/**
@@ -291,12 +434,12 @@ public final class Credential implements Parcelable {
* @return true on success or false on failure
*/
public boolean validate() {
- if (!TextUtils.equals(CERT_TYPE_X509V3, certType)) {
- Log.d(TAG, "Unsupported certificate type: " + certType);
+ if (!TextUtils.equals(CERT_TYPE_X509V3, mCertType)) {
+ Log.d(TAG, "Unsupported certificate type: " + mCertType);
return false;
}
- if (certSha256FingerPrint == null ||
- certSha256FingerPrint.length != CERT_SHA256_FINGER_PRINT_LENGTH) {
+ if (mCertSha256Fingerprint == null
+ || mCertSha256Fingerprint.length != CERT_SHA256_FINGER_PRINT_LENGTH) {
Log.d(TAG, "Invalid SHA-256 fingerprint");
return false;
}
@@ -308,8 +451,8 @@ public final class Credential implements Parcelable {
@Override
public CertificateCredential createFromParcel(Parcel in) {
CertificateCredential certCredential = new CertificateCredential();
- certCredential.certType = in.readString();
- certCredential.certSha256FingerPrint = in.createByteArray();
+ certCredential.setCertType(in.readString());
+ certCredential.setCertSha256Fingerprint(in.createByteArray());
return certCredential;
}
@@ -319,7 +462,13 @@ public final class Credential implements Parcelable {
}
};
}
- public CertificateCredential certCredential = null;
+ private CertificateCredential mCertCredential = null;
+ public void setCertCredential(CertificateCredential certCredential) {
+ mCertCredential = certCredential;
+ }
+ public CertificateCredential getCertCredential() {
+ return mCertCredential;
+ }
/**
* SIM (Subscriber Identify Module) based credential.
@@ -329,14 +478,20 @@ public final class Credential implements Parcelable {
/**
* Maximum string length for IMSI.
*/
- public static final int MAX_IMSI_LENGTH = 15;
+ private static final int MAX_IMSI_LENGTH = 15;
/**
* International Mobile Subscriber Identity, is used to identify the user
* of a cellular network and is a unique identification associated with all
* cellular networks
*/
- public String imsi = null;
+ private String mImsi = null;
+ public void setImsi(String imsi) {
+ mImsi = imsi;
+ }
+ public String getImsi() {
+ return mImsi;
+ }
/**
* EAP (Extensible Authentication Protocol) method type for using SIM credential.
@@ -344,7 +499,13 @@ public final class Credential implements Parcelable {
* for valid values.
* Using Integer.MIN_VALUE to indicate unset value.
*/
- public int eapType = Integer.MIN_VALUE;
+ private int mEapType = Integer.MIN_VALUE;
+ public void setEapType(int eapType) {
+ mEapType = eapType;
+ }
+ public int getEapType() {
+ return mEapType;
+ }
/**
* Constructor for creating SimCredential with default values.
@@ -358,8 +519,8 @@ public final class Credential implements Parcelable {
*/
public SimCredential(SimCredential source) {
if (source != null) {
- imsi = source.imsi;
- eapType = source.eapType;
+ mImsi = source.mImsi;
+ mEapType = source.mEapType;
}
}
@@ -378,14 +539,19 @@ public final class Credential implements Parcelable {
}
SimCredential that = (SimCredential) thatObject;
- return TextUtils.equals(imsi, that.imsi) &&
- eapType == that.eapType;
+ return TextUtils.equals(mImsi, that.mImsi)
+ && mEapType == that.mEapType;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mImsi, mEapType);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(imsi);
- dest.writeInt(eapType);
+ dest.writeString(mImsi);
+ dest.writeInt(mEapType);
}
/**
@@ -400,9 +566,9 @@ public final class Credential implements Parcelable {
if (!verifyImsi()) {
return false;
}
- if (eapType != EAPConstants.EAP_SIM && eapType != EAPConstants.EAP_AKA &&
- eapType != EAPConstants.EAP_AKA_PRIME) {
- Log.d(TAG, "Invalid EAP Type for SIM credential: " + eapType);
+ if (mEapType != EAPConstants.EAP_SIM && mEapType != EAPConstants.EAP_AKA
+ && mEapType != EAPConstants.EAP_AKA_PRIME) {
+ Log.d(TAG, "Invalid EAP Type for SIM credential: " + mEapType);
return false;
}
return true;
@@ -413,8 +579,8 @@ public final class Credential implements Parcelable {
@Override
public SimCredential createFromParcel(Parcel in) {
SimCredential simCredential = new SimCredential();
- simCredential.imsi = in.readString();
- simCredential.eapType = in.readInt();
+ simCredential.setImsi(in.readString());
+ simCredential.setEapType(in.readInt());
return simCredential;
}
@@ -432,51 +598,75 @@ public final class Credential implements Parcelable {
* @return true if IMSI is valid, false otherwise.
*/
private boolean verifyImsi() {
- if (TextUtils.isEmpty(imsi)) {
+ if (TextUtils.isEmpty(mImsi)) {
Log.d(TAG, "Missing IMSI");
return false;
}
- if (imsi.length() > MAX_IMSI_LENGTH) {
- Log.d(TAG, "IMSI exceeding maximum length: " + imsi.length());
+ if (mImsi.length() > MAX_IMSI_LENGTH) {
+ Log.d(TAG, "IMSI exceeding maximum length: " + mImsi.length());
return false;
}
// Locate the first non-digit character.
int nonDigit;
char stopChar = '\0';
- for (nonDigit = 0; nonDigit < imsi.length(); nonDigit++) {
- stopChar = imsi.charAt(nonDigit);
+ for (nonDigit = 0; nonDigit < mImsi.length(); nonDigit++) {
+ stopChar = mImsi.charAt(nonDigit);
if (stopChar < '0' || stopChar > '9') {
break;
}
}
- if (nonDigit == imsi.length()) {
+ if (nonDigit == mImsi.length()) {
return true;
}
- else if (nonDigit == imsi.length()-1 && stopChar == '*') {
+ else if (nonDigit == mImsi.length()-1 && stopChar == '*') {
// Prefix matching.
return true;
}
return false;
}
}
- public SimCredential simCredential = null;
+ private SimCredential mSimCredential = null;
+ public void setSimCredential(SimCredential simCredential) {
+ mSimCredential = simCredential;
+ }
+ public SimCredential getSimCredential() {
+ return mSimCredential;
+ }
/**
* CA (Certificate Authority) X509 certificate.
*/
- public X509Certificate caCertificate = null;
+ private X509Certificate mCaCertificate = null;
+ public void setCaCertificate(X509Certificate caCertificate) {
+ mCaCertificate = caCertificate;
+ }
+ public X509Certificate getCaCertificate() {
+ return mCaCertificate;
+ }
/**
* Client side X509 certificate chain.
*/
- public X509Certificate[] clientCertificateChain = null;
+ private X509Certificate[] mClientCertificateChain = null;
+ public void setClientCertificateChain(X509Certificate[] certificateChain) {
+ mClientCertificateChain = certificateChain;
+ }
+ public X509Certificate[] getClientCertificateChain() {
+ return mClientCertificateChain;
+ }
/**
* Client side private key.
*/
- public PrivateKey clientPrivateKey = null;
+ private PrivateKey mClientPrivateKey = null;
+ public void setClientPrivateKey(PrivateKey clientPrivateKey) {
+ mClientPrivateKey = clientPrivateKey;
+ }
+ public PrivateKey getClientPrivateKey() {
+ return mClientPrivateKey;
+ }
/**
* Constructor for creating Credential with default values.
@@ -490,22 +680,25 @@ public final class Credential implements Parcelable {
*/
public Credential(Credential source) {
if (source != null) {
- realm = source.realm;
- if (source.userCredential != null) {
- userCredential = new UserCredential(source.userCredential);
+ mCreationTimeInMs = source.mCreationTimeInMs;
+ mExpirationTimeInMs = source.mExpirationTimeInMs;
+ mRealm = source.mRealm;
+ mCheckAaaServerCertStatus = source.mCheckAaaServerCertStatus;
+ if (source.mUserCredential != null) {
+ mUserCredential = new UserCredential(source.mUserCredential);
}
- if (source.certCredential != null) {
- certCredential = new CertificateCredential(source.certCredential);
+ if (source.mCertCredential != null) {
+ mCertCredential = new CertificateCredential(source.mCertCredential);
}
- if (source.simCredential != null) {
- simCredential = new SimCredential(source.simCredential);
+ if (source.mSimCredential != null) {
+ mSimCredential = new SimCredential(source.mSimCredential);
}
- if (source.clientCertificateChain != null) {
- clientCertificateChain = Arrays.copyOf(source.clientCertificateChain,
- source.clientCertificateChain.length);
+ if (source.mClientCertificateChain != null) {
+ mClientCertificateChain = Arrays.copyOf(source.mClientCertificateChain,
+ source.mClientCertificateChain.length);
}
- caCertificate = source.caCertificate;
- clientPrivateKey = source.clientPrivateKey;
+ mCaCertificate = source.mCaCertificate;
+ mClientPrivateKey = source.mClientPrivateKey;
}
}
@@ -516,13 +709,16 @@ public final class Credential implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(realm);
- dest.writeParcelable(userCredential, flags);
- dest.writeParcelable(certCredential, flags);
- dest.writeParcelable(simCredential, flags);
- ParcelUtil.writeCertificate(dest, caCertificate);
- ParcelUtil.writeCertificates(dest, clientCertificateChain);
- ParcelUtil.writePrivateKey(dest, clientPrivateKey);
+ dest.writeLong(mCreationTimeInMs);
+ dest.writeLong(mExpirationTimeInMs);
+ dest.writeString(mRealm);
+ dest.writeInt(mCheckAaaServerCertStatus ? 1 : 0);
+ dest.writeParcelable(mUserCredential, flags);
+ dest.writeParcelable(mCertCredential, flags);
+ dest.writeParcelable(mSimCredential, flags);
+ ParcelUtil.writeCertificate(dest, mCaCertificate);
+ ParcelUtil.writeCertificates(dest, mClientCertificateChain);
+ ParcelUtil.writePrivateKey(dest, mClientPrivateKey);
}
@Override
@@ -535,16 +731,26 @@ public final class Credential implements Parcelable {
}
Credential that = (Credential) thatObject;
- return TextUtils.equals(realm, that.realm) &&
- (userCredential == null ? that.userCredential == null :
- userCredential.equals(that.userCredential)) &&
- (certCredential == null ? that.certCredential == null :
- certCredential.equals(that.certCredential)) &&
- (simCredential == null ? that.simCredential == null :
- simCredential.equals(that.simCredential)) &&
- isX509CertificateEquals(caCertificate, that.caCertificate) &&
- isX509CertificatesEquals(clientCertificateChain, that.clientCertificateChain) &&
- isPrivateKeyEquals(clientPrivateKey, that.clientPrivateKey);
+ return TextUtils.equals(mRealm, that.mRealm)
+ && mCreationTimeInMs == that.mCreationTimeInMs
+ && mExpirationTimeInMs == that.mExpirationTimeInMs
+ && mCheckAaaServerCertStatus == that.mCheckAaaServerCertStatus
+ && (mUserCredential == null ? that.mUserCredential == null
+ : mUserCredential.equals(that.mUserCredential))
+ && (mCertCredential == null ? that.mCertCredential == null
+ : mCertCredential.equals(that.mCertCredential))
+ && (mSimCredential == null ? that.mSimCredential == null
+ : mSimCredential.equals(that.mSimCredential))
+ && isX509CertificateEquals(mCaCertificate, that.mCaCertificate)
+ && isX509CertificatesEquals(mClientCertificateChain, that.mClientCertificateChain)
+ && isPrivateKeyEquals(mClientPrivateKey, that.mClientPrivateKey);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mRealm, mCreationTimeInMs, mExpirationTimeInMs,
+ mCheckAaaServerCertStatus, mUserCredential, mCertCredential, mSimCredential,
+ mCaCertificate, mClientCertificateChain, mClientPrivateKey);
}
/**
@@ -553,25 +759,26 @@ public final class Credential implements Parcelable {
* @return true on success or false on failure
*/
public boolean validate() {
- if (TextUtils.isEmpty(realm)) {
+ if (TextUtils.isEmpty(mRealm)) {
Log.d(TAG, "Missing realm");
return false;
}
- if (realm.length() > MAX_REALM_LENGTH) {
- Log.d(TAG, "realm exceeding maximum length: " + realm.length());
+ if (mRealm.getBytes(StandardCharsets.UTF_8).length > MAX_REALM_BYTES) {
+ Log.d(TAG, "realm exceeding maximum length: "
+ + mRealm.getBytes(StandardCharsets.UTF_8).length);
return false;
}
// Verify the credential.
- if (userCredential != null) {
+ if (mUserCredential != null) {
if (!verifyUserCredential()) {
return false;
}
- } else if (certCredential != null) {
+ } else if (mCertCredential != null) {
if (!verifyCertCredential()) {
return false;
}
- } else if (simCredential != null) {
+ } else if (mSimCredential != null) {
if (!verifySimCredential()) {
return false;
}
@@ -588,13 +795,16 @@ public final class Credential implements Parcelable {
@Override
public Credential createFromParcel(Parcel in) {
Credential credential = new Credential();
- credential.realm = in.readString();
- credential.userCredential = in.readParcelable(null);
- credential.certCredential = in.readParcelable(null);
- credential.simCredential = in.readParcelable(null);
- credential.caCertificate = ParcelUtil.readCertificate(in);
- credential.clientCertificateChain = ParcelUtil.readCertificates(in);
- credential.clientPrivateKey = ParcelUtil.readPrivateKey(in);
+ credential.setCreationTimeInMs(in.readLong());
+ credential.setExpirationTimeInMs(in.readLong());
+ credential.setRealm(in.readString());
+ credential.setCheckAaaServerCertStatus(in.readInt() != 0);
+ credential.setUserCredential(in.readParcelable(null));
+ credential.setCertCredential(in.readParcelable(null));
+ credential.setSimCredential(in.readParcelable(null));
+ credential.setCaCertificate(ParcelUtil.readCertificate(in));
+ credential.setClientCertificateChain(ParcelUtil.readCertificates(in));
+ credential.setClientPrivateKey(ParcelUtil.readPrivateKey(in));
return credential;
}
@@ -610,18 +820,18 @@ public final class Credential implements Parcelable {
* @return true if user credential is valid, false otherwise.
*/
private boolean verifyUserCredential() {
- if (userCredential == null) {
+ if (mUserCredential == null) {
Log.d(TAG, "Missing user credential");
return false;
}
- if (certCredential != null || simCredential != null) {
+ if (mCertCredential != null || mSimCredential != null) {
Log.d(TAG, "Contained more than one type of credential");
return false;
}
- if (!userCredential.validate()) {
+ if (!mUserCredential.validate()) {
return false;
}
- if (caCertificate == null) {
+ if (mCaCertificate == null) {
Log.d(TAG, "Missing CA Certificate for user credential");
return false;
}
@@ -635,32 +845,32 @@ public final class Credential implements Parcelable {
* @return true if certificate credential is valid, false otherwise.
*/
private boolean verifyCertCredential() {
- if (certCredential == null) {
+ if (mCertCredential == null) {
Log.d(TAG, "Missing certificate credential");
return false;
}
- if (userCredential != null || simCredential != null) {
+ if (mUserCredential != null || mSimCredential != null) {
Log.d(TAG, "Contained more than one type of credential");
return false;
}
- if (!certCredential.validate()) {
+ if (!mCertCredential.validate()) {
return false;
}
// Verify required key and certificates for certificate credential.
- if (caCertificate == null) {
+ if (mCaCertificate == null) {
Log.d(TAG, "Missing CA Certificate for certificate credential");
return false;
}
- if (clientPrivateKey == null) {
+ if (mClientPrivateKey == null) {
Log.d(TAG, "Missing client private key for certificate credential");
return false;
}
try {
// Verify SHA-256 fingerprint for client certificate.
- if (!verifySha256Fingerprint(clientCertificateChain,
- certCredential.certSha256FingerPrint)) {
+ if (!verifySha256Fingerprint(mClientCertificateChain,
+ mCertCredential.getCertSha256Fingerprint())) {
Log.d(TAG, "SHA-256 fingerprint mismatch");
return false;
}
@@ -678,15 +888,15 @@ public final class Credential implements Parcelable {
* @return true if SIM credential is valid, false otherwise.
*/
private boolean verifySimCredential() {
- if (simCredential == null) {
+ if (mSimCredential == null) {
Log.d(TAG, "Missing SIM credential");
return false;
}
- if (userCredential != null || certCredential != null) {
+ if (mUserCredential != null || mCertCredential != null) {
Log.d(TAG, "Contained more than one type of credential");
return false;
}
- return simCredential.validate();
+ return mSimCredential.validate();
}
private static boolean isPrivateKeyEquals(PrivateKey key1, PrivateKey key2) {
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
deleted file mode 100644
index d4a5792d93fc..000000000000
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.hotspot2.pps;
-
-import android.os.Parcelable;
-import android.os.Parcel;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.util.Arrays;
-
-/**
- * Class representing HomeSP subtree in PerProviderSubscription (PPS)
- * Management Object (MO) tree.
- *
- * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
- * Release 2 Technical Specification.
- *
- * Currently we only support the nodes that are used by Hotspot 2.0 Release 1.
- *
- * @hide
- */
-public final class HomeSP implements Parcelable {
- private static final String TAG = "HomeSP";
-
- /**
- * FQDN (Fully Qualified Domain Name) of this home service provider.
- */
- public String fqdn = null;
-
- /**
- * Friendly name of this home service provider.
- */
- public String friendlyName = null;
-
- /**
- * List of Organization Identifiers (OIs) identifying a roaming consortium of
- * which this provider is a member.
- */
- public long[] roamingConsortiumOIs = null;
-
- /**
- * Constructor for creating HomeSP with default values.
- */
- public HomeSP() {}
-
- /**
- * Copy constructor.
- *
- * @param source The source to copy from
- */
- public HomeSP(HomeSP source) {
- if (source != null) {
- fqdn = source.fqdn;
- friendlyName = source.friendlyName;
- if (source.roamingConsortiumOIs != null) {
- roamingConsortiumOIs = Arrays.copyOf(source.roamingConsortiumOIs,
- source.roamingConsortiumOIs.length);
- }
- }
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(fqdn);
- dest.writeString(friendlyName);
- dest.writeLongArray(roamingConsortiumOIs);
- }
-
- @Override
- public boolean equals(Object thatObject) {
- if (this == thatObject) {
- return true;
- }
- if (!(thatObject instanceof HomeSP)) {
- return false;
- }
- HomeSP that = (HomeSP) thatObject;
-
- return TextUtils.equals(fqdn, that.fqdn) &&
- TextUtils.equals(friendlyName, that.friendlyName) &&
- Arrays.equals(roamingConsortiumOIs, that.roamingConsortiumOIs);
- }
-
- /**
- * Validate HomeSP data.
- *
- * @return true on success or false on failure
- */
- public boolean validate() {
- if (TextUtils.isEmpty(fqdn)) {
- Log.d(TAG, "Missing FQDN");
- return false;
- }
- if (TextUtils.isEmpty(friendlyName)) {
- Log.d(TAG, "Missing friendly name");
- return false;
- }
- return true;
- }
-
- public static final Creator<HomeSP> CREATOR =
- new Creator<HomeSP>() {
- @Override
- public HomeSP createFromParcel(Parcel in) {
- HomeSP homeSp = new HomeSP();
- homeSp.fqdn = in.readString();
- homeSp.friendlyName = in.readString();
- homeSp.roamingConsortiumOIs = in.createLongArray();
- return homeSp;
- }
-
- @Override
- public HomeSP[] newArray(int size) {
- return new HomeSP[size];
- }
- };
-}
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.aidl
index 62d5603b5982..6d343bde7081 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.aidl
@@ -16,4 +16,4 @@
package android.net.wifi.hotspot2.pps;
-parcelable HomeSP;
+parcelable HomeSp;
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
new file mode 100644
index 000000000000..8ec40c00304f
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
@@ -0,0 +1,338 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.hotspot2.pps;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Class representing HomeSP subtree in PerProviderSubscription (PPS)
+ * Management Object (MO) tree.
+ *
+ * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
+ * Release 2 Technical Specification.
+ */
+public final class HomeSp implements Parcelable {
+ private static final String TAG = "HomeSp";
+
+ /**
+ * Maximum number of bytes allowed for a SSID.
+ */
+ private static final int MAX_SSID_BYTES = 32;
+
+ /**
+ * Integer value used for indicating null value in the Parcel.
+ */
+ private static final int NULL_VALUE = -1;
+
+ /**
+ * FQDN (Fully Qualified Domain Name) of this home service provider.
+ */
+ private String mFqdn = null;
+ public void setFqdn(String fqdn) {
+ mFqdn = fqdn;
+ }
+ public String getFqdn() {
+ return mFqdn;
+ }
+
+ /**
+ * Friendly name of this home service provider.
+ */
+ private String mFriendlyName = null;
+ public void setFriendlyName(String friendlyName) {
+ mFriendlyName = friendlyName;
+ }
+ public String getFriendlyName() {
+ return mFriendlyName;
+ }
+
+ /**
+ * Icon URL of this home service provider.
+ */
+ private String mIconUrl = null;
+ public void setIconUrl(String iconUrl) {
+ mIconUrl = iconUrl;
+ }
+ public String getIconUrl() {
+ return mIconUrl;
+ }
+
+ /**
+ * <SSID, HESSID> duple of the networks that are consider home networks.
+ *
+ * According to the Section 9.1.2 of the Hotspot 2.0 Release 2 Technical Specification,
+ * all nodes in the PSS MO are encoded using UTF-8 unless stated otherwise. Thus, the SSID
+ * string is assumed to be encoded using UTF-8.
+ */
+ private Map<String, Long> mHomeNetworkIds = null;
+ public void setHomeNetworkIds(Map<String, Long> homeNetworkIds) {
+ mHomeNetworkIds = homeNetworkIds;
+ }
+ public Map<String, Long> getHomeNetworkIds() {
+ return mHomeNetworkIds;
+ }
+
+ /**
+ * Used for determining if this provider is a member of a given Hotspot provider.
+ * Every Organization Identifiers (OIs) in this list are required to match an OI in the
+ * the Roaming Consortium advertised by a Hotspot, in order to consider this provider
+ * as a member of that Hotspot provider (e.g. successful authentication with such Hotspot
+ * is possible).
+ *
+ * Refer to HomeSP/HomeOIList subtree in PerProviderSubscription (PPS) Management Object
+ * (MO) tree for more detail.
+ */
+ private long[] mMatchAllOis = null;
+ public void setMatchAllOis(long[] matchAllOis) {
+ mMatchAllOis = matchAllOis;
+ }
+ public long[] getMatchAllOis() {
+ return mMatchAllOis;
+ }
+
+ /**
+ * Used for determining if this provider is a member of a given Hotspot provider.
+ * Matching of any Organization Identifiers (OIs) in this list with an OI in the
+ * Roaming Consortium advertised by a Hotspot, will consider this provider as a member
+ * of that Hotspot provider (e.g. successful authentication with such Hotspot
+ * is possible).
+ *
+ * {@link #mMatchAllOIs} will have precedence over this one, meaning this list will
+ * only be used for matching if {@link #mMatchAllOIs} is null or empty.
+ *
+ * Refer to HomeSP/HomeOIList subtree in PerProviderSubscription (PPS) Management Object
+ * (MO) tree for more detail.
+ */
+ private long[] mMatchAnyOis = null;
+ public void setMatchAnyOis(long[] matchAnyOis) {
+ mMatchAnyOis = matchAnyOis;
+ }
+ public long[] getMatchAnyOis() {
+ return mMatchAnyOis;
+ }
+
+ /**
+ * List of FQDN (Fully Qualified Domain Name) of partner providers.
+ * These providers should also be regarded as home Hotspot operators.
+ * This relationship is most likely achieved via a commercial agreement or
+ * operator merges between the providers.
+ */
+ private String[] mOtherHomePartners = null;
+ public void setOtherHomePartners(String[] otherHomePartners) {
+ mOtherHomePartners = otherHomePartners;
+ }
+ public String[] getOtherHomePartners() {
+ return mOtherHomePartners;
+ }
+
+ /**
+ * List of Organization Identifiers (OIs) identifying a roaming consortium of
+ * which this provider is a member.
+ */
+ private long[] mRoamingConsortiumOis = null;
+ public void setRoamingConsortiumOis(long[] roamingConsortiumOis) {
+ mRoamingConsortiumOis = roamingConsortiumOis;
+ }
+ public long[] getRoamingConsortiumOis() {
+ return mRoamingConsortiumOis;
+ }
+
+ /**
+ * Constructor for creating HomeSp with default values.
+ */
+ public HomeSp() {}
+
+ /**
+ * Copy constructor.
+ *
+ * @param source The source to copy from
+ */
+ public HomeSp(HomeSp source) {
+ if (source == null) {
+ return;
+ }
+ mFqdn = source.mFqdn;
+ mFriendlyName = source.mFriendlyName;
+ mIconUrl = source.mIconUrl;
+ if (source.mHomeNetworkIds != null) {
+ mHomeNetworkIds = Collections.unmodifiableMap(source.mHomeNetworkIds);
+ }
+ if (source.mMatchAllOis != null) {
+ mMatchAllOis = Arrays.copyOf(source.mMatchAllOis, source.mMatchAllOis.length);
+ }
+ if (source.mMatchAnyOis != null) {
+ mMatchAnyOis = Arrays.copyOf(source.mMatchAnyOis, source.mMatchAnyOis.length);
+ }
+ if (source.mOtherHomePartners != null) {
+ mOtherHomePartners = Arrays.copyOf(source.mOtherHomePartners,
+ source.mOtherHomePartners.length);
+ }
+ if (source.mRoamingConsortiumOis != null) {
+ mRoamingConsortiumOis = Arrays.copyOf(source.mRoamingConsortiumOis,
+ source.mRoamingConsortiumOis.length);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mFqdn);
+ dest.writeString(mFriendlyName);
+ dest.writeString(mIconUrl);
+ writeHomeNetworkIds(dest, mHomeNetworkIds);
+ dest.writeLongArray(mMatchAllOis);
+ dest.writeLongArray(mMatchAnyOis);
+ dest.writeStringArray(mOtherHomePartners);
+ dest.writeLongArray(mRoamingConsortiumOis);
+ }
+
+ @Override
+ public boolean equals(Object thatObject) {
+ if (this == thatObject) {
+ return true;
+ }
+ if (!(thatObject instanceof HomeSp)) {
+ return false;
+ }
+ HomeSp that = (HomeSp) thatObject;
+
+ return TextUtils.equals(mFqdn, that.mFqdn)
+ && TextUtils.equals(mFriendlyName, that.mFriendlyName)
+ && TextUtils.equals(mIconUrl, that.mIconUrl)
+ && (mHomeNetworkIds == null ? that.mHomeNetworkIds == null
+ : mHomeNetworkIds.equals(that.mHomeNetworkIds))
+ && Arrays.equals(mMatchAllOis, that.mMatchAllOis)
+ && Arrays.equals(mMatchAnyOis, that.mMatchAnyOis)
+ && Arrays.equals(mOtherHomePartners, that.mOtherHomePartners)
+ && Arrays.equals(mRoamingConsortiumOis, that.mRoamingConsortiumOis);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mFqdn, mFriendlyName, mIconUrl, mHomeNetworkIds, mMatchAllOis,
+ mMatchAnyOis, mOtherHomePartners, mRoamingConsortiumOis);
+ }
+
+ /**
+ * Validate HomeSp data.
+ *
+ * @return true on success or false on failure
+ */
+ public boolean validate() {
+ if (TextUtils.isEmpty(mFqdn)) {
+ Log.d(TAG, "Missing FQDN");
+ return false;
+ }
+ if (TextUtils.isEmpty(mFriendlyName)) {
+ Log.d(TAG, "Missing friendly name");
+ return false;
+ }
+ // Verify SSIDs specified in the NetworkID
+ if (mHomeNetworkIds != null) {
+ for (Map.Entry<String, Long> entry : mHomeNetworkIds.entrySet()) {
+ if (entry.getKey() == null ||
+ entry.getKey().getBytes(StandardCharsets.UTF_8).length > MAX_SSID_BYTES) {
+ Log.d(TAG, "Invalid SSID in HomeNetworkIDs");
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public static final Creator<HomeSp> CREATOR =
+ new Creator<HomeSp>() {
+ @Override
+ public HomeSp createFromParcel(Parcel in) {
+ HomeSp homeSp = new HomeSp();
+ homeSp.setFqdn(in.readString());
+ homeSp.setFriendlyName(in.readString());
+ homeSp.setIconUrl(in.readString());
+ homeSp.setHomeNetworkIds(readHomeNetworkIds(in));
+ homeSp.setMatchAllOis(in.createLongArray());
+ homeSp.setMatchAnyOis(in.createLongArray());
+ homeSp.setOtherHomePartners(in.createStringArray());
+ homeSp.setRoamingConsortiumOis(in.createLongArray());
+ return homeSp;
+ }
+
+ @Override
+ public HomeSp[] newArray(int size) {
+ return new HomeSp[size];
+ }
+
+ /**
+ * Helper function for reading a Home Network IDs map from a Parcel.
+ *
+ * @param in The Parcel to read from
+ * @return Map of home network IDs
+ */
+ private Map<String, Long> readHomeNetworkIds(Parcel in) {
+ int size = in.readInt();
+ if (size == NULL_VALUE) {
+ return null;
+ }
+ Map<String, Long> networkIds = new HashMap<>(size);
+ for (int i = 0; i < size; i++) {
+ String key = in.readString();
+ Long value = null;
+ long readValue = in.readLong();
+ if (readValue != NULL_VALUE) {
+ value = Long.valueOf(readValue);
+ }
+ networkIds.put(key, value);
+ }
+ return networkIds;
+ }
+ };
+
+ /**
+ * Helper function for writing Home Network IDs map to a Parcel.
+ *
+ * @param dest The Parcel to write to
+ * @param networkIds The map of home network IDs
+ */
+ private static void writeHomeNetworkIds(Parcel dest, Map<String, Long> networkIds) {
+ if (networkIds == null) {
+ dest.writeInt(NULL_VALUE);
+ return;
+ }
+ dest.writeInt(networkIds.size());
+ for (Map.Entry<String, Long> entry : networkIds.entrySet()) {
+ dest.writeString(entry.getKey());
+ if (entry.getValue() == null) {
+ dest.writeLong(NULL_VALUE);
+ } else {
+ dest.writeLong(entry.getValue());
+ }
+ }
+ }
+}
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl b/wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl
new file mode 100644
index 000000000000..e923f1f0fee8
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.hotspot2.pps;
+
+parcelable Policy;
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Policy.java b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
new file mode 100644
index 000000000000..63238e86c0fd
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
@@ -0,0 +1,539 @@
+/**
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.hotspot2.pps;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Class representing Policy subtree in PerProviderSubscription (PPS)
+ * Management Object (MO) tree.
+ *
+ * The Policy specifies additional criteria for Passpoint network selections, such as preferred
+ * roaming partner, minimum backhaul bandwidth, and etc. It also provides the meta data for
+ * updating the policy.
+ *
+ * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
+ * Release 2 Technical Specification.
+ */
+public final class Policy implements Parcelable {
+ private static final String TAG = "Policy";
+
+ /**
+ * Maximum number of SSIDs in the exclusion list.
+ */
+ private static final int MAX_EXCLUSION_SSIDS = 128;
+
+ /**
+ * Maximum byte for SSID.
+ */
+ private static final int MAX_SSID_BYTES = 32;
+
+ /**
+ * Maximum bytes for port string in {@link #requiredProtoPortMap}.
+ */
+ private static final int MAX_PORT_STRING_BYTES = 64;
+
+ /**
+ * Integer value used for indicating null value in the Parcel.
+ */
+ private static final int NULL_VALUE = -1;
+
+ /**
+ * Minimum available downlink/uplink bandwidth (in kilobits per second) required when
+ * selecting a network from home providers.
+ *
+ * The bandwidth is calculated as the LinkSpeed * (1 – LinkLoad/255), where LinkSpeed
+ * and LinkLoad parameters are drawn from the WAN Metrics ANQP element at that hotspot.
+ *
+ * Using Long.MIN_VALUE to indicate unset value.
+ */
+ private long mMinHomeDownlinkBandwidth = Long.MIN_VALUE;
+ public void setMinHomeDownlinkBandwidth(long minHomeDownlinkBandwidth) {
+ mMinHomeDownlinkBandwidth = minHomeDownlinkBandwidth;
+ }
+ public long getMinHomeDownlinkBandwidth() {
+ return mMinHomeDownlinkBandwidth;
+ }
+ private long mMinHomeUplinkBandwidth = Long.MIN_VALUE;
+ public void setMinHomeUplinkBandwidth(long minHomeUplinkBandwidth) {
+ mMinHomeUplinkBandwidth = minHomeUplinkBandwidth;
+ }
+ public long getMinHomeUplinkBandwidth() {
+ return mMinHomeUplinkBandwidth;
+ }
+
+ /**
+ * Minimum available downlink/uplink bandwidth (in kilobits per second) required when
+ * selecting a network from roaming providers.
+ *
+ * The bandwidth is calculated as the LinkSpeed * (1 – LinkLoad/255), where LinkSpeed
+ * and LinkLoad parameters are drawn from the WAN Metrics ANQP element at that hotspot.
+ *
+ * Using Long.MIN_VALUE to indicate unset value.
+ */
+ private long mMinRoamingDownlinkBandwidth = Long.MIN_VALUE;
+ public void setMinRoamingDownlinkBandwidth(long minRoamingDownlinkBandwidth) {
+ mMinRoamingDownlinkBandwidth = minRoamingDownlinkBandwidth;
+ }
+ public long getMinRoamingDownlinkBandwidth() {
+ return mMinRoamingDownlinkBandwidth;
+ }
+ private long mMinRoamingUplinkBandwidth = Long.MIN_VALUE;
+ public void setMinRoamingUplinkBandwidth(long minRoamingUplinkBandwidth) {
+ mMinRoamingUplinkBandwidth = minRoamingUplinkBandwidth;
+ }
+ public long getMinRoamingUplinkBandwidth() {
+ return mMinRoamingUplinkBandwidth;
+ }
+
+ /**
+ * List of SSIDs that are not preferred by the Home SP.
+ */
+ private String[] mExcludedSsidList = null;
+ public void setExcludedSsidList(String[] excludedSsidList) {
+ mExcludedSsidList = excludedSsidList;
+ }
+ public String[] getExcludedSsidList() {
+ return mExcludedSsidList;
+ }
+
+ /**
+ * List of IP protocol and port number required by one or more operator supported application.
+ * The port string contained one or more port numbers delimited by ",".
+ */
+ private Map<Integer, String> mRequiredProtoPortMap = null;
+ public void setRequiredProtoPortMap(Map<Integer, String> requiredProtoPortMap) {
+ mRequiredProtoPortMap = requiredProtoPortMap;
+ }
+ public Map<Integer, String> getRequiredProtoPortMap() {
+ return mRequiredProtoPortMap;
+ }
+
+ /**
+ * This specifies the maximum acceptable BSS load policy. This is used to prevent device
+ * from joining an AP whose channel is overly congested with traffic.
+ * Using Integer.MIN_VALUE to indicate unset value.
+ */
+ private int mMaximumBssLoadValue = Integer.MIN_VALUE;
+ public void setMaximumBssLoadValue(int maximumBssLoadValue) {
+ mMaximumBssLoadValue = maximumBssLoadValue;
+ }
+ public int getMaximumBssLoadValue() {
+ return mMaximumBssLoadValue;
+ }
+
+ /**
+ * Policy associated with a roaming provider. This specifies a priority associated
+ * with a roaming provider for given list of countries.
+ *
+ * Contains field under PerProviderSubscription/Policy/PreferredRoamingPartnerList.
+ */
+ public static final class RoamingPartner implements Parcelable {
+ /**
+ * FQDN of the roaming partner.
+ */
+ private String mFqdn = null;
+ public void setFqdn(String fqdn) {
+ mFqdn = fqdn;
+ }
+ public String getFqdn() {
+ return mFqdn;
+ }
+
+ /**
+ * Flag indicating the exact match of FQDN is required for FQDN matching.
+ *
+ * When this flag is set to false, sub-domain matching is used. For example, when
+ * {@link #fqdn} s set to "example.com", "host.example.com" would be a match.
+ */
+ private boolean mFqdnExactMatch = false;
+ public void setFqdnExactMatch(boolean fqdnExactMatch) {
+ mFqdnExactMatch = fqdnExactMatch;
+ }
+ public boolean getFqdnExactMatch() {
+ return mFqdnExactMatch;
+ }
+
+ /**
+ * Priority associated with this roaming partner policy.
+ * Using Integer.MIN_VALUE to indicate unset value.
+ */
+ private int mPriority = Integer.MIN_VALUE;
+ public void setPriority(int priority) {
+ mPriority = priority;
+ }
+ public int getPriority() {
+ return mPriority;
+ }
+
+ /**
+ * A string contained One or more, comma delimited (i.e., ",") ISO/IEC 3166-1 two
+ * character country strings or the country-independent value, "*".
+ */
+ private String mCountries = null;
+ public void setCountries(String countries) {
+ mCountries = countries;
+ }
+ public String getCountries() {
+ return mCountries;
+ }
+
+ public RoamingPartner() {}
+
+ public RoamingPartner(RoamingPartner source) {
+ if (source != null) {
+ mFqdn = source.mFqdn;
+ mFqdnExactMatch = source.mFqdnExactMatch;
+ mPriority = source.mPriority;
+ mCountries = source.mCountries;
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mFqdn);
+ dest.writeInt(mFqdnExactMatch ? 1 : 0);
+ dest.writeInt(mPriority);
+ dest.writeString(mCountries);
+ }
+
+ @Override
+ public boolean equals(Object thatObject) {
+ if (this == thatObject) {
+ return true;
+ }
+ if (!(thatObject instanceof RoamingPartner)) {
+ return false;
+ }
+
+ RoamingPartner that = (RoamingPartner) thatObject;
+ return TextUtils.equals(mFqdn, that.mFqdn)
+ && mFqdnExactMatch == that.mFqdnExactMatch
+ && mPriority == that.mPriority
+ && TextUtils.equals(mCountries, that.mCountries);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mFqdn, mFqdnExactMatch, mPriority, mCountries);
+ }
+
+ /**
+ * Validate RoamingParnter data.
+ *
+ * @return true on success
+ */
+ public boolean validate() {
+ if (TextUtils.isEmpty(mFqdn)) {
+ Log.d(TAG, "Missing FQDN");
+ return false;
+ }
+ if (TextUtils.isEmpty(mCountries)) {
+ Log.d(TAG, "Missing countries");
+ return false;
+ }
+ return true;
+ }
+
+ public static final Creator<RoamingPartner> CREATOR =
+ new Creator<RoamingPartner>() {
+ @Override
+ public RoamingPartner createFromParcel(Parcel in) {
+ RoamingPartner roamingPartner = new RoamingPartner();
+ roamingPartner.setFqdn(in.readString());
+ roamingPartner.setFqdnExactMatch(in.readInt() != 0);
+ roamingPartner.setPriority(in.readInt());
+ roamingPartner.setCountries(in.readString());
+ return roamingPartner;
+ }
+
+ @Override
+ public RoamingPartner[] newArray(int size) {
+ return new RoamingPartner[size];
+ }
+ };
+ }
+ private List<RoamingPartner> mPreferredRoamingPartnerList = null;
+ public void setPreferredRoamingPartnerList(List<RoamingPartner> partnerList) {
+ mPreferredRoamingPartnerList = partnerList;
+ }
+ public List<RoamingPartner> getPreferredRoamingPartnerList() {
+ return mPreferredRoamingPartnerList;
+ }
+
+ /**
+ * Meta data used for policy update.
+ */
+ private UpdateParameter mPolicyUpdate = null;
+ public void setPolicyUpdate(UpdateParameter policyUpdate) {
+ mPolicyUpdate = policyUpdate;
+ }
+ public UpdateParameter getPolicyUpdate() {
+ return mPolicyUpdate;
+ }
+
+ /**
+ * Constructor for creating Policy with default values.
+ */
+ public Policy() {}
+
+ /**
+ * Copy constructor.
+ *
+ * @param source The source to copy from
+ */
+ public Policy(Policy source) {
+ if (source == null) {
+ return;
+ }
+ mMinHomeDownlinkBandwidth = source.mMinHomeDownlinkBandwidth;
+ mMinHomeUplinkBandwidth = source.mMinHomeUplinkBandwidth;
+ mMinRoamingDownlinkBandwidth = source.mMinRoamingDownlinkBandwidth;
+ mMinRoamingUplinkBandwidth = source.mMinRoamingUplinkBandwidth;
+ mMaximumBssLoadValue = source.mMaximumBssLoadValue;
+ if (source.mExcludedSsidList != null) {
+ mExcludedSsidList = Arrays.copyOf(source.mExcludedSsidList,
+ source.mExcludedSsidList.length);
+ }
+ if (source.mRequiredProtoPortMap != null) {
+ mRequiredProtoPortMap = Collections.unmodifiableMap(source.mRequiredProtoPortMap);
+ }
+ if (source.mPreferredRoamingPartnerList != null) {
+ mPreferredRoamingPartnerList = Collections.unmodifiableList(
+ source.mPreferredRoamingPartnerList);
+ }
+ if (source.mPolicyUpdate != null) {
+ mPolicyUpdate = new UpdateParameter(source.mPolicyUpdate);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(mMinHomeDownlinkBandwidth);
+ dest.writeLong(mMinHomeUplinkBandwidth);
+ dest.writeLong(mMinRoamingDownlinkBandwidth);
+ dest.writeLong(mMinRoamingUplinkBandwidth);
+ dest.writeStringArray(mExcludedSsidList);
+ writeProtoPortMap(dest, mRequiredProtoPortMap);
+ dest.writeInt(mMaximumBssLoadValue);
+ writeRoamingPartnerList(dest, flags, mPreferredRoamingPartnerList);
+ dest.writeParcelable(mPolicyUpdate, flags);
+ }
+
+ @Override
+ public boolean equals(Object thatObject) {
+ if (this == thatObject) {
+ return true;
+ }
+ if (!(thatObject instanceof Policy)) {
+ return false;
+ }
+ Policy that = (Policy) thatObject;
+
+ return mMinHomeDownlinkBandwidth == that.mMinHomeDownlinkBandwidth
+ && mMinHomeUplinkBandwidth == that.mMinHomeUplinkBandwidth
+ && mMinRoamingDownlinkBandwidth == that.mMinRoamingDownlinkBandwidth
+ && mMinRoamingUplinkBandwidth == that.mMinRoamingUplinkBandwidth
+ && Arrays.equals(mExcludedSsidList, that.mExcludedSsidList)
+ && (mRequiredProtoPortMap == null ? that.mRequiredProtoPortMap == null
+ : mRequiredProtoPortMap.equals(that.mRequiredProtoPortMap))
+ && mMaximumBssLoadValue == that.mMaximumBssLoadValue
+ && (mPreferredRoamingPartnerList == null
+ ? that.mPreferredRoamingPartnerList == null
+ : mPreferredRoamingPartnerList.equals(that.mPreferredRoamingPartnerList))
+ && (mPolicyUpdate == null ? that.mPolicyUpdate == null
+ : mPolicyUpdate.equals(that.mPolicyUpdate));
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mMinHomeDownlinkBandwidth, mMinHomeUplinkBandwidth,
+ mMinRoamingDownlinkBandwidth, mMinRoamingUplinkBandwidth, mExcludedSsidList,
+ mRequiredProtoPortMap, mMaximumBssLoadValue, mPreferredRoamingPartnerList,
+ mPolicyUpdate);
+ }
+
+ /**
+ * Validate Policy data.
+ *
+ * @return true on success
+ */
+ public boolean validate() {
+ if (mPolicyUpdate == null) {
+ Log.d(TAG, "PolicyUpdate not specified");
+ return false;
+ }
+ if (!mPolicyUpdate.validate()) {
+ return false;
+ }
+
+ // Validate SSID exclusion list.
+ if (mExcludedSsidList != null) {
+ if (mExcludedSsidList.length > MAX_EXCLUSION_SSIDS) {
+ Log.d(TAG, "SSID exclusion list size exceeded the max: "
+ + mExcludedSsidList.length);
+ return false;
+ }
+ for (String ssid : mExcludedSsidList) {
+ if (ssid.getBytes(StandardCharsets.UTF_8).length > MAX_SSID_BYTES) {
+ Log.d(TAG, "Invalid SSID: " + ssid);
+ return false;
+ }
+ }
+ }
+ // Validate required protocol to port map.
+ if (mRequiredProtoPortMap != null) {
+ for (Map.Entry<Integer, String> entry : mRequiredProtoPortMap.entrySet()) {
+ String portNumber = entry.getValue();
+ if (portNumber.getBytes(StandardCharsets.UTF_8).length > MAX_PORT_STRING_BYTES) {
+ Log.d(TAG, "PortNumber string bytes exceeded the max: " + portNumber);
+ return false;
+ }
+ }
+ }
+ // Validate preferred roaming partner list.
+ if (mPreferredRoamingPartnerList != null) {
+ for (RoamingPartner partner : mPreferredRoamingPartnerList) {
+ if (!partner.validate()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public static final Creator<Policy> CREATOR =
+ new Creator<Policy>() {
+ @Override
+ public Policy createFromParcel(Parcel in) {
+ Policy policy = new Policy();
+ policy.setMinHomeDownlinkBandwidth(in.readLong());
+ policy.setMinHomeUplinkBandwidth(in.readLong());
+ policy.setMinRoamingDownlinkBandwidth(in.readLong());
+ policy.setMinRoamingUplinkBandwidth(in.readLong());
+ policy.setExcludedSsidList(in.createStringArray());
+ policy.setRequiredProtoPortMap(readProtoPortMap(in));
+ policy.setMaximumBssLoadValue(in.readInt());
+ policy.setPreferredRoamingPartnerList(readRoamingPartnerList(in));
+ policy.setPolicyUpdate(in.readParcelable(null));
+ return policy;
+ }
+
+ @Override
+ public Policy[] newArray(int size) {
+ return new Policy[size];
+ }
+
+ /**
+ * Helper function for reading IP Protocol to Port Number map from a Parcel.
+ *
+ * @param in The Parcel to read from
+ * @return Map of IP protocol to port number
+ */
+ private Map<Integer, String> readProtoPortMap(Parcel in) {
+ int size = in.readInt();
+ if (size == NULL_VALUE) {
+ return null;
+ }
+ Map<Integer, String> protoPortMap = new HashMap<>(size);
+ for (int i = 0; i < size; i++) {
+ int key = in.readInt();
+ String value = in.readString();
+ protoPortMap.put(key, value);
+ }
+ return protoPortMap;
+ }
+
+ /**
+ * Helper function for reading roaming partner list from a Parcel.
+ *
+ * @param in The Parcel to read from
+ * @return List of roaming partners
+ */
+ private List<RoamingPartner> readRoamingPartnerList(Parcel in) {
+ int size = in.readInt();
+ if (size == NULL_VALUE) {
+ return null;
+ }
+ List<RoamingPartner> partnerList = new ArrayList<>();
+ for (int i = 0; i < size; i++) {
+ partnerList.add(in.readParcelable(null));
+ }
+ return partnerList;
+ }
+
+ };
+
+ /**
+ * Helper function for writing IP Protocol to Port Number map to a Parcel.
+ *
+ * @param dest The Parcel to write to
+ * @param protoPortMap The map to write
+ */
+ private static void writeProtoPortMap(Parcel dest, Map<Integer, String> protoPortMap) {
+ if (protoPortMap == null) {
+ dest.writeInt(NULL_VALUE);
+ return;
+ }
+ dest.writeInt(protoPortMap.size());
+ for (Map.Entry<Integer, String> entry : protoPortMap.entrySet()) {
+ dest.writeInt(entry.getKey());
+ dest.writeString(entry.getValue());
+ }
+ }
+
+ /**
+ * Helper function for writing roaming partner list to a Parcel.
+ *
+ * @param dest The Parcel to write to
+ * @param flags The flag about how the object should be written
+ * @param partnerList The partner list to write
+ */
+ private static void writeRoamingPartnerList(Parcel dest, int flags,
+ List<RoamingPartner> partnerList) {
+ if (partnerList == null) {
+ dest.writeInt(NULL_VALUE);
+ return;
+ }
+ dest.writeInt(partnerList.size());
+ for (RoamingPartner partner : partnerList) {
+ dest.writeParcelable(partner, flags);
+ }
+ }
+}
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.aidl b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.aidl
new file mode 100644
index 000000000000..701db479076a
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.hotspot2.pps;
+
+parcelable UpdateParameter;
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java
new file mode 100644
index 000000000000..70264b0e625a
--- /dev/null
+++ b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java
@@ -0,0 +1,357 @@
+/**
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.hotspot2.pps;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.Log;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Class representing configuration parameters for subscription or policy update in
+ * PerProviderSubscription (PPS) Management Object (MO) tree. This is used by both
+ * PerProviderSubscription/Policy/PolicyUpdate and PerProviderSubscription/SubscriptionUpdate
+ * subtree.
+ *
+ * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
+ * Release 2 Technical Specification.
+ */
+public final class UpdateParameter implements Parcelable {
+ private static final String TAG = "UpdateParameter";
+
+ /**
+ * Value indicating policy update is not applicable. Thus, never check with policy server
+ * for updates.
+ */
+ public static final long UPDATE_CHECK_INTERVAL_NEVER = 0xFFFFFFFFL;
+
+ /**
+ * Valid string for UpdateMethod.
+ */
+ public static final String UPDATE_METHOD_OMADM = "OMA-DM-ClientInitiated";
+ public static final String UPDATE_METHOD_SSP = "SSP-ClientInitiated";
+
+ /**
+ * Valid string for Restriction.
+ */
+ public static final String UPDATE_RESTRICTION_HOMESP = "HomeSP";
+ public static final String UPDATE_RESTRICTION_ROAMING_PARTNER = "RoamingPartner";
+ public static final String UPDATE_RESTRICTION_UNRESTRICTED = "Unrestricted";
+
+ /**
+ * Maximum bytes for URI string.
+ */
+ private static final int MAX_URI_BYTES = 1023;
+
+ /**
+ * Maximum bytes for URI string.
+ */
+ private static final int MAX_URL_BYTES = 1023;
+
+ /**
+ * Maximum bytes for username.
+ */
+ private static final int MAX_USERNAME_BYTES = 63;
+
+ /**
+ * Maximum bytes for password.
+ */
+ private static final int MAX_PASSWORD_BYTES = 255;
+
+ /**
+ * Number of bytes for certificate SHA-256 fingerprint byte array.
+ */
+ private static final int CERTIFICATE_SHA256_BYTES = 32;
+
+ /**
+ * This specifies how often the mobile device shall check with policy server for updates.
+ *
+ * Using Long.MIN_VALUE to indicate unset value.
+ */
+ private long mUpdateIntervalInMinutes = Long.MIN_VALUE;
+ public void setUpdateIntervalInMinutes(long updateIntervalInMinutes) {
+ mUpdateIntervalInMinutes = updateIntervalInMinutes;
+ }
+ public long getUpdateIntervalInMinutes() {
+ return mUpdateIntervalInMinutes;
+ }
+
+ /**
+ * The method used to update the policy. Permitted values are "OMA-DM-ClientInitiated"
+ * and "SPP-ClientInitiated".
+ */
+ private String mUpdateMethod = null;
+ public void setUpdateMethod(String updateMethod) {
+ mUpdateMethod = updateMethod;
+ }
+ public String getUpdateMethod() {
+ return mUpdateMethod;
+ }
+
+ /**
+ * This specifies the hotspots at which the subscription update is permitted. Permitted
+ * values are "HomeSP", "RoamingPartner", or "Unrestricted";
+ */
+ private String mRestriction = null;
+ public void setRestriction(String restriction) {
+ mRestriction = restriction;
+ }
+ public String getRestriction() {
+ return mRestriction;
+ }
+
+ /**
+ * The URI of the update server.
+ */
+ private String mServerUri = null;
+ public void setServerUri(String serverUri) {
+ mServerUri = serverUri;
+ }
+ public String getServerUri() {
+ return mServerUri;
+ }
+
+ /**
+ * Username used to authenticate with the policy server.
+ */
+ private String mUsername = null;
+ public void setUsername(String username) {
+ mUsername = username;
+ }
+ public String getUsername() {
+ return mUsername;
+ }
+
+ /**
+ * Base64 encoded password used to authenticate with the policy server.
+ */
+ private String mBase64EncodedPassword = null;
+ public void setBase64EncodedPassword(String password) {
+ mBase64EncodedPassword = password;
+ }
+ public String getBase64EncodedPassword() {
+ return mBase64EncodedPassword;
+ }
+
+ /**
+ * HTTPS URL for retrieving certificate for trust root. The trust root is used to validate
+ * policy server's identity.
+ */
+ private String mTrustRootCertUrl = null;
+ public void setTrustRootCertUrl(String trustRootCertUrl) {
+ mTrustRootCertUrl = trustRootCertUrl;
+ }
+ public String getTrustRootCertUrl() {
+ return mTrustRootCertUrl;
+ }
+
+ /**
+ * SHA-256 fingerprint of the certificate located at {@link #trustRootCertUrl}
+ */
+ private byte[] mTrustRootCertSha256Fingerprint = null;
+ public void setTrustRootCertSha256Fingerprint(byte[] fingerprint) {
+ mTrustRootCertSha256Fingerprint = fingerprint;
+ }
+ public byte[] getTrustRootCertSha256Fingerprint() {
+ return mTrustRootCertSha256Fingerprint;
+ }
+
+ /**
+ * Constructor for creating Policy with default values.
+ */
+ public UpdateParameter() {}
+
+ /**
+ * Copy constructor.
+ *
+ * @param source The source to copy from
+ */
+ public UpdateParameter(UpdateParameter source) {
+ if (source == null) {
+ return;
+ }
+ mUpdateIntervalInMinutes = source.mUpdateIntervalInMinutes;
+ mUpdateMethod = source.mUpdateMethod;
+ mRestriction = source.mRestriction;
+ mServerUri = source.mServerUri;
+ mUsername = source.mUsername;
+ mBase64EncodedPassword = source.mBase64EncodedPassword;
+ mTrustRootCertUrl = source.mTrustRootCertUrl;
+ if (source.mTrustRootCertSha256Fingerprint != null) {
+ mTrustRootCertSha256Fingerprint = Arrays.copyOf(source.mTrustRootCertSha256Fingerprint,
+ source.mTrustRootCertSha256Fingerprint.length);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(mUpdateIntervalInMinutes);
+ dest.writeString(mUpdateMethod);
+ dest.writeString(mRestriction);
+ dest.writeString(mServerUri);
+ dest.writeString(mUsername);
+ dest.writeString(mBase64EncodedPassword);
+ dest.writeString(mTrustRootCertUrl);
+ dest.writeByteArray(mTrustRootCertSha256Fingerprint);
+ }
+
+ @Override
+ public boolean equals(Object thatObject) {
+ if (this == thatObject) {
+ return true;
+ }
+ if (!(thatObject instanceof UpdateParameter)) {
+ return false;
+ }
+ UpdateParameter that = (UpdateParameter) thatObject;
+
+ return mUpdateIntervalInMinutes == that.mUpdateIntervalInMinutes
+ && TextUtils.equals(mUpdateMethod, that.mUpdateMethod)
+ && TextUtils.equals(mRestriction, that.mRestriction)
+ && TextUtils.equals(mServerUri, that.mServerUri)
+ && TextUtils.equals(mUsername, that.mUsername)
+ && TextUtils.equals(mBase64EncodedPassword, that.mBase64EncodedPassword)
+ && TextUtils.equals(mTrustRootCertUrl, that.mTrustRootCertUrl)
+ && Arrays.equals(mTrustRootCertSha256Fingerprint,
+ that.mTrustRootCertSha256Fingerprint);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUpdateIntervalInMinutes, mUpdateMethod, mRestriction, mServerUri,
+ mUsername, mBase64EncodedPassword, mTrustRootCertUrl,
+ mTrustRootCertSha256Fingerprint);
+ }
+
+ /**
+ * Validate UpdateParameter data.
+ *
+ * @return true on success
+ */
+ public boolean validate() {
+ if (mUpdateIntervalInMinutes == Long.MIN_VALUE) {
+ Log.d(TAG, "Update interval not specified");
+ return false;
+ }
+ // Update not applicable.
+ if (mUpdateIntervalInMinutes == UPDATE_CHECK_INTERVAL_NEVER) {
+ return true;
+ }
+
+ if (!TextUtils.equals(mUpdateMethod, UPDATE_METHOD_OMADM)
+ && !TextUtils.equals(mUpdateMethod, UPDATE_METHOD_SSP)) {
+ Log.d(TAG, "Unknown update method: " + mUpdateMethod);
+ return false;
+ }
+
+ if (!TextUtils.equals(mRestriction, UPDATE_RESTRICTION_HOMESP)
+ && !TextUtils.equals(mRestriction, UPDATE_RESTRICTION_ROAMING_PARTNER)
+ && !TextUtils.equals(mRestriction, UPDATE_RESTRICTION_UNRESTRICTED)) {
+ Log.d(TAG, "Unknown restriction: " + mRestriction);
+ return false;
+ }
+
+ if (TextUtils.isEmpty(mServerUri)) {
+ Log.d(TAG, "Missing update server URI");
+ return false;
+ }
+ if (mServerUri.getBytes(StandardCharsets.UTF_8).length > MAX_URI_BYTES) {
+ Log.d(TAG, "URI bytes exceeded the max: "
+ + mServerUri.getBytes(StandardCharsets.UTF_8).length);
+ return false;
+ }
+
+ if (TextUtils.isEmpty(mUsername)) {
+ Log.d(TAG, "Missing username");
+ return false;
+ }
+ if (mUsername.getBytes(StandardCharsets.UTF_8).length > MAX_USERNAME_BYTES) {
+ Log.d(TAG, "Username bytes exceeded the max: "
+ + mUsername.getBytes(StandardCharsets.UTF_8).length);
+ return false;
+ }
+
+ if (TextUtils.isEmpty(mBase64EncodedPassword)) {
+ Log.d(TAG, "Missing username");
+ return false;
+ }
+ if (mBase64EncodedPassword.getBytes(StandardCharsets.UTF_8).length > MAX_PASSWORD_BYTES) {
+ Log.d(TAG, "Password bytes exceeded the max: "
+ + mBase64EncodedPassword.getBytes(StandardCharsets.UTF_8).length);
+ return false;
+ }
+ try {
+ Base64.decode(mBase64EncodedPassword, Base64.DEFAULT);
+ } catch (IllegalArgumentException e) {
+ Log.d(TAG, "Invalid encoding for password: " + mBase64EncodedPassword);
+ return false;
+ }
+
+ if (TextUtils.isEmpty(mTrustRootCertUrl)) {
+ Log.d(TAG, "Missing trust root certificate URL");
+ return false;
+ }
+ if (mTrustRootCertUrl.getBytes(StandardCharsets.UTF_8).length > MAX_URL_BYTES) {
+ Log.d(TAG, "Trust root cert URL bytes exceeded the max: "
+ + mTrustRootCertUrl.getBytes(StandardCharsets.UTF_8).length);
+ return false;
+ }
+
+ if (mTrustRootCertSha256Fingerprint == null) {
+ Log.d(TAG, "Missing trust root certificate SHA-256 fingerprint");
+ return false;
+ }
+ if (mTrustRootCertSha256Fingerprint.length != CERTIFICATE_SHA256_BYTES) {
+ Log.d(TAG, "Incorrect size of trust root certificate SHA-256 fingerprint: "
+ + mTrustRootCertSha256Fingerprint.length);
+ return false;
+ }
+ return true;
+ }
+
+ public static final Creator<UpdateParameter> CREATOR =
+ new Creator<UpdateParameter>() {
+ @Override
+ public UpdateParameter createFromParcel(Parcel in) {
+ UpdateParameter updateParam = new UpdateParameter();
+ updateParam.setUpdateIntervalInMinutes(in.readLong());
+ updateParam.setUpdateMethod(in.readString());
+ updateParam.setRestriction(in.readString());
+ updateParam.setServerUri(in.readString());
+ updateParam.setUsername(in.readString());
+ updateParam.setBase64EncodedPassword(in.readString());
+ updateParam.setTrustRootCertUrl(in.readString());
+ updateParam.setTrustRootCertSha256Fingerprint(in.createByteArray());
+ return updateParam;
+ }
+
+ @Override
+ public UpdateParameter[] newArray(int size) {
+ return new UpdateParameter[size];
+ }
+ };
+}
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64
index 8c1eb0867298..995963d2b4cc 100644
--- a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64
@@ -42,7 +42,7 @@ V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ
a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD
QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q
-VTJSbWx1WjJWeVVISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
+VTJSbWx1WjJWeWNISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG
bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB
OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf
index 6d86dd53eb76..3ddd09f91ff4 100644
--- a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf
@@ -35,7 +35,7 @@ ICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkRpZ2l0YWxDZXJ0
aWZpY2F0ZTwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1l
PkNlcnRpZmljYXRlVHlwZTwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxWYWx1ZT54NTA5djM8L1Zh
bHVlPgogICAgICAgICAgPC9Ob2RlPgogICAgICAgICAgPE5vZGU+CiAgICAgICAgICAgIDxOb2Rl
-TmFtZT5DZXJ0U0hBMjU2RmluZ2VyUHJpbnQ8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+
+TmFtZT5DZXJ0U0hBMjU2RmluZ2VycHJpbnQ8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+
MWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYx
ZjFmMWYxZjwvVmFsdWU+CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgPC9Ob2RlPgogICAgICAg
IDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlNJTTwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9k
diff --git a/wifi/tests/assets/pps/PerProviderSubscription.xml b/wifi/tests/assets/pps/PerProviderSubscription.xml
index 53d38ad23b9b..7f2d95de95e9 100644
--- a/wifi/tests/assets/pps/PerProviderSubscription.xml
+++ b/wifi/tests/assets/pps/PerProviderSubscription.xml
@@ -8,6 +8,10 @@
</Type>
</RTProperties>
<Node>
+ <NodeName>UpdateIdentifier</NodeName>
+ <Value>12</Value>
+ </Node>
+ <Node>
<NodeName>i001</NodeName>
<Node>
<NodeName>HomeSP</NodeName>
@@ -23,14 +27,86 @@
<NodeName>RoamingConsortiumOI</NodeName>
<Value>112233,445566</Value>
</Node>
+ <Node>
+ <NodeName>IconURL</NodeName>
+ <Value>icon.test.com</Value>
+ </Node>
+ <Node>
+ <NodeName>NetworkID</NodeName>
+ <Node>
+ <NodeName>n001</NodeName>
+ <Node>
+ <NodeName>SSID</NodeName>
+ <Value>TestSSID</Value>
+ </Node>
+ <Node>
+ <NodeName>HESSID</NodeName>
+ <Value>12345678</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>n002</NodeName>
+ <Node>
+ <NodeName>SSID</NodeName>
+ <Value>NullHESSID</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>HomeOIList</NodeName>
+ <Node>
+ <NodeName>h001</NodeName>
+ <Node>
+ <NodeName>HomeOI</NodeName>
+ <Value>11223344</Value>
+ </Node>
+ <Node>
+ <NodeName>HomeOIRequired</NodeName>
+ <Value>true</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>h002</NodeName>
+ <Node>
+ <NodeName>HomeOI</NodeName>
+ <Value>55667788</Value>
+ </Node>
+ <Node>
+ <NodeName>HomeOIRequired</NodeName>
+ <Value>false</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>OtherHomePartners</NodeName>
+ <Node>
+ <NodeName>o001</NodeName>
+ <Node>
+ <NodeName>FQDN</NodeName>
+ <Value>other.fqdn.com</Value>
+ </Node>
+ </Node>
+ </Node>
</Node>
<Node>
<NodeName>Credential</NodeName>
<Node>
+ <NodeName>CreationDate</NodeName>
+ <Value>2016-01-01T10:00:00Z</Value>
+ </Node>
+ <Node>
+ <NodeName>ExpirationDate</NodeName>
+ <Value>2016-02-01T10:00:00Z</Value>
+ </Node>
+ <Node>
<NodeName>Realm</NodeName>
<Value>shaken.stirred.com</Value>
</Node>
<Node>
+ <NodeName>CheckAAAServerCertStatus</NodeName>
+ <Value>true</Value>
+ </Node>
+ <Node>
<NodeName>UsernamePassword</NodeName>
<Node>
<NodeName>Username</NodeName>
@@ -41,6 +117,18 @@
<Value>Ym9uZDAwNw==</Value>
</Node>
<Node>
+ <NodeName>MachineManaged</NodeName>
+ <Value>true</Value>
+ </Node>
+ <Node>
+ <NodeName>SoftTokenApp</NodeName>
+ <Value>TestApp</Value>
+ </Node>
+ <Node>
+ <NodeName>AbleToShare</NodeName>
+ <Value>true</Value>
+ </Node>
+ <Node>
<NodeName>EAPMethod</NodeName>
<Node>
<NodeName>EAPType</NodeName>
@@ -59,7 +147,7 @@
<Value>x509v3</Value>
</Node>
<Node>
- <NodeName>CertSHA256FingerPrint</NodeName>
+ <NodeName>CertSHA256Fingerprint</NodeName>
<Value>1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f</Value>
</Node>
</Node>
@@ -75,6 +163,237 @@
</Node>
</Node>
</Node>
+ <Node>
+ <NodeName>Policy</NodeName>
+ <Node>
+ <NodeName>PreferredRoamingPartnerList</NodeName>
+ <Node>
+ <NodeName>p001</NodeName>
+ <Node>
+ <NodeName>FQDN_Match</NodeName>
+ <Value>test1.fqdn.com,exactMatch</Value>
+ </Node>
+ <Node>
+ <NodeName>Priority</NodeName>
+ <Value>127</Value>
+ </Node>
+ <Node>
+ <NodeName>Country</NodeName>
+ <Value>us,fr</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>p002</NodeName>
+ <Node>
+ <NodeName>FQDN_Match</NodeName>
+ <Value>test2.fqdn.com,includeSubdomains</Value>
+ </Node>
+ <Node>
+ <NodeName>Priority</NodeName>
+ <Value>200</Value>
+ </Node>
+ <Node>
+ <NodeName>Country</NodeName>
+ <Value>*</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>MinBackhaulThreshold</NodeName>
+ <Node>
+ <NodeName>m001</NodeName>
+ <Node>
+ <NodeName>NetworkType</NodeName>
+ <Value>home</Value>
+ </Node>
+ <Node>
+ <NodeName>DLBandwidth</NodeName>
+ <Value>23412</Value>
+ </Node>
+ <Node>
+ <NodeName>ULBandwidth</NodeName>
+ <Value>9823</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>m002</NodeName>
+ <Node>
+ <NodeName>NetworkType</NodeName>
+ <Value>roaming</Value>
+ </Node>
+ <Node>
+ <NodeName>DLBandwidth</NodeName>
+ <Value>9271</Value>
+ </Node>
+ <Node>
+ <NodeName>ULBandwidth</NodeName>
+ <Value>2315</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>PolicyUpdate</NodeName>
+ <Node>
+ <NodeName>UpdateInterval</NodeName>
+ <Value>120</Value>
+ </Node>
+ <Node>
+ <NodeName>UpdateMethod</NodeName>
+ <Value>OMA-DM-ClientInitiated</Value>
+ </Node>
+ <Node>
+ <NodeName>Restriction</NodeName>
+ <Value>HomeSP</Value>
+ </Node>
+ <Node>
+ <NodeName>URI</NodeName>
+ <Value>policy.update.com</Value>
+ </Node>
+ <Node>
+ <NodeName>UsernamePassword</NodeName>
+ <Node>
+ <NodeName>Username</NodeName>
+ <Value>updateUser</Value>
+ </Node>
+ <Node>
+ <NodeName>Password</NodeName>
+ <Value>updatePass</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>TrustRoot</NodeName>
+ <Node>
+ <NodeName>CertURL</NodeName>
+ <Value>update.cert.com</Value>
+ </Node>
+ <Node>
+ <NodeName>CertSHA256Fingerprint</NodeName>
+ <Value>1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>SPExclusionList</NodeName>
+ <Node>
+ <NodeName>s001</NodeName>
+ <Node>
+ <NodeName>SSID</NodeName>
+ <Value>excludeSSID</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>RequiredProtoPortTuple</NodeName>
+ <Node>
+ <NodeName>r001</NodeName>
+ <Node>
+ <NodeName>IPProtocol</NodeName>
+ <Value>12</Value>
+ </Node>
+ <Node>
+ <NodeName>PortNumber</NodeName>
+ <Value>34,92,234</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>MaximumBSSLoadValue</NodeName>
+ <Value>23</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>CredentialPriority</NodeName>
+ <Value>99</Value>
+ </Node>
+ <Node>
+ <NodeName>AAAServerTrustRoot</NodeName>
+ <Node>
+ <NodeName>a001</NodeName>
+ <Node>
+ <NodeName>CertURL</NodeName>
+ <Value>server1.trust.root.com</Value>
+ </Node>
+ <Node>
+ <NodeName>CertSHA256Fingerprint</NodeName>
+ <Value>1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>SubscriptionUpdate</NodeName>
+ <Node>
+ <NodeName>UpdateInterval</NodeName>
+ <Value>120</Value>
+ </Node>
+ <Node>
+ <NodeName>UpdateMethod</NodeName>
+ <Value>SSP-ClientInitiated</Value>
+ </Node>
+ <Node>
+ <NodeName>Restriction</NodeName>
+ <Value>RoamingPartner</Value>
+ </Node>
+ <Node>
+ <NodeName>URI</NodeName>
+ <Value>subscription.update.com</Value>
+ </Node>
+ <Node>
+ <NodeName>UsernamePassword</NodeName>
+ <Node>
+ <NodeName>Username</NodeName>
+ <Value>subscriptionUser</Value>
+ </Node>
+ <Node>
+ <NodeName>Password</NodeName>
+ <Value>subscriptionPass</Value>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>TrustRoot</NodeName>
+ <Node>
+ <NodeName>CertURL</NodeName>
+ <Value>subscription.update.cert.com</Value>
+ </Node>
+ <Node>
+ <NodeName>CertSHA256Fingerprint</NodeName>
+ <Value>1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f</Value>
+ </Node>
+ </Node>
+ </Node>
+ <Node>
+ <NodeName>SubscriptionParameter</NodeName>
+ <Node>
+ <NodeName>CreationDate</NodeName>
+ <Value>2016-02-01T10:00:00Z</Value>
+ </Node>
+ <Node>
+ <NodeName>ExpirationDate</NodeName>
+ <Value>2016-03-01T10:00:00Z</Value>
+ </Node>
+ <Node>
+ <NodeName>TypeOfSubscription</NodeName>
+ <Value>Gold</Value>
+ </Node>
+ <Node>
+ <NodeName>UsageLimits</NodeName>
+ <Node>
+ <NodeName>DataLimit</NodeName>
+ <Value>921890</Value>
+ </Node>
+ <Node>
+ <NodeName>StartDate</NodeName>
+ <Value>2016-12-01T10:00:00Z</Value>
+ </Node>
+ <Node>
+ <NodeName>TimeLimit</NodeName>
+ <Value>120</Value>
+ </Node>
+ <Node>
+ <NodeName>UsageTimePeriod</NodeName>
+ <Value>99910</Value>
+ </Node>
+ </Node>
+ </Node>
</Node>
</Node>
</MgmtTree>
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 5f9497474a77..632cfaf2155a 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -20,6 +20,7 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import android.os.Parcel;
+import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
import org.junit.Before;
import org.junit.Test;
@@ -66,4 +67,35 @@ public class WifiConfigurationTest {
assertArrayEquals(bytes, rebytes);
}
+
+ @Test
+ public void testNetworkSelectionStatusCopy() {
+ NetworkSelectionStatus networkSelectionStatus = new NetworkSelectionStatus();
+ networkSelectionStatus.setNotRecommended(true);
+
+ NetworkSelectionStatus copy = new NetworkSelectionStatus();
+ copy.copy(networkSelectionStatus);
+
+ assertEquals(networkSelectionStatus.isNotRecommended(), copy.isNotRecommended());
+ }
+
+ @Test
+ public void testNetworkSelectionStatusParcel() {
+ NetworkSelectionStatus networkSelectionStatus = new NetworkSelectionStatus();
+ networkSelectionStatus.setNotRecommended(true);
+
+ Parcel parcelW = Parcel.obtain();
+ networkSelectionStatus.writeToParcel(parcelW);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+
+ NetworkSelectionStatus copy = new NetworkSelectionStatus();
+ copy.readFromParcel(parcelR);
+
+ assertEquals(networkSelectionStatus.isNotRecommended(), copy.isNotRecommended());
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
index 0e503d5e7139..c4d2d32512a2 100644
--- a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -87,6 +87,52 @@ public class WifiEnterpriseConfigTest {
}
@Test
+ public void testSetClientKeyEntryWithNull() {
+ mEnterpriseConfig.setClientKeyEntry(null, null);
+ assertEquals(null, mEnterpriseConfig.getClientCertificateChain());
+ assertEquals(null, mEnterpriseConfig.getClientCertificate());
+ mEnterpriseConfig.setClientKeyEntryWithCertificateChain(null, null);
+ assertEquals(null, mEnterpriseConfig.getClientCertificateChain());
+ assertEquals(null, mEnterpriseConfig.getClientCertificate());
+ }
+
+ @Test
+ public void testSetClientCertificateChain() {
+ PrivateKey clientKey = FakeKeys.RSA_KEY1;
+ X509Certificate cert0 = FakeKeys.CLIENT_CERT;
+ X509Certificate cert1 = FakeKeys.CA_CERT1;
+ X509Certificate[] clientChain = new X509Certificate[] {cert0, cert1};
+ mEnterpriseConfig.setClientKeyEntryWithCertificateChain(clientKey, clientChain);
+ X509Certificate[] result = mEnterpriseConfig.getClientCertificateChain();
+ assertEquals(result.length, 2);
+ assertTrue(result[0] == cert0 && result[1] == cert1);
+ assertTrue(mEnterpriseConfig.getClientCertificate() == cert0);
+ }
+
+ private boolean isClientCertificateChainInvalid(X509Certificate[] clientChain) {
+ boolean exceptionThrown = false;
+ try {
+ PrivateKey clientKey = FakeKeys.RSA_KEY1;
+ mEnterpriseConfig.setClientKeyEntryWithCertificateChain(clientKey, clientChain);
+ } catch (IllegalArgumentException e) {
+ exceptionThrown = true;
+ }
+ return exceptionThrown;
+ }
+
+ @Test
+ public void testSetInvalidClientCertificateChain() {
+ X509Certificate clientCert = FakeKeys.CLIENT_CERT;
+ X509Certificate caCert = FakeKeys.CA_CERT1;
+ assertTrue("Invalid client certificate",
+ isClientCertificateChainInvalid(new X509Certificate[] {caCert, caCert}));
+ assertTrue("Invalid CA certificate",
+ isClientCertificateChainInvalid(new X509Certificate[] {clientCert, clientCert}));
+ assertTrue("Both certificates invalid",
+ isClientCertificateChainInvalid(new X509Certificate[] {caCert, clientCert}));
+ }
+
+ @Test
public void testSaveSingleCaCertificateAlias() {
final String alias = "single_alias 0";
mEnterpriseConfig.setCaCertificateAliases(new String[] {alias});
@@ -237,6 +283,21 @@ public class WifiEnterpriseConfigTest {
assertEquals("\"auth=GTC\"", getSupplicantPhase2Method());
}
+ /** Verfies PEAP/SIM, PEAP/AKA, PEAP/AKA'. */
+ @Test
+ public void peapSimAkaAkaPrime() {
+ mEnterpriseConfig.setEapMethod(Eap.PEAP);
+ mEnterpriseConfig.setPhase2Method(Phase2.SIM);
+ assertEquals("PEAP", getSupplicantEapMethod());
+ assertEquals("\"auth=SIM\"", getSupplicantPhase2Method());
+
+ mEnterpriseConfig.setPhase2Method(Phase2.AKA);
+ assertEquals("\"auth=AKA\"", getSupplicantPhase2Method());
+
+ mEnterpriseConfig.setPhase2Method(Phase2.AKA_PRIME);
+ assertEquals("\"auth=AKA'\"", getSupplicantPhase2Method());
+ }
+
/** Verfies that the copy constructor preseves the inner method information. */
@Test
public void copyConstructor() {
diff --git a/wifi/tests/src/android/net/wifi/WifiSsidTest.java b/wifi/tests/src/android/net/wifi/WifiSsidTest.java
new file mode 100644
index 000000000000..c7bdb7b27cfc
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiSsidTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiSsid}.
+ */
+public class WifiSsidTest {
+
+ private static final byte[] TEST_SSID =
+ new byte[] {'G', 'o', 'o', 'g', 'l', 'e', 'G', 'u', 'e', 's', 't'};
+ /**
+ * Check that createFromByteArray() works.
+ */
+ @Test
+ public void testCreateFromByteArray() {
+ WifiSsid wifiSsid = WifiSsid.createFromByteArray(TEST_SSID);
+ assertTrue(wifiSsid != null);
+ assertEquals(new String(TEST_SSID), wifiSsid.toString());
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index a396d8775ab6..7f68f6f128da 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -100,26 +100,6 @@ public class WifiAwareManagerTest {
*/
/**
- * Validate pass-through of enableUsage() API.
- */
- @Test
- public void testEnableUsage() throws Exception {
- mDut.enableUsage();
-
- verify(mockAwareService).enableUsage();
- }
-
- /**
- * Validate pass-through of disableUsage() API.
- */
- @Test
- public void testDisableUsage() throws Exception {
- mDut.disableUsage();
-
- verify(mockAwareService).disableUsage();
- }
-
- /**
* Validate pass-through of isUsageEnabled() API.
*/
@Test
@@ -566,6 +546,12 @@ public class WifiAwareManagerTest {
collector.checkThat("mMasterPreference", 0,
equalTo(configRequest.mMasterPreference));
collector.checkThat("mSupport5gBand", false, equalTo(configRequest.mSupport5gBand));
+ collector.checkThat("mDiscoveryWindowInterval.length", 2,
+ equalTo(configRequest.mDiscoveryWindowInterval.length));
+ collector.checkThat("mDiscoveryWindowInterval[2.4GHz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
+ equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ]));
+ collector.checkThat("mDiscoveryWindowInterval[5Hz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
+ equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ]));
}
@Test
@@ -574,10 +560,12 @@ public class WifiAwareManagerTest {
final int clusterLow = 5;
final int masterPreference = 55;
final boolean supportBand5g = true;
+ final int dwWindow5GHz = 3;
ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh)
.setClusterLow(clusterLow).setMasterPreference(masterPreference)
.setSupport5gBand(supportBand5g)
+ .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwWindow5GHz)
.build();
collector.checkThat("mClusterHigh", clusterHigh, equalTo(configRequest.mClusterHigh));
@@ -585,6 +573,12 @@ public class WifiAwareManagerTest {
collector.checkThat("mMasterPreference", masterPreference,
equalTo(configRequest.mMasterPreference));
collector.checkThat("mSupport5gBand", supportBand5g, equalTo(configRequest.mSupport5gBand));
+ collector.checkThat("mDiscoveryWindowInterval.length", 2,
+ equalTo(configRequest.mDiscoveryWindowInterval.length));
+ collector.checkThat("mDiscoveryWindowInterval[2.4GHz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
+ equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ]));
+ collector.checkThat("mDiscoveryWindowInterval[5GHz]", dwWindow5GHz,
+ equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ]));
}
@Test(expected = IllegalArgumentException.class)
@@ -633,16 +627,44 @@ public class WifiAwareManagerTest {
new ConfigRequest.Builder().setClusterLow(100).setClusterHigh(5).build();
}
+ @Test(expected = IllegalArgumentException.class)
+ public void testConfigRequestBuilderDwIntervalInvalidBand() {
+ new ConfigRequest.Builder().setDiscoveryWindowInterval(5, 1).build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testConfigRequestBuilderDwIntervalInvalidValueZero() {
+ new ConfigRequest.Builder().setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ,
+ 0).build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testConfigRequestBuilderDwIntervalInvalidValueLarge() {
+ new ConfigRequest.Builder().setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ,
+ 6).build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testConfigRequestBuilderDwIntervalInvalidValueLargeValidate() {
+ ConfigRequest cr = new ConfigRequest.Builder().build();
+ cr.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ] = 6;
+ cr.validate();
+ }
+
@Test
public void testConfigRequestParcel() {
final int clusterHigh = 189;
final int clusterLow = 25;
final int masterPreference = 177;
final boolean supportBand5g = true;
+ final int dwWindow24GHz = 1;
+ final int dwWindow5GHz = 5;
ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh)
.setClusterLow(clusterLow).setMasterPreference(masterPreference)
.setSupport5gBand(supportBand5g)
+ .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ, dwWindow24GHz)
+ .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwWindow5GHz)
.build();
Parcel parcelW = Parcel.obtain();
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java
index 6095929758f0..56bb4375acdd 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java
@@ -21,7 +21,7 @@ import static org.junit.Assert.assertTrue;
import android.net.wifi.FakeKeys;
import android.net.wifi.hotspot2.pps.Credential;
-import android.net.wifi.hotspot2.pps.HomeSP;
+import android.net.wifi.hotspot2.pps.HomeSp;
import android.test.suitebuilder.annotation.SmallTest;
import java.io.BufferedReader;
@@ -33,10 +33,10 @@ import java.util.Arrays;
import org.junit.Test;
/**
- * Unit tests for {@link android.net.wifi.hotspot2.ConfigBuilder}.
+ * Unit tests for {@link android.net.wifi.hotspot2.ConfigParser}.
*/
@SmallTest
-public class ConfigBuilderTest {
+public class ConfigParserTest {
/**
* Hotspot 2.0 Release 1 installation file that contains a Passpoint profile and a
* CA (Certificate Authority) X.509 certificate {@link FakeKeys#CA_CERT0}.
@@ -83,27 +83,33 @@ public class ConfigBuilderTest {
PasspointConfiguration config = new PasspointConfiguration();
// HomeSP configuration.
- config.homeSp = new HomeSP();
- config.homeSp.friendlyName = "Century House";
- config.homeSp.fqdn = "mi6.co.uk";
- config.homeSp.roamingConsortiumOIs = new long[] {0x112233L, 0x445566L};
+ HomeSp homeSp = new HomeSp();
+ homeSp.setFriendlyName("Century House");
+ homeSp.setFqdn("mi6.co.uk");
+ homeSp.setRoamingConsortiumOis(new long[] {0x112233L, 0x445566L});
+ config.setHomeSp(homeSp);
// Credential configuration.
- config.credential = new Credential();
- config.credential.realm = "shaken.stirred.com";
- config.credential.userCredential = new Credential.UserCredential();
- config.credential.userCredential.username = "james";
- config.credential.userCredential.password = "Ym9uZDAwNw==";
- config.credential.userCredential.eapType = 21;
- config.credential.userCredential.nonEapInnerMethod = "MS-CHAP-V2";
- config.credential.certCredential = new Credential.CertificateCredential();
- config.credential.certCredential.certType = "x509v3";
- config.credential.certCredential.certSha256FingerPrint = new byte[32];
- Arrays.fill(config.credential.certCredential.certSha256FingerPrint, (byte)0x1f);
- config.credential.simCredential = new Credential.SimCredential();
- config.credential.simCredential.imsi = "imsi";
- config.credential.simCredential.eapType = 24;
- config.credential.caCertificate = FakeKeys.CA_CERT0;
+ Credential credential = new Credential();
+ credential.setRealm("shaken.stirred.com");
+ Credential.UserCredential userCredential = new Credential.UserCredential();
+ userCredential.setUsername("james");
+ userCredential.setPassword("Ym9uZDAwNw==");
+ userCredential.setEapType(21);
+ userCredential.setNonEapInnerMethod("MS-CHAP-V2");
+ credential.setUserCredential(userCredential);
+ Credential.CertificateCredential certCredential = new Credential.CertificateCredential();
+ certCredential.setCertType("x509v3");
+ byte[] certSha256Fingerprint = new byte[32];
+ Arrays.fill(certSha256Fingerprint, (byte)0x1f);
+ certCredential.setCertSha256Fingerprint(certSha256Fingerprint);
+ credential.setCertCredential(certCredential);
+ Credential.SimCredential simCredential = new Credential.SimCredential();
+ simCredential.setImsi("imsi");
+ simCredential.setEapType(24);
+ credential.setSimCredential(simCredential);
+ credential.setCaCertificate(FakeKeys.CA_CERT0);
+ config.setCredential(credential);
return config;
}
@@ -117,7 +123,7 @@ public class ConfigBuilderTest {
String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT);
PasspointConfiguration expectedConfig = generateConfigurationFromProfile();
PasspointConfiguration actualConfig =
- ConfigBuilder.buildPasspointConfig(
+ ConfigParser.parsePasspointConfig(
"application/x-wifi-config", configStr.getBytes());
assertTrue(actualConfig.equals(expectedConfig));
}
@@ -130,7 +136,7 @@ public class ConfigBuilderTest {
@Test
public void parseConfigFileWithInvalidMimeType() throws Exception {
String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT);
- assertNull(ConfigBuilder.buildPasspointConfig(
+ assertNull(ConfigParser.parsePasspointConfig(
"application/wifi-config", configStr.getBytes()));
}
@@ -142,7 +148,7 @@ public class ConfigBuilderTest {
@Test
public void parseConfigFileWithUnencodedData() throws Exception {
String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_UNENCODED_DATA);
- assertNull(ConfigBuilder.buildPasspointConfig(
+ assertNull(ConfigParser.parsePasspointConfig(
"application/x-wifi-config", configStr.getBytes()));
}
@@ -154,7 +160,7 @@ public class ConfigBuilderTest {
@Test
public void parseConfigFileWithInvalidPart() throws Exception {
String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_INVALID_PART);
- assertNull(ConfigBuilder.buildPasspointConfig(
+ assertNull(ConfigParser.parsePasspointConfig(
"application/x-wifi-config", configStr.getBytes()));
}
@@ -166,7 +172,7 @@ public class ConfigBuilderTest {
@Test
public void parseConfigFileWithMissingBoundary() throws Exception {
String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_MISSING_BOUNDARY);
- assertNull(ConfigBuilder.buildPasspointConfig(
+ assertNull(ConfigParser.parsePasspointConfig(
"application/x-wifi-config", configStr.getBytes()));
}
@@ -179,7 +185,7 @@ public class ConfigBuilderTest {
@Test
public void parseConfigFileWithInvalidContentType() throws Exception {
String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_INVALID_CONTENT_TYPE);
- assertNull(ConfigBuilder.buildPasspointConfig(
+ assertNull(ConfigParser.parsePasspointConfig(
"application/x-wifi-config", configStr.getBytes()));
}
@@ -191,7 +197,7 @@ public class ConfigBuilderTest {
@Test
public void parseConfigFileWithoutPasspointProfile() throws Exception {
String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITHOUT_PROFILE);
- assertNull(ConfigBuilder.buildPasspointConfig(
+ assertNull(ConfigParser.parsePasspointConfig(
"application/x-wifi-config", configStr.getBytes()));
}
} \ No newline at end of file
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index 2350d3201171..7df4fcf56e8a 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -21,28 +21,40 @@ import static org.junit.Assert.assertTrue;
import android.net.wifi.EAPConstants;
import android.net.wifi.hotspot2.pps.Credential;
-import android.net.wifi.hotspot2.pps.HomeSP;
+import android.net.wifi.hotspot2.pps.HomeSp;
+import android.net.wifi.hotspot2.pps.Policy;
+import android.net.wifi.hotspot2.pps.UpdateParameter;
import android.os.Parcel;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Base64;
import org.junit.Test;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
/**
* Unit tests for {@link android.net.wifi.hotspot2.PasspointConfiguration}.
*/
@SmallTest
public class PasspointConfigurationTest {
+ private static final int MAX_URL_BYTES = 1023;
+ private static final int CERTIFICATE_FINGERPRINT_BYTES = 32;
/**
* Utility function for creating a {@link android.net.wifi.hotspot2.pps.HomeSP}.
*
* @return {@link android.net.wifi.hotspot2.pps.HomeSP}
*/
- private static HomeSP createHomeSp() {
- HomeSP homeSp = new HomeSP();
- homeSp.fqdn = "fqdn";
- homeSp.friendlyName = "friendly name";
- homeSp.roamingConsortiumOIs = new long[] {0x55, 0x66};
+ private static HomeSp createHomeSp() {
+ HomeSp homeSp = new HomeSp();
+ homeSp.setFqdn("fqdn");
+ homeSp.setFriendlyName("friendly name");
+ homeSp.setRoamingConsortiumOis(new long[] {0x55, 0x66});
return homeSp;
}
@@ -53,19 +65,110 @@ public class PasspointConfigurationTest {
*/
private static Credential createCredential() {
Credential cred = new Credential();
- cred.realm = "realm";
- cred.userCredential = null;
- cred.certCredential = null;
- cred.simCredential = new Credential.SimCredential();
- cred.simCredential.imsi = "1234*";
- cred.simCredential.eapType = EAPConstants.EAP_SIM;
- cred.caCertificate = null;
- cred.clientCertificateChain = null;
- cred.clientPrivateKey = null;
+ cred.setRealm("realm");
+ cred.setUserCredential(null);
+ cred.setCertCredential(null);
+ cred.setSimCredential(new Credential.SimCredential());
+ cred.getSimCredential().setImsi("1234*");
+ cred.getSimCredential().setEapType(EAPConstants.EAP_SIM);
+ cred.setCaCertificate(null);
+ cred.setClientCertificateChain(null);
+ cred.setClientPrivateKey(null);
return cred;
}
/**
+ * Helper function for creating a {@link Policy} for testing.
+ *
+ * @return {@link Policy}
+ */
+ private static Policy createPolicy() {
+ Policy policy = new Policy();
+ policy.setMinHomeDownlinkBandwidth(123);
+ policy.setMinHomeUplinkBandwidth(345);
+ policy.setMinRoamingDownlinkBandwidth(567);
+ policy.setMinRoamingUplinkBandwidth(789);
+ policy.setMaximumBssLoadValue(12);
+ policy.setExcludedSsidList(new String[] {"ssid1", "ssid2"});
+ HashMap<Integer, String> requiredProtoPortMap = new HashMap<>();
+ requiredProtoPortMap.put(12, "23,342,123");
+ requiredProtoPortMap.put(23, "789,372,1235");
+ policy.setRequiredProtoPortMap(requiredProtoPortMap);
+
+ List<Policy.RoamingPartner> preferredRoamingPartnerList = new ArrayList<>();
+ Policy.RoamingPartner partner1 = new Policy.RoamingPartner();
+ partner1.setFqdn("partner1.com");
+ partner1.setFqdnExactMatch(true);
+ partner1.setPriority(12);
+ partner1.setCountries("us,jp");
+ Policy.RoamingPartner partner2 = new Policy.RoamingPartner();
+ partner2.setFqdn("partner2.com");
+ partner2.setFqdnExactMatch(false);
+ partner2.setPriority(42);
+ partner2.setCountries("ca,fr");
+ preferredRoamingPartnerList.add(partner1);
+ preferredRoamingPartnerList.add(partner2);
+ policy.setPreferredRoamingPartnerList(preferredRoamingPartnerList);
+
+ UpdateParameter policyUpdate = new UpdateParameter();
+ policyUpdate.setUpdateIntervalInMinutes(1712);
+ policyUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM);
+ policyUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP);
+ policyUpdate.setServerUri("policy.update.com");
+ policyUpdate.setUsername("username");
+ policyUpdate.setBase64EncodedPassword(
+ Base64.encodeToString("password".getBytes(), Base64.DEFAULT));
+ policyUpdate.setTrustRootCertUrl("trust.cert.com");
+ policyUpdate.setTrustRootCertSha256Fingerprint(
+ new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+ policy.setPolicyUpdate(policyUpdate);
+
+ return policy;
+ }
+
+ private static UpdateParameter createSubscriptionUpdate() {
+ UpdateParameter subUpdate = new UpdateParameter();
+ subUpdate.setUpdateIntervalInMinutes(9021);
+ subUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_SSP);
+ subUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_ROAMING_PARTNER);
+ subUpdate.setServerUri("subscription.update.com");
+ subUpdate.setUsername("subUsername");
+ subUpdate.setBase64EncodedPassword(
+ Base64.encodeToString("subPassword".getBytes(), Base64.DEFAULT));
+ subUpdate.setTrustRootCertUrl("subscription.trust.cert.com");
+ subUpdate.setTrustRootCertSha256Fingerprint(new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+ return subUpdate;
+ }
+ /**
+ * Helper function for creating a {@link PasspointConfiguration} for testing.
+ *
+ * @return {@link PasspointConfiguration}
+ */
+ private static PasspointConfiguration createConfig() {
+ PasspointConfiguration config = new PasspointConfiguration();
+ config.setHomeSp(createHomeSp());
+ config.setCredential(createCredential());
+ config.setPolicy(createPolicy());
+ config.setSubscriptionUpdate(createSubscriptionUpdate());
+ Map<String, byte[]> trustRootCertList = new HashMap<>();
+ trustRootCertList.put("trustRoot.cert1.com",
+ new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+ trustRootCertList.put("trustRoot.cert2.com",
+ new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+ config.setTrustRootCertList(trustRootCertList);
+ config.setUpdateIdentifier(1);
+ config.setCredentialPriority(120);
+ config.setSubscriptionCreationTimeInMs(231200);
+ config.setSubscriptionExpirationTimeInMs(2134232);
+ config.setSubscriptionType("Gold");
+ config.setUsageLimitUsageTimePeriodInMinutes(3600);
+ config.setUsageLimitStartTimeInMs(124214213);
+ config.setUsageLimitDataLimit(14121);
+ config.setUsageLimitTimeLimitInMinutes(78912);
+ return config;
+ }
+
+ /**
* Verify parcel write and read consistency for the given configuration.
*
* @param writeConfig The configuration to verify
@@ -92,39 +195,73 @@ public class PasspointConfigurationTest {
}
/**
- * Verify parcel read/write for a configuration that contained both HomeSP and Credential.
+ * Verify parcel read/write for a configuration that contained the full configuration.
*
* @throws Exception
*/
@Test
- public void verifyParcelWithHomeSPAndCredential() throws Exception {
- PasspointConfiguration config = new PasspointConfiguration();
- config.homeSp = createHomeSp();
- config.credential = createCredential();
+ public void verifyParcelWithFullConfiguration() throws Exception {
+ verifyParcel(createConfig());
+ }
+
+ /**
+ * Verify parcel read/write for a configuration that doesn't contain HomeSP.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithoutHomeSP() throws Exception {
+ PasspointConfiguration config = createConfig();
+ config.setHomeSp(null);
verifyParcel(config);
}
/**
- * Verify parcel read/write for a configuration that contained only HomeSP.
+ * Verify parcel read/write for a configuration that doesn't contain Credential.
*
* @throws Exception
*/
@Test
- public void verifyParcelWithHomeSPOnly() throws Exception {
- PasspointConfiguration config = new PasspointConfiguration();
- config.homeSp = createHomeSp();
+ public void verifyParcelWithoutCredential() throws Exception {
+ PasspointConfiguration config = createConfig();
+ config.setCredential(null);
verifyParcel(config);
}
/**
- * Verify parcel read/write for a configuration that contained only Credential.
+ * Verify parcel read/write for a configuration that doesn't contain Policy.
*
* @throws Exception
*/
@Test
- public void verifyParcelWithCredentialOnly() throws Exception {
- PasspointConfiguration config = new PasspointConfiguration();
- config.credential = createCredential();
+ public void verifyParcelWithoutPolicy() throws Exception {
+ PasspointConfiguration config = createConfig();
+ config.setPolicy(null);
+ verifyParcel(config);
+ }
+
+ /**
+ * Verify parcel read/write for a configuration that doesn't contain subscription update.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithoutSubscriptionUpdate() throws Exception {
+ PasspointConfiguration config = createConfig();
+ config.setSubscriptionUpdate(null);
+ verifyParcel(config);
+ }
+
+ /**
+ * Verify parcel read/write for a configuration that doesn't contain trust root certificate
+ * list.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithoutTrustRootCertList() throws Exception {
+ PasspointConfiguration config = createConfig();
+ config.setTrustRootCertList(null);
verifyParcel(config);
}
@@ -140,43 +277,114 @@ public class PasspointConfigurationTest {
}
/**
+ * Verify that a configuration contained all fields is valid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateFullConfig() throws Exception {
+ PasspointConfiguration config = createConfig();
+ assertTrue(config.validate());
+ }
+
+ /**
* Verify that a configuration without Credential is invalid.
*
* @throws Exception
*/
@Test
public void validateConfigWithoutCredential() throws Exception {
- PasspointConfiguration config = new PasspointConfiguration();
- config.homeSp = createHomeSp();
+ PasspointConfiguration config = createConfig();
+ config.setCredential(null);
assertFalse(config.validate());
}
/**
- * Verify that a a configuration without HomeSP is invalid.
+ * Verify that a configuration without HomeSP is invalid.
*
* @throws Exception
*/
@Test
public void validateConfigWithoutHomeSp() throws Exception {
- PasspointConfiguration config = new PasspointConfiguration();
- config.credential = createCredential();
+ PasspointConfiguration config = createConfig();
+ config.setHomeSp(null);
assertFalse(config.validate());
}
/**
- * Verify a valid configuration.
+ * Verify that a configuration without Policy is valid, since Policy configurations
+ * are optional (applied for Hotspot 2.0 Release only).
*
* @throws Exception
*/
@Test
- public void validateValidConfig() throws Exception {
- PasspointConfiguration config = new PasspointConfiguration();
- config.homeSp = createHomeSp();
- config.credential = createCredential();
+ public void validateConfigWithoutPolicy() throws Exception {
+ PasspointConfiguration config = createConfig();
+ config.setPolicy(null);
assertTrue(config.validate());
}
/**
+ * Verify that a configuration without subscription update is valid, since subscription
+ * update configurations are optional (applied for Hotspot 2.0 Release only).
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateConfigWithoutSubscriptionUpdate() throws Exception {
+ PasspointConfiguration config = createConfig();
+ config.setSubscriptionUpdate(null);
+ assertTrue(config.validate());
+ }
+
+ /**
+ * Verify that a configuration with a trust root certificate URL exceeding the max size
+ * is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateConfigWithInvalidTrustRootCertUrl() throws Exception {
+ PasspointConfiguration config = createConfig();
+ byte[] rawUrlBytes = new byte[MAX_URL_BYTES + 1];
+ Map<String, byte[]> trustRootCertList = new HashMap<>();
+ Arrays.fill(rawUrlBytes, (byte) 'a');
+ trustRootCertList.put(new String(rawUrlBytes, StandardCharsets.UTF_8),
+ new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+ config.setTrustRootCertList(trustRootCertList);
+ assertFalse(config.validate());
+
+ trustRootCertList = new HashMap<>();
+ trustRootCertList.put(null, new byte[CERTIFICATE_FINGERPRINT_BYTES]);
+ config.setTrustRootCertList(trustRootCertList);
+ assertFalse(config.validate());
+ }
+
+ /**
+ * Verify that a configuration with an invalid trust root certificate fingerprint is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateConfigWithInvalidTrustRootCertFingerprint() throws Exception {
+ PasspointConfiguration config = createConfig();
+ Map<String, byte[]> trustRootCertList = new HashMap<>();
+ trustRootCertList.put("test.cert.com", new byte[CERTIFICATE_FINGERPRINT_BYTES + 1]);
+ config.setTrustRootCertList(trustRootCertList);
+ assertFalse(config.validate());
+
+ trustRootCertList = new HashMap<>();
+ trustRootCertList.put("test.cert.com", new byte[CERTIFICATE_FINGERPRINT_BYTES - 1]);
+ config.setTrustRootCertList(trustRootCertList);
+ assertFalse(config.validate());
+
+ trustRootCertList = new HashMap<>();
+ trustRootCertList.put("test.cert.com", null);
+ config.setTrustRootCertList(trustRootCertList);
+ assertFalse(config.validate());
+ }
+
+ /**
* Verify that copy constructor works when pass in a null source.
*
* @throws Exception
@@ -195,9 +403,7 @@ public class PasspointConfigurationTest {
*/
@Test
public void validateCopyConstructorWithValidSource() throws Exception {
- PasspointConfiguration sourceConfig = new PasspointConfiguration();
- sourceConfig.homeSp = createHomeSp();
- sourceConfig.credential = createCredential();
+ PasspointConfiguration sourceConfig = createConfig();
PasspointConfiguration copyConfig = new PasspointConfiguration(sourceConfig);
assertTrue(copyConfig.equals(sourceConfig));
}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java
deleted file mode 100644
index 10b02677a15b..000000000000
--- a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.hotspot2.omadm;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.net.wifi.hotspot2.omadm.PPSMOParser;
-import android.net.wifi.hotspot2.PasspointConfiguration;
-import android.net.wifi.hotspot2.pps.Credential;
-import android.net.wifi.hotspot2.pps.HomeSP;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.junit.Test;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.Arrays;
-
-/**
- * Unit tests for {@link android.net.wifi.hotspot2.omadm.PPSMOParser}.
- */
-@SmallTest
-public class PPSMOParserTest {
- private static final String VALID_PPS_MO_XML_FILE = "assets/pps/PerProviderSubscription.xml";
- private static final String PPS_MO_XML_FILE_DUPLICATE_HOMESP =
- "assets/pps/PerProviderSubscription_DuplicateHomeSP.xml";
- private static final String PPS_MO_XML_FILE_DUPLICATE_VALUE =
- "assets/pps/PerProviderSubscription_DuplicateValue.xml";
- private static final String PPS_MO_XML_FILE_MISSING_VALUE =
- "assets/pps/PerProviderSubscription_MissingValue.xml";
- private static final String PPS_MO_XML_FILE_MISSING_NAME =
- "assets/pps/PerProviderSubscription_MissingName.xml";
- private static final String PPS_MO_XML_FILE_INVALID_NODE =
- "assets/pps/PerProviderSubscription_InvalidNode.xml";
- private static final String PPS_MO_XML_FILE_INVALID_NAME =
- "assets/pps/PerProviderSubscription_InvalidName.xml";
-
- /**
- * Read the content of the given resource file into a String.
- *
- * @param filename String name of the file
- * @return String
- * @throws IOException
- */
- private String loadResourceFile(String filename) throws IOException {
- InputStream in = getClass().getClassLoader().getResourceAsStream(filename);
- BufferedReader reader = new BufferedReader(new InputStreamReader(in));
- StringBuilder builder = new StringBuilder();
- String line;
- while ((line = reader.readLine()) != null) {
- builder.append(line).append("\n");
- }
-
- return builder.toString();
- }
-
- /**
- * Generate a {@link PasspointConfiguration} that matches the configuration specified in the
- * XML file {@link #VALID_PPS_MO_XML_FILE}.
- *
- * @return {@link PasspointConfiguration}
- */
- private PasspointConfiguration generateConfigurationFromPPSMOTree() {
- PasspointConfiguration config = new PasspointConfiguration();
-
- // HomeSP configuration.
- config.homeSp = new HomeSP();
- config.homeSp.friendlyName = "Century House";
- config.homeSp.fqdn = "mi6.co.uk";
- config.homeSp.roamingConsortiumOIs = new long[] {0x112233L, 0x445566L};
-
- // Credential configuration.
- config.credential = new Credential();
- config.credential.realm = "shaken.stirred.com";
- config.credential.userCredential = new Credential.UserCredential();
- config.credential.userCredential.username = "james";
- config.credential.userCredential.password = "Ym9uZDAwNw==";
- config.credential.userCredential.eapType = 21;
- config.credential.userCredential.nonEapInnerMethod = "MS-CHAP-V2";
- config.credential.certCredential = new Credential.CertificateCredential();
- config.credential.certCredential.certType = "x509v3";
- config.credential.certCredential.certSha256FingerPrint = new byte[32];
- Arrays.fill(config.credential.certCredential.certSha256FingerPrint, (byte)0x1f);
- config.credential.simCredential = new Credential.SimCredential();
- config.credential.simCredential.imsi = "imsi";
- config.credential.simCredential.eapType = 24;
- return config;
- }
-
- /**
- * Parse and verify all supported fields under PPS MO tree (currently only fields under
- * HomeSP and Credential subtree).
- *
- * @throws Exception
- */
- @Test
- public void parseValidPPSMOTree() throws Exception {
- String ppsMoTree = loadResourceFile(VALID_PPS_MO_XML_FILE);
- PasspointConfiguration expectedConfig = generateConfigurationFromPPSMOTree();
- PasspointConfiguration actualConfig = PPSMOParser.parseMOText(ppsMoTree);
- assertTrue(actualConfig.equals(expectedConfig));
- }
-
- @Test
- public void parseNullPPSMOTree() throws Exception {
- assertEquals(null, PPSMOParser.parseMOText(null));
- }
-
- @Test
- public void parseEmptyPPSMOTree() throws Exception {
- assertEquals(null, PPSMOParser.parseMOText(new String()));
- }
-
- @Test
- public void parsePPSMOTreeWithDuplicateHomeSP() throws Exception {
- assertEquals(null, PPSMOParser.parseMOText(
- loadResourceFile(PPS_MO_XML_FILE_DUPLICATE_HOMESP)));
- }
-
- @Test
- public void parsePPSMOTreeWithDuplicateValue() throws Exception {
- assertEquals(null, PPSMOParser.parseMOText(
- loadResourceFile(PPS_MO_XML_FILE_DUPLICATE_VALUE)));
- }
-
- @Test
- public void parsePPSMOTreeWithMissingValue() throws Exception {
- assertEquals(null, PPSMOParser.parseMOText(
- loadResourceFile(PPS_MO_XML_FILE_MISSING_VALUE)));
- }
-
- @Test
- public void parsePPSMOTreeWithMissingName() throws Exception {
- assertEquals(null, PPSMOParser.parseMOText(
- loadResourceFile(PPS_MO_XML_FILE_MISSING_NAME)));
- }
-
- @Test
- public void parsePPSMOTreeWithInvalidNode() throws Exception {
- assertEquals(null, PPSMOParser.parseMOText(
- loadResourceFile(PPS_MO_XML_FILE_INVALID_NODE)));
- }
-
- @Test
- public void parsePPSMOTreeWithInvalidName() throws Exception {
- assertEquals(null, PPSMOParser.parseMOText(
- loadResourceFile(PPS_MO_XML_FILE_INVALID_NAME)));
- }
-}
-
-
-
-
-
-
-
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java
new file mode 100644
index 000000000000..7cd72f03dd1b
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.hotspot2.omadm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.net.wifi.hotspot2.omadm.PpsMoParser;
+import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.pps.Credential;
+import android.net.wifi.hotspot2.pps.HomeSp;
+import android.net.wifi.hotspot2.pps.Policy;
+import android.net.wifi.hotspot2.pps.UpdateParameter;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
+
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Unit tests for {@link android.net.wifi.hotspot2.omadm.PpsMoParser}.
+ */
+@SmallTest
+public class PpsMoParserTest {
+ private static final String VALID_PPS_MO_XML_FILE = "assets/pps/PerProviderSubscription.xml";
+ private static final String PPS_MO_XML_FILE_DUPLICATE_HOMESP =
+ "assets/pps/PerProviderSubscription_DuplicateHomeSP.xml";
+ private static final String PPS_MO_XML_FILE_DUPLICATE_VALUE =
+ "assets/pps/PerProviderSubscription_DuplicateValue.xml";
+ private static final String PPS_MO_XML_FILE_MISSING_VALUE =
+ "assets/pps/PerProviderSubscription_MissingValue.xml";
+ private static final String PPS_MO_XML_FILE_MISSING_NAME =
+ "assets/pps/PerProviderSubscription_MissingName.xml";
+ private static final String PPS_MO_XML_FILE_INVALID_NODE =
+ "assets/pps/PerProviderSubscription_InvalidNode.xml";
+ private static final String PPS_MO_XML_FILE_INVALID_NAME =
+ "assets/pps/PerProviderSubscription_InvalidName.xml";
+
+ /**
+ * Read the content of the given resource file into a String.
+ *
+ * @param filename String name of the file
+ * @return String
+ * @throws IOException
+ */
+ private String loadResourceFile(String filename) throws IOException {
+ InputStream in = getClass().getClassLoader().getResourceAsStream(filename);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+ StringBuilder builder = new StringBuilder();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ builder.append(line).append("\n");
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * Generate a {@link PasspointConfiguration} that matches the configuration specified in the
+ * XML file {@link #VALID_PPS_MO_XML_FILE}.
+ *
+ * @return {@link PasspointConfiguration}
+ */
+ private PasspointConfiguration generateConfigurationFromPPSMOTree() throws Exception {
+ DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+ byte[] certFingerprint = new byte[32];
+ Arrays.fill(certFingerprint, (byte) 0x1f);
+
+ PasspointConfiguration config = new PasspointConfiguration();
+ config.setUpdateIdentifier(12);
+ config.setCredentialPriority(99);
+
+ // AAA Server trust root.
+ Map<String, byte[]> trustRootCertList = new HashMap<>();
+ trustRootCertList.put("server1.trust.root.com", certFingerprint);
+ config.setTrustRootCertList(trustRootCertList);
+
+ // Subscription update.
+ UpdateParameter subscriptionUpdate = new UpdateParameter();
+ subscriptionUpdate.setUpdateIntervalInMinutes(120);
+ subscriptionUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_SSP);
+ subscriptionUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_ROAMING_PARTNER);
+ subscriptionUpdate.setServerUri("subscription.update.com");
+ subscriptionUpdate.setUsername("subscriptionUser");
+ subscriptionUpdate.setBase64EncodedPassword("subscriptionPass");
+ subscriptionUpdate.setTrustRootCertUrl("subscription.update.cert.com");
+ subscriptionUpdate.setTrustRootCertSha256Fingerprint(certFingerprint);
+ config.setSubscriptionUpdate(subscriptionUpdate);
+
+ // Subscription parameters.
+ config.setSubscriptionCreationTimeInMs(format.parse("2016-02-01T10:00:00Z").getTime());
+ config.setSubscriptionExpirationTimeInMs(format.parse("2016-03-01T10:00:00Z").getTime());
+ config.setSubscriptionType("Gold");
+ config.setUsageLimitDataLimit(921890);
+ config.setUsageLimitStartTimeInMs(format.parse("2016-12-01T10:00:00Z").getTime());
+ config.setUsageLimitTimeLimitInMinutes(120);
+ config.setUsageLimitUsageTimePeriodInMinutes(99910);
+
+ // HomeSP configuration.
+ HomeSp homeSp = new HomeSp();
+ homeSp.setFriendlyName("Century House");
+ homeSp.setFqdn("mi6.co.uk");
+ homeSp.setRoamingConsortiumOis(new long[] {0x112233L, 0x445566L});
+ homeSp.setIconUrl("icon.test.com");
+ Map<String, Long> homeNetworkIds = new HashMap<>();
+ homeNetworkIds.put("TestSSID", 0x12345678L);
+ homeNetworkIds.put("NullHESSID", null);
+ homeSp.setHomeNetworkIds(homeNetworkIds);
+ homeSp.setMatchAllOis(new long[] {0x11223344});
+ homeSp.setMatchAnyOis(new long[] {0x55667788});
+ homeSp.setOtherHomePartners(new String[] {"other.fqdn.com"});
+ config.setHomeSp(homeSp);
+
+ // Credential configuration.
+ Credential credential = new Credential();
+ credential.setCreationTimeInMs(format.parse("2016-01-01T10:00:00Z").getTime());
+ credential.setExpirationTimeInMs(format.parse("2016-02-01T10:00:00Z").getTime());
+ credential.setRealm("shaken.stirred.com");
+ credential.setCheckAaaServerCertStatus(true);
+ Credential.UserCredential userCredential = new Credential.UserCredential();
+ userCredential.setUsername("james");
+ userCredential.setPassword("Ym9uZDAwNw==");
+ userCredential.setMachineManaged(true);
+ userCredential.setSoftTokenApp("TestApp");
+ userCredential.setAbleToShare(true);
+ userCredential.setEapType(21);
+ userCredential.setNonEapInnerMethod("MS-CHAP-V2");
+ credential.setUserCredential(userCredential);
+ Credential.CertificateCredential certCredential = new Credential.CertificateCredential();
+ certCredential.setCertType("x509v3");
+ certCredential.setCertSha256Fingerprint(certFingerprint);
+ credential.setCertCredential(certCredential);
+ Credential.SimCredential simCredential = new Credential.SimCredential();
+ simCredential.setImsi("imsi");
+ simCredential.setEapType(24);
+ credential.setSimCredential(simCredential);
+ config.setCredential(credential);
+
+ // Policy configuration.
+ Policy policy = new Policy();
+ List<Policy.RoamingPartner> preferredRoamingPartnerList = new ArrayList<>();
+ Policy.RoamingPartner partner1 = new Policy.RoamingPartner();
+ partner1.setFqdn("test1.fqdn.com");
+ partner1.setFqdnExactMatch(true);
+ partner1.setPriority(127);
+ partner1.setCountries("us,fr");
+ Policy.RoamingPartner partner2 = new Policy.RoamingPartner();
+ partner2.setFqdn("test2.fqdn.com");
+ partner2.setFqdnExactMatch(false);
+ partner2.setPriority(200);
+ partner2.setCountries("*");
+ preferredRoamingPartnerList.add(partner1);
+ preferredRoamingPartnerList.add(partner2);
+ policy.setPreferredRoamingPartnerList(preferredRoamingPartnerList);
+ policy.setMinHomeDownlinkBandwidth(23412);
+ policy.setMinHomeUplinkBandwidth(9823);
+ policy.setMinRoamingDownlinkBandwidth(9271);
+ policy.setMinRoamingUplinkBandwidth(2315);
+ policy.setExcludedSsidList(new String[] {"excludeSSID"});
+ Map<Integer, String> requiredProtoPortMap = new HashMap<>();
+ requiredProtoPortMap.put(12, "34,92,234");
+ policy.setRequiredProtoPortMap(requiredProtoPortMap);
+ policy.setMaximumBssLoadValue(23);
+ UpdateParameter policyUpdate = new UpdateParameter();
+ policyUpdate.setUpdateIntervalInMinutes(120);
+ policyUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM);
+ policyUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP);
+ policyUpdate.setServerUri("policy.update.com");
+ policyUpdate.setUsername("updateUser");
+ policyUpdate.setBase64EncodedPassword("updatePass");
+ policyUpdate.setTrustRootCertUrl("update.cert.com");
+ policyUpdate.setTrustRootCertSha256Fingerprint(certFingerprint);
+ policy.setPolicyUpdate(policyUpdate);
+ config.setPolicy(policy);
+ return config;
+ }
+
+ /**
+ * Parse and verify all supported fields under PPS MO tree.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseValidPPSMOTree() throws Exception {
+ String ppsMoTree = loadResourceFile(VALID_PPS_MO_XML_FILE);
+ PasspointConfiguration expectedConfig = generateConfigurationFromPPSMOTree();
+ PasspointConfiguration actualConfig = PpsMoParser.parseMoText(ppsMoTree);
+ assertTrue(actualConfig.equals(expectedConfig));
+ }
+
+ @Test
+ public void parseNullPPSMOTree() throws Exception {
+ assertEquals(null, PpsMoParser.parseMoText(null));
+ }
+
+ @Test
+ public void parseEmptyPPSMOTree() throws Exception {
+ assertEquals(null, PpsMoParser.parseMoText(new String()));
+ }
+
+ @Test
+ public void parsePPSMOTreeWithDuplicateHomeSP() throws Exception {
+ assertEquals(null, PpsMoParser.parseMoText(
+ loadResourceFile(PPS_MO_XML_FILE_DUPLICATE_HOMESP)));
+ }
+
+ @Test
+ public void parsePPSMOTreeWithDuplicateValue() throws Exception {
+ assertEquals(null, PpsMoParser.parseMoText(
+ loadResourceFile(PPS_MO_XML_FILE_DUPLICATE_VALUE)));
+ }
+
+ @Test
+ public void parsePPSMOTreeWithMissingValue() throws Exception {
+ assertEquals(null, PpsMoParser.parseMoText(
+ loadResourceFile(PPS_MO_XML_FILE_MISSING_VALUE)));
+ }
+
+ @Test
+ public void parsePPSMOTreeWithMissingName() throws Exception {
+ assertEquals(null, PpsMoParser.parseMoText(
+ loadResourceFile(PPS_MO_XML_FILE_MISSING_NAME)));
+ }
+
+ @Test
+ public void parsePPSMOTreeWithInvalidNode() throws Exception {
+ assertEquals(null, PpsMoParser.parseMoText(
+ loadResourceFile(PPS_MO_XML_FILE_INVALID_NODE)));
+ }
+
+ @Test
+ public void parsePPSMOTreeWithInvalidName() throws Exception {
+ assertEquals(null, PpsMoParser.parseMoText(
+ loadResourceFile(PPS_MO_XML_FILE_INVALID_NAME)));
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
index 9c8b749e1c93..c7ade002c826 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
@@ -23,10 +23,11 @@ import android.net.wifi.EAPConstants;
import android.net.wifi.FakeKeys;
import android.os.Parcel;
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
@@ -37,6 +38,17 @@ import org.junit.Test;
*/
@SmallTest
public class CredentialTest {
+ /**
+ * Helper function for generating Credential for testing.
+ *
+ * @param userCred Instance of UserCredential
+ * @param certCred Instance of CertificateCredential
+ * @param simCred Instance of SimCredential
+ * @param caCert CA certificate
+ * @param clientCertificateChain Chain of client certificates
+ * @param clientPrivateKey Client private key
+ * @return {@link Credential}
+ */
private static Credential createCredential(Credential.UserCredential userCred,
Credential.CertificateCredential certCred,
Credential.SimCredential simCred,
@@ -44,39 +56,61 @@ public class CredentialTest {
X509Certificate[] clientCertificateChain,
PrivateKey clientPrivateKey) {
Credential cred = new Credential();
- cred.realm = "realm";
- cred.userCredential = userCred;
- cred.certCredential = certCred;
- cred.simCredential = simCred;
- cred.caCertificate = caCert;
- cred.clientCertificateChain = clientCertificateChain;
- cred.clientPrivateKey = clientPrivateKey;
+ cred.setCreationTimeInMs(123455L);
+ cred.setExpirationTimeInMs(2310093L);
+ cred.setRealm("realm");
+ cred.setCheckAaaServerCertStatus(true);
+ cred.setUserCredential(userCred);
+ cred.setCertCredential(certCred);
+ cred.setSimCredential(simCred);
+ cred.setCaCertificate(caCert);
+ cred.setClientCertificateChain(clientCertificateChain);
+ cred.setClientPrivateKey(clientPrivateKey);
return cred;
}
- private static Credential createCredentialWithCertificateCredential() {
+ /**
+ * Helper function for generating certificate credential for testing.
+ *
+ * @return {@link Credential}
+ */
+ private static Credential createCredentialWithCertificateCredential()
+ throws NoSuchAlgorithmException, CertificateEncodingException {
Credential.CertificateCredential certCred = new Credential.CertificateCredential();
- certCred.certType = "x509v3";
- certCred.certSha256FingerPrint = new byte[32];
+ certCred.setCertType("x509v3");
+ certCred.setCertSha256Fingerprint(
+ MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded()));
return createCredential(null, certCred, null, FakeKeys.CA_CERT0,
new X509Certificate[] {FakeKeys.CLIENT_CERT}, FakeKeys.RSA_KEY1);
}
+ /**
+ * Helper function for generating SIM credential for testing.
+ *
+ * @return {@link Credential}
+ */
private static Credential createCredentialWithSimCredential() {
Credential.SimCredential simCred = new Credential.SimCredential();
- simCred.imsi = "1234*";
- simCred.eapType = EAPConstants.EAP_SIM;
+ simCred.setImsi("1234*");
+ simCred.setEapType(EAPConstants.EAP_SIM);
return createCredential(null, null, simCred, null, null, null);
}
+ /**
+ * Helper function for generating user credential for testing.
+ *
+ * @return {@link Credential}
+ */
private static Credential createCredentialWithUserCredential() {
Credential.UserCredential userCred = new Credential.UserCredential();
- userCred.username = "username";
- userCred.password = "password";
- userCred.eapType = EAPConstants.EAP_TTLS;
- userCred.nonEapInnerMethod = "MS-CHAP";
- return createCredential(userCred, null, null, FakeKeys.CA_CERT0,
- new X509Certificate[] {FakeKeys.CLIENT_CERT}, FakeKeys.RSA_KEY1);
+ userCred.setUsername("username");
+ userCred.setPassword("password");
+ userCred.setMachineManaged(true);
+ userCred.setAbleToShare(true);
+ userCred.setSoftTokenApp("TestApp");
+ userCred.setEapType(EAPConstants.EAP_TTLS);
+ userCred.setNonEapInnerMethod("MS-CHAP");
+ return createCredential(userCred, null, null, FakeKeys.CA_CERT0, null, null);
}
private static void verifyParcel(Credential writeCred) {
@@ -134,14 +168,7 @@ public class CredentialTest {
*/
@Test
public void validateUserCredential() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- cred.userCredential = new Credential.UserCredential();
- cred.userCredential.username = "username";
- cred.userCredential.password = "password";
- cred.userCredential.eapType = EAPConstants.EAP_TTLS;
- cred.userCredential.nonEapInnerMethod = "MS-CHAP";
- cred.caCertificate = FakeKeys.CA_CERT0;
+ Credential cred = createCredentialWithUserCredential();
assertTrue(cred.validate());
}
@@ -152,13 +179,8 @@ public class CredentialTest {
*/
@Test
public void validateUserCredentialWithoutCaCert() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- cred.userCredential = new Credential.UserCredential();
- cred.userCredential.username = "username";
- cred.userCredential.password = "password";
- cred.userCredential.eapType = EAPConstants.EAP_TTLS;
- cred.userCredential.nonEapInnerMethod = "MS-CHAP";
+ Credential cred = createCredentialWithUserCredential();
+ cred.setCaCertificate(null);
assertFalse(cred.validate());
}
@@ -169,14 +191,8 @@ public class CredentialTest {
*/
@Test
public void validateUserCredentialWithEapTls() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- cred.userCredential = new Credential.UserCredential();
- cred.userCredential.username = "username";
- cred.userCredential.password = "password";
- cred.userCredential.eapType = EAPConstants.EAP_TLS;
- cred.userCredential.nonEapInnerMethod = "MS-CHAP";
- cred.caCertificate = FakeKeys.CA_CERT0;
+ Credential cred = createCredentialWithUserCredential();
+ cred.getUserCredential().setEapType(EAPConstants.EAP_TLS);
assertFalse(cred.validate());
}
@@ -188,13 +204,8 @@ public class CredentialTest {
*/
@Test
public void validateUserCredentialWithoutRealm() throws Exception {
- Credential cred = new Credential();
- cred.userCredential = new Credential.UserCredential();
- cred.userCredential.username = "username";
- cred.userCredential.password = "password";
- cred.userCredential.eapType = EAPConstants.EAP_TTLS;
- cred.userCredential.nonEapInnerMethod = "MS-CHAP";
- cred.caCertificate = FakeKeys.CA_CERT0;
+ Credential cred = createCredentialWithUserCredential();
+ cred.setRealm(null);
assertFalse(cred.validate());
}
@@ -205,13 +216,8 @@ public class CredentialTest {
*/
@Test
public void validateUserCredentialWithoutUsername() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- cred.userCredential = new Credential.UserCredential();
- cred.userCredential.password = "password";
- cred.userCredential.eapType = EAPConstants.EAP_TTLS;
- cred.userCredential.nonEapInnerMethod = "MS-CHAP";
- cred.caCertificate = FakeKeys.CA_CERT0;
+ Credential cred = createCredentialWithUserCredential();
+ cred.getUserCredential().setUsername(null);
assertFalse(cred.validate());
}
@@ -222,13 +228,8 @@ public class CredentialTest {
*/
@Test
public void validateUserCredentialWithoutPassword() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- cred.userCredential = new Credential.UserCredential();
- cred.userCredential.username = "username";
- cred.userCredential.eapType = EAPConstants.EAP_TTLS;
- cred.userCredential.nonEapInnerMethod = "MS-CHAP";
- cred.caCertificate = FakeKeys.CA_CERT0;
+ Credential cred = createCredentialWithUserCredential();
+ cred.getUserCredential().setPassword(null);
assertFalse(cred.validate());
}
@@ -239,13 +240,8 @@ public class CredentialTest {
*/
@Test
public void validateUserCredentialWithoutAuthMethod() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- cred.userCredential = new Credential.UserCredential();
- cred.userCredential.username = "username";
- cred.userCredential.password = "password";
- cred.userCredential.eapType = EAPConstants.EAP_TTLS;
- cred.caCertificate = FakeKeys.CA_CERT0;
+ Credential cred = createCredentialWithUserCredential();
+ cred.getUserCredential().setNonEapInnerMethod(null);
assertFalse(cred.validate());
}
@@ -258,17 +254,7 @@ public class CredentialTest {
*/
@Test
public void validateCertCredential() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup certificate credential.
- cred.certCredential = new Credential.CertificateCredential();
- cred.certCredential.certType = "x509v3";
- cred.certCredential.certSha256FingerPrint =
- MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
- // Setup certificates and private key.
- cred.caCertificate = FakeKeys.CA_CERT0;
- cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
- cred.clientPrivateKey = FakeKeys.RSA_KEY1;
+ Credential cred = createCredentialWithCertificateCredential();
assertTrue(cred.validate());
}
@@ -278,16 +264,8 @@ public class CredentialTest {
* @throws Exception
*/
public void validateCertCredentialWithoutCaCert() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup certificate credential.
- cred.certCredential = new Credential.CertificateCredential();
- cred.certCredential.certType = "x509v3";
- cred.certCredential.certSha256FingerPrint =
- MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
- // Setup certificates and private key.
- cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
- cred.clientPrivateKey = FakeKeys.RSA_KEY1;
+ Credential cred = createCredentialWithCertificateCredential();
+ cred.setCaCertificate(null);
assertFalse(cred.validate());
}
@@ -298,16 +276,8 @@ public class CredentialTest {
*/
@Test
public void validateCertCredentialWithoutClientCertChain() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup certificate credential.
- cred.certCredential = new Credential.CertificateCredential();
- cred.certCredential.certType = "x509v3";
- cred.certCredential.certSha256FingerPrint =
- MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
- // Setup certificates and private key.
- cred.caCertificate = FakeKeys.CA_CERT0;
- cred.clientPrivateKey = FakeKeys.RSA_KEY1;
+ Credential cred = createCredentialWithCertificateCredential();
+ cred.setClientCertificateChain(null);
assertFalse(cred.validate());
}
@@ -318,16 +288,8 @@ public class CredentialTest {
*/
@Test
public void validateCertCredentialWithoutClientPrivateKey() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup certificate credential.
- cred.certCredential = new Credential.CertificateCredential();
- cred.certCredential.certType = "x509v3";
- cred.certCredential.certSha256FingerPrint =
- MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
- // Setup certificates and private key.
- cred.caCertificate = FakeKeys.CA_CERT0;
- cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
+ Credential cred = createCredentialWithCertificateCredential();
+ cred.setClientPrivateKey(null);
assertFalse(cred.validate());
}
@@ -339,17 +301,8 @@ public class CredentialTest {
*/
@Test
public void validateCertCredentialWithMismatchFingerprint() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup certificate credential.
- cred.certCredential = new Credential.CertificateCredential();
- cred.certCredential.certType = "x509v3";
- cred.certCredential.certSha256FingerPrint = new byte[32];
- Arrays.fill(cred.certCredential.certSha256FingerPrint, (byte)0);
- // Setup certificates and private key.
- cred.caCertificate = FakeKeys.CA_CERT0;
- cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
- cred.clientPrivateKey = FakeKeys.RSA_KEY1;
+ Credential cred = createCredentialWithCertificateCredential();
+ cred.getCertCredential().setCertSha256Fingerprint(new byte[32]);
assertFalse(cred.validate());
}
@@ -360,12 +313,7 @@ public class CredentialTest {
*/
@Test
public void validateSimCredentialWithEapSim() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup SIM credential.
- cred.simCredential = new Credential.SimCredential();
- cred.simCredential.imsi = "1234*";
- cred.simCredential.eapType = EAPConstants.EAP_SIM;
+ Credential cred = createCredentialWithSimCredential();
assertTrue(cred.validate());
}
@@ -376,12 +324,8 @@ public class CredentialTest {
*/
@Test
public void validateSimCredentialWithEapAka() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup SIM credential.
- cred.simCredential = new Credential.SimCredential();
- cred.simCredential.imsi = "1234*";
- cred.simCredential.eapType = EAPConstants.EAP_AKA;
+ Credential cred = createCredentialWithSimCredential();
+ cred.getSimCredential().setEapType(EAPConstants.EAP_AKA);
assertTrue(cred.validate());
}
@@ -392,12 +336,8 @@ public class CredentialTest {
*/
@Test
public void validateSimCredentialWithEapAkaPrime() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup SIM credential.
- cred.simCredential = new Credential.SimCredential();
- cred.simCredential.imsi = "1234*";
- cred.simCredential.eapType = EAPConstants.EAP_AKA_PRIME;
+ Credential cred = createCredentialWithSimCredential();
+ cred.getSimCredential().setEapType(EAPConstants.EAP_AKA_PRIME);
assertTrue(cred.validate());
}
@@ -408,11 +348,8 @@ public class CredentialTest {
*/
@Test
public void validateSimCredentialWithoutIMSI() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup SIM credential.
- cred.simCredential = new Credential.SimCredential();
- cred.simCredential.eapType = EAPConstants.EAP_SIM;
+ Credential cred = createCredentialWithSimCredential();
+ cred.getSimCredential().setImsi(null);
assertFalse(cred.validate());
}
@@ -423,12 +360,8 @@ public class CredentialTest {
*/
@Test
public void validateSimCredentialWithInvalidIMSI() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup SIM credential.
- cred.simCredential = new Credential.SimCredential();
- cred.simCredential.imsi = "dummy";
- cred.simCredential.eapType = EAPConstants.EAP_SIM;
+ Credential cred = createCredentialWithSimCredential();
+ cred.getSimCredential().setImsi("dummy");
assertFalse(cred.validate());
}
@@ -439,12 +372,8 @@ public class CredentialTest {
*/
@Test
public void validateSimCredentialWithEapTls() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup SIM credential.
- cred.simCredential = new Credential.SimCredential();
- cred.simCredential.imsi = "1234*";
- cred.simCredential.eapType = EAPConstants.EAP_TLS;
+ Credential cred = createCredentialWithSimCredential();
+ cred.getSimCredential().setEapType(EAPConstants.EAP_TLS);
assertFalse(cred.validate());
}
@@ -455,19 +384,12 @@ public class CredentialTest {
*/
@Test
public void validateCredentialWithUserAndSimCredential() throws Exception {
- Credential cred = new Credential();
- cred.realm = "realm";
- // Setup user credential with EAP-TTLS.
- cred.userCredential = new Credential.UserCredential();
- cred.userCredential.username = "username";
- cred.userCredential.password = "password";
- cred.userCredential.eapType = EAPConstants.EAP_TTLS;
- cred.userCredential.nonEapInnerMethod = "MS-CHAP";
- cred.caCertificate = FakeKeys.CA_CERT0;
+ Credential cred = createCredentialWithUserCredential();
// Setup SIM credential.
- cred.simCredential = new Credential.SimCredential();
- cred.simCredential.imsi = "1234*";
- cred.simCredential.eapType = EAPConstants.EAP_SIM;
+ Credential.SimCredential simCredential = new Credential.SimCredential();
+ simCredential.setImsi("1234*");
+ simCredential.setEapType(EAPConstants.EAP_SIM);
+ cred.setSimCredential(simCredential);
assertFalse(cred.validate());
}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
deleted file mode 100644
index c70799332b02..000000000000
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.net.wifi.hotspot2.pps;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.junit.Test;
-
-/**
- * Unit tests for {@link android.net.wifi.hotspot2.pps.HomeSP}.
- */
-@SmallTest
-public class HomeSPTest {
- private static HomeSP createHomeSp() {
- HomeSP homeSp = new HomeSP();
- homeSp.fqdn = "fqdn";
- homeSp.friendlyName = "friendly name";
- homeSp.roamingConsortiumOIs = new long[] {0x55, 0x66};
- return homeSp;
- }
-
- private static void verifyParcel(HomeSP writeHomeSp) throws Exception {
- Parcel parcel = Parcel.obtain();
- writeHomeSp.writeToParcel(parcel, 0);
-
- parcel.setDataPosition(0); // Rewind data position back to the beginning for read.
- HomeSP readHomeSp = HomeSP.CREATOR.createFromParcel(parcel);
- assertTrue(readHomeSp.equals(writeHomeSp));
- }
-
- /**
- * Verify parcel read/write for an empty HomeSP.
- *
- * @throws Exception
- */
- @Test
- public void verifyParcelWithEmptyHomeSP() throws Exception {
- verifyParcel(new HomeSP());
- }
-
- /**
- * Verify parcel read/write for a valid HomeSP.
- *
- * @throws Exception
- */
- @Test
- public void verifyParcelWithValidHomeSP() throws Exception {
- verifyParcel(createHomeSp());
- }
-
- /**
- * Verify that a HomeSP is valid when both FQDN and Friendly Name
- * are provided.
- *
- * @throws Exception
- */
- @Test
- public void validateValidHomeSP() throws Exception {
- HomeSP homeSp = new HomeSP();
- homeSp.fqdn = "fqdn";
- homeSp.friendlyName = "friendly name";
- assertTrue(homeSp.validate());
- }
-
- /**
- * Verify that a HomeSP is not valid when FQDN is not provided
- *
- * @throws Exception
- */
- @Test
- public void validateHomeSpWithoutFqdn() throws Exception {
- HomeSP homeSp = new HomeSP();
- homeSp.friendlyName = "friendly name";
- assertFalse(homeSp.validate());
- }
-
- /**
- * Verify that a HomeSP is not valid when Friendly Name is not provided
- *
- * @throws Exception
- */
- @Test
- public void validateHomeSpWithoutFriendlyName() throws Exception {
- HomeSP homeSp = new HomeSP();
- homeSp.fqdn = "fqdn";
- assertFalse(homeSp.validate());
- }
-
- /**
- * Verify that a HomeSP is valid when the optional Roaming Consortium OIs are
- * provided.
- *
- * @throws Exception
- */
- @Test
- public void validateHomeSpWithRoamingConsoritums() throws Exception {
- HomeSP homeSp = new HomeSP();
- homeSp.fqdn = "fqdn";
- homeSp.friendlyName = "friendly name";
- homeSp.roamingConsortiumOIs = new long[] {0x55, 0x66};
- assertTrue(homeSp.validate());
- }
-
- /**
- * Verify that copy constructor works when pass in a null source.
- *
- * @throws Exception
- */
- @Test
- public void validateCopyConstructorFromNullSource() throws Exception {
- HomeSP copySp = new HomeSP(null);
- HomeSP defaultSp = new HomeSP();
- assertTrue(copySp.equals(defaultSp));
- }
-
- /**
- * Verify that copy constructor works when pass in a valid source.
- *
- * @throws Exception
- */
- @Test
- public void validateCopyConstructorFromValidSource() throws Exception {
- HomeSP sourceSp = new HomeSP();
- sourceSp.fqdn = "fqdn";
- sourceSp.friendlyName = "friendlyName";
- sourceSp.roamingConsortiumOIs = new long[] {0x55, 0x66};
- HomeSP copySp = new HomeSP(sourceSp);
- assertTrue(copySp.equals(sourceSp));
- }
-}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
new file mode 100644
index 000000000000..c41c11f16acf
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.net.wifi.hotspot2.pps;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Unit tests for {@link android.net.wifi.hotspot2.pps.HomeSp}.
+ */
+@SmallTest
+public class HomeSpTest {
+
+ /**
+ * Helper function for creating a map of home network IDs for testing.
+ *
+ * @return Map of home network IDs
+ */
+ private static Map<String, Long> createHomeNetworkIds() {
+ Map<String, Long> homeNetworkIds = new HashMap<>();
+ homeNetworkIds.put("ssid", 0x1234L);
+ homeNetworkIds.put("nullhessid", null);
+ return homeNetworkIds;
+ }
+
+ /**
+ * Helper function for creating a HomeSp for testing.
+ *
+ * @param homeNetworkIds The map of home network IDs associated with HomeSp
+ * @return {@link HomeSp}
+ */
+ private static HomeSp createHomeSp(Map<String, Long> homeNetworkIds) {
+ HomeSp homeSp = new HomeSp();
+ homeSp.setFqdn("fqdn");
+ homeSp.setFriendlyName("friendly name");
+ homeSp.setIconUrl("icon.url");
+ homeSp.setHomeNetworkIds(homeNetworkIds);
+ homeSp.setMatchAllOis(new long[] {0x11L, 0x22L});
+ homeSp.setMatchAnyOis(new long[] {0x33L, 0x44L});
+ homeSp.setOtherHomePartners(new String[] {"partner1", "partner2"});
+ homeSp.setRoamingConsortiumOis(new long[] {0x55, 0x66});
+ return homeSp;
+ }
+
+ /**
+ * Helper function for creating a HomeSp with home network IDs for testing.
+ *
+ * @return {@link HomeSp}
+ */
+ private static HomeSp createHomeSpWithHomeNetworkIds() {
+ return createHomeSp(createHomeNetworkIds());
+ }
+
+ /**
+ * Helper function for creating a HomeSp without home network IDs for testing.
+ *
+ * @return {@link HomeSp}
+ */
+ private static HomeSp createHomeSpWithoutHomeNetworkIds() {
+ return createHomeSp(null);
+ }
+
+ /**
+ * Helper function for verifying HomeSp after parcel write then read.
+ * @param writeHomeSp
+ * @throws Exception
+ */
+ private static void verifyParcel(HomeSp writeHomeSp) throws Exception {
+ Parcel parcel = Parcel.obtain();
+ writeHomeSp.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0); // Rewind data position back to the beginning for read.
+ HomeSp readHomeSp = HomeSp.CREATOR.createFromParcel(parcel);
+ assertTrue(readHomeSp.equals(writeHomeSp));
+ }
+
+ /**
+ * Verify parcel read/write for an empty HomeSp.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithEmptyHomeSp() throws Exception {
+ verifyParcel(new HomeSp());
+ }
+
+ /**
+ * Verify parcel read/write for a HomeSp containing Home Network IDs.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithHomeNetworkIds() throws Exception {
+ verifyParcel(createHomeSpWithHomeNetworkIds());
+ }
+
+ /**
+ * Verify parcel read/write for a HomeSp without Home Network IDs.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithoutHomeNetworkIds() throws Exception {
+ verifyParcel(createHomeSpWithoutHomeNetworkIds());
+ }
+
+ /**
+ * Verify that a HomeSp is valid when both FQDN and Friendly Name
+ * are provided.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateValidHomeSp() throws Exception {
+ HomeSp homeSp = createHomeSpWithHomeNetworkIds();
+ assertTrue(homeSp.validate());
+ }
+
+ /**
+ * Verify that a HomeSp is not valid when FQDN is not provided
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateHomeSpWithoutFqdn() throws Exception {
+ HomeSp homeSp = createHomeSpWithHomeNetworkIds();
+ homeSp.setFqdn(null);
+ assertFalse(homeSp.validate());
+ }
+
+ /**
+ * Verify that a HomeSp is not valid when Friendly Name is not provided
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateHomeSpWithoutFriendlyName() throws Exception {
+ HomeSp homeSp = createHomeSpWithHomeNetworkIds();
+ homeSp.setFriendlyName(null);
+ assertFalse(homeSp.validate());
+ }
+
+ /**
+ * Verify that a HomeSp is valid when the optional Home Network IDs are
+ * not provided.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateHomeSpWithoutHomeNetworkIds() throws Exception {
+ HomeSp homeSp = createHomeSpWithoutHomeNetworkIds();
+ assertTrue(homeSp.validate());
+ }
+
+ /**
+ * Verify that a HomeSp is invalid when the optional Home Network IDs
+ * contained an invalid SSID (exceeding maximum number of bytes).
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateHomeSpWithInvalidHomeNetworkIds() throws Exception {
+ HomeSp homeSp = createHomeSpWithoutHomeNetworkIds();
+ // HomeNetworkID with SSID exceeding the maximum length.
+ Map<String, Long> homeNetworkIds = new HashMap<>();
+ byte[] rawSsidBytes = new byte[33];
+ Arrays.fill(rawSsidBytes, (byte) 'a');
+ homeNetworkIds.put(
+ StringFactory.newStringFromBytes(rawSsidBytes, StandardCharsets.UTF_8), 0x1234L);
+ homeSp.setHomeNetworkIds(homeNetworkIds);
+ assertFalse(homeSp.validate());
+ }
+
+ /**
+ * Verify that copy constructor works when pass in a null source.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateCopyConstructorFromNullSource() throws Exception {
+ HomeSp copySp = new HomeSp(null);
+ HomeSp defaultSp = new HomeSp();
+ assertTrue(copySp.equals(defaultSp));
+ }
+
+ /**
+ * Verify that copy constructor works when pass in a valid source.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateCopyConstructorFromValidSource() throws Exception {
+ HomeSp sourceSp = createHomeSpWithHomeNetworkIds();
+ HomeSp copySp = new HomeSp(sourceSp);
+ assertTrue(copySp.equals(sourceSp));
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java
new file mode 100644
index 000000000000..2a3676463936
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.net.wifi.hotspot2.pps;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Base64;
+
+import org.junit.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Unit tests for {@link android.net.wifi.hotspot2.pps.Policy}.
+ */
+@SmallTest
+public class PolicyTest {
+ private static final int MAX_NUMBER_OF_EXCLUDED_SSIDS = 128;
+ private static final int MAX_SSID_BYTES = 32;
+ private static final int MAX_PORT_STRING_BYTES = 64;
+
+ /**
+ * Helper function for creating a {@link Policy} for testing.
+ *
+ * @return {@link Policy}
+ */
+ private static Policy createPolicy() {
+ Policy policy = new Policy();
+ policy.setMinHomeDownlinkBandwidth(123);
+ policy.setMinHomeUplinkBandwidth(345);
+ policy.setMinRoamingDownlinkBandwidth(567);
+ policy.setMinRoamingUplinkBandwidth(789);
+ policy.setExcludedSsidList(new String[] {"ssid1", "ssid2"});
+ Map<Integer, String> requiredProtoPortMap = new HashMap<>();
+ requiredProtoPortMap.put(12, "23,342,123");
+ requiredProtoPortMap.put(23, "789,372,1235");
+ policy.setRequiredProtoPortMap(requiredProtoPortMap);
+ policy.setMaximumBssLoadValue(12);
+
+ List<Policy.RoamingPartner> preferredRoamingPartnerList = new ArrayList<>();
+ Policy.RoamingPartner partner1 = new Policy.RoamingPartner();
+ partner1.setFqdn("partner1.com");
+ partner1.setFqdnExactMatch(true);
+ partner1.setPriority(12);
+ partner1.setCountries("us,jp");
+ Policy.RoamingPartner partner2 = new Policy.RoamingPartner();
+ partner2.setFqdn("partner2.com");
+ partner2.setFqdnExactMatch(false);
+ partner2.setPriority(42);
+ partner2.setCountries("ca,fr");
+ preferredRoamingPartnerList.add(partner1);
+ preferredRoamingPartnerList.add(partner2);
+ policy.setPreferredRoamingPartnerList(preferredRoamingPartnerList);
+
+ UpdateParameter policyUpdate = new UpdateParameter();
+ policyUpdate.setUpdateIntervalInMinutes(1712);
+ policyUpdate.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM);
+ policyUpdate.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP);
+ policyUpdate.setServerUri("policy.update.com");
+ policyUpdate.setUsername("username");
+ policyUpdate.setBase64EncodedPassword(
+ Base64.encodeToString("password".getBytes(), Base64.DEFAULT));
+ policyUpdate.setTrustRootCertUrl("trust.cert.com");
+ policyUpdate.setTrustRootCertSha256Fingerprint(new byte[32]);
+ policy.setPolicyUpdate(policyUpdate);
+
+ return policy;
+ }
+
+ /**
+ * Helper function for verifying Policy after parcel write then read.
+ * @param policyToWrite
+ * @throws Exception
+ */
+ private static void verifyParcel(Policy policyToWrite) throws Exception {
+ Parcel parcel = Parcel.obtain();
+ policyToWrite.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0); // Rewind data position back to the beginning for read.
+ Policy policyFromRead = Policy.CREATOR.createFromParcel(parcel);
+ assertTrue(policyFromRead.equals(policyToWrite));
+ }
+
+ /**
+ * Verify parcel read/write for an empty Policy.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithEmptyPolicy() throws Exception {
+ verifyParcel(new Policy());
+ }
+
+ /**
+ * Verify parcel read/write for a Policy with all fields set.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithFullPolicy() throws Exception {
+ verifyParcel(createPolicy());
+ }
+
+ /**
+ * Verify parcel read/write for a Policy without protocol port map.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithoutProtoPortMap() throws Exception {
+ Policy policy = createPolicy();
+ policy.setRequiredProtoPortMap(null);
+ verifyParcel(policy);
+ }
+
+ /**
+ * Verify parcel read/write for a Policy without preferred roaming partner list.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithoutPreferredRoamingPartnerList() throws Exception {
+ Policy policy = createPolicy();
+ policy.setPreferredRoamingPartnerList(null);
+ verifyParcel(policy);
+ }
+
+ /**
+ * Verify parcel read/write for a Policy without policy update parameters.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithoutPolicyUpdate() throws Exception {
+ Policy policy = createPolicy();
+ policy.setPolicyUpdate(null);
+ verifyParcel(policy);
+ }
+
+ /**
+ * Verify that policy created using copy constructor with null source should be the same
+ * as the policy created using default constructor.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyCopyConstructionWithNullSource() throws Exception {
+ Policy copyPolicy = new Policy(null);
+ Policy defaultPolicy = new Policy();
+ assertTrue(defaultPolicy.equals(copyPolicy));
+ }
+
+ /**
+ * Verify that policy created using copy constructor with a valid source should be the
+ * same as the source.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyCopyConstructionWithFullPolicy() throws Exception {
+ Policy policy = createPolicy();
+ Policy copyPolicy = new Policy(policy);
+ assertTrue(policy.equals(copyPolicy));
+ }
+
+ /**
+ * Verify that a default policy (with no informatio) is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithDefault() throws Exception {
+ Policy policy = new Policy();
+ assertFalse(policy.validate());
+ }
+
+ /**
+ * Verify that a policy created using {@link #createPolicy} is valid, since all fields are
+ * filled in with valid values.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithFullPolicy() throws Exception {
+ assertTrue(createPolicy().validate());
+ }
+
+ /**
+ * Verify that a policy without policy update parameters is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithoutPolicyUpdate() throws Exception {
+ Policy policy = createPolicy();
+ policy.setPolicyUpdate(null);
+ assertFalse(policy.validate());
+ }
+
+ /**
+ * Verify that a policy with invalid policy update parameters is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithInvalidPolicyUpdate() throws Exception {
+ Policy policy = createPolicy();
+ policy.setPolicyUpdate(new UpdateParameter());
+ assertFalse(policy.validate());
+ }
+
+ /**
+ * Verify that a policy with a preferred roaming partner with FQDN not specified is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithRoamingPartnerWithoutFQDN() throws Exception {
+ Policy policy = createPolicy();
+ Policy.RoamingPartner partner = new Policy.RoamingPartner();
+ partner.setFqdnExactMatch(true);
+ partner.setPriority(12);
+ partner.setCountries("us,jp");
+ policy.getPreferredRoamingPartnerList().add(partner);
+ assertFalse(policy.validate());
+ }
+
+ /**
+ * Verify that a policy with a preferred roaming partner with countries not specified is
+ * invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithRoamingPartnerWithoutCountries() throws Exception {
+ Policy policy = createPolicy();
+ Policy.RoamingPartner partner = new Policy.RoamingPartner();
+ partner.setFqdn("test.com");
+ partner.setFqdnExactMatch(true);
+ partner.setPriority(12);
+ policy.getPreferredRoamingPartnerList().add(partner);
+ assertFalse(policy.validate());
+ }
+
+ /**
+ * Verify that a policy with a proto-port tuple that contains an invalid port string is
+ * invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithInvalidPortStringInProtoPortMap() throws Exception {
+ Policy policy = createPolicy();
+ byte[] rawPortBytes = new byte[MAX_PORT_STRING_BYTES + 1];
+ policy.getRequiredProtoPortMap().put(
+ 324, new String(rawPortBytes, StandardCharsets.UTF_8));
+ assertFalse(policy.validate());
+ }
+
+ /**
+ * Verify that a policy with number of excluded SSIDs exceeded the max is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithSsidExclusionListSizeExceededMax() throws Exception {
+ Policy policy = createPolicy();
+ String[] excludedSsidList = new String[MAX_NUMBER_OF_EXCLUDED_SSIDS + 1];
+ Arrays.fill(excludedSsidList, "ssid");
+ policy.setExcludedSsidList(excludedSsidList);
+ assertFalse(policy.validate());
+ }
+
+ /**
+ * Verify that a policy with an invalid SSID in the excluded SSID list is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithInvalidSsid() throws Exception {
+ Policy policy = createPolicy();
+ byte[] rawSsidBytes = new byte[MAX_SSID_BYTES + 1];
+ Arrays.fill(rawSsidBytes, (byte) 'a');
+ String[] excludedSsidList = new String[] {
+ new String(rawSsidBytes, StandardCharsets.UTF_8)};
+ policy.setExcludedSsidList(excludedSsidList);
+ assertFalse(policy.validate());
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java
new file mode 100644
index 000000000000..551ed43c5efa
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.net.wifi.hotspot2.pps;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Base64;
+
+import org.junit.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Unit tests for {@link android.net.wifi.hotspot2.pps.UpdateParameter}.
+ */
+@SmallTest
+public class UpdateParameterTest {
+ private static final int MAX_URI_BYTES = 1023;
+ private static final int MAX_URL_BYTES = 1023;
+ private static final int MAX_USERNAME_BYTES = 63;
+ private static final int MAX_PASSWORD_BYTES = 255;
+ private static final int CERTIFICATE_SHA256_BYTES = 32;
+
+ /**
+ * Helper function for creating a {@link UpdateParameter} for testing.
+ *
+ * @return {@link UpdateParameter}
+ */
+ private static UpdateParameter createUpdateParameter() {
+ UpdateParameter updateParam = new UpdateParameter();
+ updateParam.setUpdateIntervalInMinutes(1712);
+ updateParam.setUpdateMethod(UpdateParameter.UPDATE_METHOD_OMADM);
+ updateParam.setRestriction(UpdateParameter.UPDATE_RESTRICTION_HOMESP);
+ updateParam.setServerUri("server.pdate.com");
+ updateParam.setUsername("username");
+ updateParam.setBase64EncodedPassword(
+ Base64.encodeToString("password".getBytes(), Base64.DEFAULT));
+ updateParam.setTrustRootCertUrl("trust.cert.com");
+ updateParam.setTrustRootCertSha256Fingerprint(new byte[32]);
+ return updateParam;
+ }
+
+ /**
+ * Helper function for verifying UpdateParameter after parcel write then read.
+ * @param paramToWrite The UpdateParamter to verify
+ * @throws Exception
+ */
+ private static void verifyParcel(UpdateParameter paramToWrite) throws Exception {
+ Parcel parcel = Parcel.obtain();
+ paramToWrite.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0); // Rewind data position back to the beginning for read.
+ UpdateParameter paramFromRead = UpdateParameter.CREATOR.createFromParcel(parcel);
+ assertTrue(paramFromRead.equals(paramToWrite));
+ }
+
+ /**
+ * Verify parcel read/write for an empty UpdateParameter.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithEmptyUpdateParameter() throws Exception {
+ verifyParcel(new UpdateParameter());
+ }
+
+ /**
+ * Verify parcel read/write for a UpdateParameter with all fields set.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyParcelWithFullUpdateParameter() throws Exception {
+ verifyParcel(createUpdateParameter());
+ }
+
+ /**
+ * Verify that UpdateParameter created using copy constructor with null source should be the
+ * same as the UpdateParameter created using default constructor.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyCopyConstructionWithNullSource() throws Exception {
+ UpdateParameter copyParam = new UpdateParameter(null);
+ UpdateParameter defaultParam = new UpdateParameter();
+ assertTrue(defaultParam.equals(copyParam));
+ }
+
+ /**
+ * Verify that UpdateParameter created using copy constructor with a valid source should be the
+ * same as the source.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyCopyConstructionWithFullUpdateParameter() throws Exception {
+ UpdateParameter origParam = createUpdateParameter();
+ UpdateParameter copyParam = new UpdateParameter(origParam);
+ assertTrue(origParam.equals(copyParam));
+ }
+
+ /**
+ * Verify that a default UpdateParameter is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithDefault() throws Exception {
+ UpdateParameter updateParam = new UpdateParameter();
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter created using {@link #createUpdateParameter} is valid,
+ * since all fields are filled in with valid values.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithFullPolicy() throws Exception {
+ assertTrue(createUpdateParameter().validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with an unknown update method is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithUnknowMethod() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setUpdateMethod("adsfasd");
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with an unknown restriction is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithUnknowRestriction() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setRestriction("adsfasd");
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with an username exceeding maximum size is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithUsernameExceedingMaxSize() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ byte[] rawUsernameBytes = new byte[MAX_USERNAME_BYTES + 1];
+ Arrays.fill(rawUsernameBytes, (byte) 'a');
+ updateParam.setUsername(new String(rawUsernameBytes, StandardCharsets.UTF_8));
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with an empty username is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithEmptyUsername() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setUsername(null);
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with a password exceeding maximum size is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithPasswordExceedingMaxSize() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ byte[] rawPasswordBytes = new byte[MAX_PASSWORD_BYTES + 1];
+ Arrays.fill(rawPasswordBytes, (byte) 'a');
+ updateParam.setBase64EncodedPassword(new String(rawPasswordBytes, StandardCharsets.UTF_8));
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with an empty password is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithEmptyPassword() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setBase64EncodedPassword(null);
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with a Base64 encoded password that contained invalid padding
+ * is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithPasswordContainedInvalidPadding() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setBase64EncodedPassword(updateParam.getBase64EncodedPassword() + "=");
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter without trust root certificate URL is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithoutTrustRootCertUrl() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setTrustRootCertUrl(null);
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with invalid trust root certificate URL is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithInvalidTrustRootCertUrl() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ byte[] rawUrlBytes = new byte[MAX_URL_BYTES + 1];
+ Arrays.fill(rawUrlBytes, (byte) 'a');
+ updateParam.setTrustRootCertUrl(new String(rawUrlBytes, StandardCharsets.UTF_8));
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter without trust root certificate SHA-256 fingerprint is
+ * invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithouttrustRootCertSha256Fingerprint() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setTrustRootCertSha256Fingerprint(null);
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with an incorrect size trust root certificate SHA-256
+ * fingerprint is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithInvalidtrustRootCertSha256Fingerprint() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setTrustRootCertSha256Fingerprint(new byte[CERTIFICATE_SHA256_BYTES + 1]);
+ assertFalse(updateParam.validate());
+
+ updateParam.setTrustRootCertSha256Fingerprint(new byte[CERTIFICATE_SHA256_BYTES - 1]);
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter without server URI is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithoutServerUri() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setServerUri(null);
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with an invalid server URI is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validatePolicyWithInvalidServerUri() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ byte[] rawUriBytes = new byte[MAX_URI_BYTES + 1];
+ Arrays.fill(rawUriBytes, (byte) 'a');
+ updateParam.setServerUri(new String(rawUriBytes, StandardCharsets.UTF_8));
+ assertFalse(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with update interval set to "never" will not perform
+ * validation on other parameters, since update is not applicable in this case.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithNoServerCheck() throws Exception {
+ UpdateParameter updateParam = new UpdateParameter();
+ updateParam.setUpdateIntervalInMinutes(UpdateParameter.UPDATE_CHECK_INTERVAL_NEVER);
+ updateParam.setUsername(null);
+ updateParam.setBase64EncodedPassword(null);
+ updateParam.setUpdateMethod(null);
+ updateParam.setRestriction(null);
+ updateParam.setServerUri(null);
+ updateParam.setTrustRootCertUrl(null);
+ updateParam.setTrustRootCertSha256Fingerprint(null);
+ assertTrue(updateParam.validate());
+ }
+
+ /**
+ * Verify that an UpdateParameter with unset update interval is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUpdateParameterWithoutUpdateInterval() throws Exception {
+ UpdateParameter updateParam = createUpdateParameter();
+ updateParam.setUpdateIntervalInMinutes(Long.MIN_VALUE);
+ assertFalse(updateParam.validate());
+ }
+}