├── README.md ├── device └── qcom │ └── sdm845 │ └── sdm845.mk ├── frameworks ├── base │ ├── core │ │ └── java │ │ │ └── android │ │ │ └── provider │ │ │ └── Settings.java │ ├── packages │ │ └── SettingsProvider │ │ │ ├── res │ │ │ └── values │ │ │ │ └── defaults.xml │ │ │ └── src │ │ │ └── com │ │ │ └── android │ │ │ └── providers │ │ │ └── settings │ │ │ └── DatabaseHelper.java │ └── services │ │ └── core │ │ └── java │ │ └── com │ │ └── android │ │ └── server │ │ └── ConnectivityService.java └── opt │ └── net │ └── ethernet │ └── java │ └── com │ └── android │ └── server │ └── ethernet │ ├── EthernetNetworkFactory.java │ ├── EthernetServiceImpl.java │ └── EthernetTracker.java └── packages └── apps └── Settings ├── res ├── layout │ └── ethernet_configure.xml ├── values-zh-rCN │ └── strings.xml └── values │ └── strings.xml └── src └── com └── android └── settings └── ethernet ├── EthernetDialog.java ├── EthernetEnabler.java ├── EthernetSettings.java └── ip ├── AbsEditText.java ├── AbsEditTextGroup.java ├── IPEditText.java └── IPView.java /README.md: -------------------------------------------------------------------------------- 1 | # Android_Ethernet_StaticIPConfig 2 | 此方案在android中实现了网卡静态IP设置、有线网和USB无线网卡的切换。 3 | 4 | 源码是增量代码,基于Android 9实现。你需要将源码合入到android系统版本中。0(n_n)0 5 | 6 | 7 | -------------------------------------------------------------------------------- /device/qcom/sdm845/sdm845.mk: -------------------------------------------------------------------------------- 1 | # Enable AVB 2.0 2 | BOARD_AVB_ENABLE := true 3 | 4 | 5 | 6 | # Enable chain partition for system, to facilitate system-only OTA in Treble. 7 | BOARD_AVB_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem 8 | BOARD_AVB_SYSTEM_ALGORITHM := SHA256_RSA2048 9 | BOARD_AVB_SYSTEM_ROLLBACK_INDEX := 0 10 | BOARD_AVB_SYSTEM_ROLLBACK_INDEX_LOCATION := 2 11 | 12 | TARGET_DEFINES_DALVIK_HEAP := true 13 | $(call inherit-product, device/qcom/common/common64.mk) 14 | #Inherit all except heap growth limit from phone-xhdpi-2048-dalvik-heap.mk 15 | PRODUCT_PROPERTY_OVERRIDES += \ 16 | dalvik.vm.heapstartsize=8m \ 17 | dalvik.vm.heapsize=512m \ 18 | dalvik.vm.heaptargetutilization=0.75 \ 19 | dalvik.vm.heapminfree=512k \ 20 | dalvik.vm.heapmaxfree=8m 21 | 22 | 23 | # Property to enable app trigger 24 | PRODUCT_PROPERTY_OVERRIDES += \ 25 | ro.vendor.at_library=libqti-at.so\ 26 | persist.vendor.qti.games.gt.prof=1 27 | 28 | # system prop for opengles version 29 | # 30 | # 196608 is decimal for 0x30000 to report version 3 31 | # 196609 is decimal for 0x30001 to report version 3.1 32 | # 196610 is decimal for 0x30002 to report version 3.2 33 | PRODUCT_PROPERTY_OVERRIDES += \ 34 | ro.opengles.version=196610 35 | 36 | PRODUCT_NAME := sdm845 37 | PRODUCT_DEVICE := sdm845 38 | PRODUCT_BRAND := Android 39 | #device name 40 | PRODUCT_MODEL := Sinsam Pad 41 | 42 | #Initial bringup flags 43 | TARGET_USES_AOSP := false 44 | TARGET_USES_AOSP_FOR_AUDIO := false 45 | TARGET_USES_QCOM_BSP := false 46 | 47 | # RRO configuration 48 | TARGET_USES_RRO := true 49 | 50 | # Default A/B configuration. 51 | ENABLE_AB ?= true 52 | 53 | TARGET_KERNEL_VERSION := 4.9 54 | 55 | TARGET_USES_NQ_NFC := true 56 | ifeq ($(TARGET_USES_NQ_NFC),true) 57 | # Flag to enable and support NQ3XX chipsets 58 | NQ3XX_PRESENT := true 59 | endif 60 | 61 | # default is nosdcard, S/W button enabled in resource 62 | PRODUCT_CHARACTERISTICS := nosdcard 63 | 64 | BOARD_FRP_PARTITION_NAME := frp 65 | 66 | # WLAN chipset 67 | WLAN_CHIPSET := qca_cld3 68 | 69 | #Android EGL implementation 70 | PRODUCT_PACKAGES += libGLES_android 71 | 72 | -include $(QCPATH)/common/config/qtic-config.mk 73 | -include hardware/qcom/display/config/sdm845.mk 74 | 75 | # Video seccomp policy files 76 | PRODUCT_COPY_FILES += \ 77 | device/qcom/sdm845/seccomp/mediacodec-seccomp.policy:$(TARGET_COPY_OUT_VENDOR)/etc/seccomp_policy/mediacodec.policy \ 78 | device/qcom/sdm845/seccomp/mediaextractor-seccomp.policy:$(TARGET_COPY_OUT_VENDOR)/etc/seccomp_policy/mediaextractor.policy 79 | 80 | PRODUCT_BOOT_JARS += telephony-ext \ 81 | tcmiface 82 | PRODUCT_PACKAGES += telephony-ext 83 | 84 | TARGET_ENABLE_QC_AV_ENHANCEMENTS := true 85 | 86 | TARGET_DISABLE_DASH := true 87 | 88 | ifneq ($(TARGET_DISABLE_DASH), true) 89 | PRODUCT_BOOT_JARS += qcmediaplayer 90 | endif 91 | 92 | ifneq ($(strip $(QCPATH)),) 93 | PRODUCT_BOOT_JARS += WfdCommon 94 | endif 95 | 96 | PRODUCT_BOOT_JARS += vendor.qti.voiceprint-V1.0-java 97 | 98 | # Video platform properties file 99 | PRODUCT_COPY_FILES += hardware/qcom/media/conf_files/sdm845/system_properties.xml:$(TARGET_COPY_OUT_VENDOR)/etc/system_properties.xml 100 | 101 | # Video codec configuration files 102 | ifeq ($(TARGET_ENABLE_QC_AV_ENHANCEMENTS), true) 103 | PRODUCT_COPY_FILES += device/qcom/sdm845/media_profiles.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_profiles_vendor.xml 104 | 105 | PRODUCT_COPY_FILES += device/qcom/sdm845/media_codecs.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_codecs.xml 106 | PRODUCT_COPY_FILES += device/qcom/sdm845/media_codecs_vendor.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_codecs_vendor.xml 107 | PRODUCT_COPY_FILES += device/qcom/sdm845/media_codecs_vendor_audio.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_codecs_vendor_audio.xml 108 | 109 | PRODUCT_COPY_FILES += device/qcom/sdm845/media_codecs_performance.xml:$(TARGET_COPY_OUT_VENDOR)/etc/media_codecs_performance.xml 110 | endif #TARGET_ENABLE_QC_AV_ENHANCEMENTS 111 | 112 | PRODUCT_PACKAGES += android.hardware.media.omx@1.0-impl 113 | 114 | # Audio configuration file 115 | -include $(TOPDIR)hardware/qcom/audio/configs/sdm845/sdm845.mk 116 | 117 | PRODUCT_PACKAGES += fs_config_files 118 | 119 | ifeq ($(ENABLE_AB), true) 120 | #A/B related packages 121 | PRODUCT_PACKAGES += update_engine \ 122 | update_engine_client \ 123 | update_verifier \ 124 | bootctrl.sdm845 \ 125 | brillo_update_payload \ 126 | android.hardware.boot@1.0-impl \ 127 | android.hardware.boot@1.0-service 128 | 129 | #Boot control HAL test app 130 | PRODUCT_PACKAGES_DEBUG += bootctl 131 | endif 132 | 133 | DEVICE_MATRIX_FILE := device/qcom/common/compatibility_matrix.xml 134 | DEVICE_FRAMEWORK_MANIFEST_FILE := device/qcom/sdm845/framework_manifest.xml 135 | 136 | #SHIFT6MQ 137 | ifeq ($(SIMCOM_PROJECT),SHIFT6MQ) 138 | DEVICE_MANIFEST_FILE := device/qcom/sdm845/manifest_shift6mq.xml 139 | DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE := device/qcom/common/vendor_framework_compatibility_matrix_shift6mq.xml 140 | else 141 | DEVICE_MANIFEST_FILE := device/qcom/sdm845/manifest.xml 142 | DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE := device/qcom/common/vendor_framework_compatibility_matrix.xml 143 | endif 144 | 145 | #ANT+ stack 146 | PRODUCT_PACKAGES += \ 147 | AntHalService \ 148 | libantradio \ 149 | antradio_app \ 150 | libvolumelistener 151 | 152 | PRODUCT_PACKAGES += \ 153 | android.hardware.configstore@1.0-service \ 154 | android.hardware.broadcastradio@1.0-impl 155 | 156 | # Vibrator 157 | PRODUCT_PACKAGES += \ 158 | android.hardware.vibrator@1.0-impl \ 159 | android.hardware.vibrator@1.0-service \ 160 | 161 | # Context hub HAL 162 | PRODUCT_PACKAGES += \ 163 | android.hardware.contexthub@1.0-impl.generic \ 164 | android.hardware.contexthub@1.0-service 165 | 166 | # FBE support 167 | PRODUCT_COPY_FILES += \ 168 | device/qcom/sdm845/init.qti.qseecomd.sh:$(TARGET_COPY_OUT_VENDOR)/bin/init.qti.qseecomd.sh \ 169 | frameworks/native/data/etc/android.software.verified_boot.xml:system/etc/permissions/android.software.verified_boot.xml 170 | 171 | # MSM IRQ Balancer configuration file 172 | PRODUCT_COPY_FILES += device/qcom/sdm845/msm_irqbalance.conf:$(TARGET_COPY_OUT_VENDOR)/etc/msm_irqbalance.conf 173 | 174 | # Powerhint configuration file 175 | PRODUCT_COPY_FILES += device/qcom/sdm845/powerhint.xml:$(TARGET_COPY_OUT_VENDOR)/etc/powerhint.xml 176 | 177 | # Camera configuration file. Shared by passthrough/binderized camera HAL 178 | PRODUCT_PACKAGES += camera.device@3.2-impl 179 | PRODUCT_PACKAGES += camera.device@1.0-impl 180 | PRODUCT_PACKAGES += android.hardware.camera.provider@2.4-impl 181 | # Enable binderized camera HAL 182 | PRODUCT_PACKAGES += android.hardware.camera.provider@2.4-service 183 | 184 | PRODUCT_PACKAGES += \ 185 | android.hardware.usb@1.0-service 186 | 187 | # WLAN host driver 188 | ifneq ($(WLAN_CHIPSET),) 189 | PRODUCT_PACKAGES += $(WLAN_CHIPSET)_wlan.ko 190 | endif 191 | 192 | # WLAN configuration file 193 | PRODUCT_COPY_FILES += \ 194 | device/qcom/sdm845/WCNSS_qcom_cfg.ini:$(TARGET_COPY_OUT_VENDOR)/etc/wifi/WCNSS_qcom_cfg.ini \ 195 | frameworks/native/data/etc/android.hardware.wifi.aware.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.wifi.aware.xml \ 196 | frameworks/native/data/etc/android.hardware.wifi.rtt.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.wifi.rtt.xml 197 | 198 | # MIDI feature 199 | PRODUCT_COPY_FILES += \ 200 | frameworks/native/data/etc/android.software.midi.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.midi.xml 201 | 202 | PRODUCT_PACKAGES += \ 203 | wpa_supplicant_overlay.conf \ 204 | p2p_supplicant_overlay.conf 205 | 206 | #for wlan 207 | PRODUCT_PACKAGES += \ 208 | wificond \ 209 | wifilogd 210 | 211 | # Sensor conf files 212 | PRODUCT_COPY_FILES += \ 213 | device/qcom/sdm845/sensors/hals.conf:$(TARGET_COPY_OUT_VENDOR)/etc/sensors/hals.conf \ 214 | frameworks/native/data/etc/android.hardware.sensor.accelerometer.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.accelerometer.xml \ 215 | frameworks/native/data/etc/android.hardware.sensor.compass.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.compass.xml \ 216 | frameworks/native/data/etc/android.hardware.sensor.gyroscope.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.gyroscope.xml \ 217 | frameworks/native/data/etc/android.hardware.sensor.light.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.light.xml \ 218 | frameworks/native/data/etc/android.hardware.sensor.proximity.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.proximity.xml \ 219 | frameworks/native/data/etc/android.hardware.sensor.barometer.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.barometer.xml \ 220 | frameworks/native/data/etc/android.hardware.sensor.stepcounter.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.stepcounter.xml \ 221 | frameworks/native/data/etc/android.hardware.sensor.stepdetector.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.stepdetector.xml \ 222 | frameworks/native/data/etc/android.hardware.sensor.ambient_temperature.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.ambient_temperature.xml \ 223 | frameworks/native/data/etc/android.hardware.sensor.relative_humidity.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.relative_humidity.xml \ 224 | frameworks/native/data/etc/android.hardware.sensor.hifi_sensors.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.hifi_sensors.xml 225 | 226 | #Enable debug libraries 227 | ifeq ($(TARGET_BUILD_VARIANT),userdebug) 228 | PRODUCT_PACKAGES += libstagefright_debug \ 229 | libmediaplayerservice_debug 230 | endif 231 | 232 | # High performance VR feature 233 | PRODUCT_COPY_FILES += \ 234 | frameworks/native/data/etc/android.hardware.vr.high_performance.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vr.high_performance.xml 235 | 236 | # Kernel modules install path 237 | KERNEL_MODULES_INSTALL := dlkm 238 | KERNEL_MODULES_OUT := out/target/product/$(PRODUCT_NAME)/$(KERNEL_MODULES_INSTALL)/lib/modules 239 | 240 | #FEATURE_OPENGLES_EXTENSION_PACK support string config file 241 | PRODUCT_COPY_FILES += \ 242 | frameworks/native/data/etc/android.hardware.opengles.aep.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.opengles.aep.xml 243 | 244 | #STATIC IP CONFIG 245 | PRODUCT_COPY_FILES += \ 246 | frameworks/native/data/etc/android.hardware.ethernet.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.ethernet.xml 247 | 248 | #Enable full treble flag 249 | 250 | #Add soft home, back and multitask keys 251 | PRODUCT_PROPERTY_OVERRIDES += \ 252 | qemu.hw.mainkeys=0 253 | 254 | # system prop for opengles version 255 | # 256 | # 196608 is decimal for 0x30000 to report version 3 257 | # 196609 is decimal for 0x30001 to report version 3.1 258 | # 196610 is decimal for 0x30002 to report version 3.2 259 | PRODUCT_PROPERTY_OVERRIDES += \ 260 | ro.opengles.version=196610 261 | 262 | #system prop for bluetooth SOC type 263 | PRODUCT_PROPERTY_OVERRIDES += \ 264 | vendor.qcom.bluetooth.soc=cherokee 265 | 266 | PRODUCT_FULL_TREBLE_OVERRIDE := true 267 | PRODUCT_VENDOR_MOVE_ENABLED := true 268 | 269 | PRODUCT_PROPERTY_OVERRIDES += rild.libpath=/vendor/lib64/libril-qc-hal-qmi.so 270 | 271 | #Property to set BG App limit 272 | PRODUCT_PROPERTY_OVERRIDES += ro.vendor.qti.sys.fw.bg_apps_limit=60 273 | 274 | #Enable QTI KEYMASTER and GATEKEEPER HIDLs 275 | KMGK_USE_QTI_SERVICE := true 276 | 277 | #Enable KEYMASTER 4.0 278 | ENABLE_KM_4_0 := true 279 | 280 | ifneq ($(strip $(TARGET_USES_RRO)),true) 281 | DEVICE_PACKAGE_OVERLAYS += device/qcom/sdm845/overlay 282 | endif 283 | 284 | #VR 285 | PRODUCT_PACKAGES += android.hardware.vr@1.0-impl \ 286 | android.hardware.vr@1.0-service 287 | #Thermal 288 | PRODUCT_PACKAGES += android.hardware.thermal@1.0-impl \ 289 | android.hardware.thermal@1.0-service 290 | 291 | # Camera HIDL configuration file. Shared by passthrough/binderized camera HAL 292 | PRODUCT_PACKAGES += camera.device@3.2-impl 293 | PRODUCT_PACKAGES += camera.device@1.0-impl 294 | PRODUCT_PACKAGES += android.hardware.camera.provider@2.4-impl 295 | # Enable binderized camera HAL 296 | PRODUCT_PACKAGES += android.hardware.camera.provider@2.4-service 297 | 298 | TARGET_SCVE_DISABLED := true 299 | #TARGET_USES_QTIC := false 300 | #TARGET_USES_QTIC_EXTENSION := false 301 | 302 | SDM845_DISABLE_MODULE := true 303 | 304 | ENABLE_VENDOR_RIL_SERVICE := true 305 | 306 | # Enable vndk-sp Libraries 307 | PRODUCT_PACKAGES += vndk_package 308 | 309 | PRODUCT_COMPATIBLE_PROPERTY_OVERRIDE:=true 310 | 311 | #Enable WIFI AWARE FEATURE 312 | WIFI_HIDL_FEATURE_AWARE := true 313 | 314 | # Enable STA + SAP Concurrency. 315 | WIFI_HIDL_FEATURE_DUAL_INTERFACE := true 316 | 317 | # Enable SAP + SAP Feature. 318 | QC_WIFI_HIDL_FEATURE_DUAL_AP := true 319 | 320 | TARGET_USES_MKE2FS := true 321 | $(call inherit-product, build/make/target/product/product_launched_with_p.mk) 322 | 323 | TARGET_MOUNT_POINTS_SYMLINKS := false 324 | 325 | # propery "ro.vendor.build.security_patch" is checked for 326 | # CTS compliance so need to make sure its set with following 327 | # format "YYYY-MM-DD" on production devices. 328 | # 329 | ifeq ($(ENABLE_VENDOR_IMAGE), true) 330 | VENDOR_SECURITY_PATCH := 2018-06-05 331 | endif 332 | 333 | #goodixfp 334 | ifeq ($(SIMCOM_PROJECT),SHIFT6MQ) 335 | PRODUCT_PACKAGES += \ 336 | libgf_ca \ 337 | libgf_hal \ 338 | libgoodixfingerprintd_binder \ 339 | fingerprint.default \ 340 | fingerprintd \ 341 | com.goodix.fingerprint \ 342 | GFManager 343 | 344 | PRODUCT_PACKAGES += \ 345 | android.hardware.biometrics.fingerprint@2.1-service \ 346 | android.hardware.biometrics.fingerprint@2.1 347 | 348 | PRODUCT_COPY_FILES += \ 349 | frameworks/native/data/etc/android.hardware.fingerprint.xml:vendor/etc/permissions/android.hardware.fingerprint.xml 350 | 351 | 352 | PRODUCT_COPY_FILES += kernel/msm-4.9/drivers/input/fingerprint/so/fingerprint.default.so:vendor/lib64/hw/fingerprint.default.so 353 | PRODUCT_COPY_FILES += kernel/msm-4.9/drivers/input/fingerprint/so/libgf_hal.so:vendor/lib64/libgf_hal.so 354 | PRODUCT_COPY_FILES += kernel/msm-4.9/drivers/input/fingerprint/so/libgf_ca.so:vendor/lib64/libgf_ca.so 355 | PRODUCT_COPY_FILES += kernel/msm-4.9/drivers/input/fingerprint/so/libgoodixhwfingerprint.so:vendor/lib64/libgoodixhwfingerprint.so 356 | PRODUCT_COPY_FILES += kernel/msm-4.9/drivers/input/fingerprint/so/libvendor.goodix.hardware.biometrics.fingerprint@2.1.so:vendor/lib64/libvendor.goodix.hardware.biometrics.fingerprint@2.1.so 357 | endif 358 | 359 | ifeq ($(SIMCOM_PROJECT),ZANSHANG) 360 | $(call inherit-product-if-exists, vendor/simcom/3rd-party/3rd_party.mk) 361 | endif 362 | 363 | #zhoujian 364 | #For fota support 365 | $(call inherit-product-if-exists, packages/apps/FotaUpdateApp/FotaUpdate.mk) 366 | 367 | # preinstall apps 368 | PRODUCT_COPY_FILES += device/qcom/sdm845/copy_apps.sh:vendor/bin/copy_apps.sh 369 | PRODUCT_COPY_FILES += device/qcom/sdm845/performance.sh:system/bin/performance.sh 370 | 371 | 372 | 373 | # for usb camera 374 | PRODUCT_PACKAGES += android.hardware.camera.provider@2.4-impl 375 | PRODUCT_PACKAGES += android.hardware.camera.provider@2.4-external-service 376 | 377 | PRODUCT_COPY_FILES += \ 378 | device/qcom/sdm845/external_camera_config.xml:$(TARGET_COPY_OUT_VENDOR)/etc/external_camera_config.xml 379 | -------------------------------------------------------------------------------- /frameworks/base/packages/SettingsProvider/res/values/defaults.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | true 21 | 60000 22 | -1 23 | false 24 | false 25 | 26 | cell,bluetooth,wifi,nfc,wimax 27 | bluetooth,wifi,nfc 28 | 0 29 | true 30 | true 31 | false 32 | 33 | 102 34 | false 35 | 100% 36 | 100% 37 | true 38 | 39 | false 40 | false 41 | false 42 | true 43 | 47 | gps 48 | true 49 | true 50 | true 51 | false 52 | 53 | 2 54 | true 55 | true 56 | 57 | false 58 | android/com.android.internal.backup.LocalTransport 59 | 60 | 62 | true 63 | 64 | true 65 | false 66 | true 67 | true 68 | 69 | 70 | 1 71 | /system/media/audio/ui/LowBattery.ogg 72 | 0 73 | 0 74 | /system/media/audio/ui/Dock.ogg 75 | /system/media/audio/ui/Undock.ogg 76 | /system/media/audio/ui/Dock.ogg 77 | /system/media/audio/ui/Undock.ogg 78 | 1 79 | /system/media/audio/ui/Lock.ogg 80 | /system/media/audio/ui/Unlock.ogg 81 | /system/media/audio/ui/Trusted.ogg 82 | /system/media/audio/ui/WirelessChargingStarted.ogg 83 | /system/media/audio/ui/ChargingStarted.ogg 84 | 85 | 86 | 1000 87 | 15000 88 | 89 | false 90 | false 91 | 1 92 | 93 | 94 | true 95 | 96 | 97 | true 98 | 99 | 100 | true 101 | 102 | 103 | true 104 | 105 | 106 | false 107 | 108 | 109 | 200% 110 | 111 | 112 | false 113 | 114 | 115 | true 116 | 117 | 118 | 1 119 | 120 | 121 | -1 122 | 123 | -1 124 | 125 | 126 | 400 127 | 128 | 129 | 300 130 | 131 | 132 | false 133 | 134 | 135 | 0 136 | 137 | 138 | true 139 | 140 | true 141 | 142 | 143 | false 144 | 145 | 147 | 9 148 | 149 | 150 | false 151 | 152 | 155 | 0 156 | 157 | 161 | 162 | 163 | 164 | 0 165 | 166 | 167 | 1 168 | 169 | 170 | true 171 | 172 | 173 | 1 174 | 175 | 176 | %1$s %2$s 177 | 178 | 179 | %1$s 180 | 181 | 182 | true 183 | 184 | 185 | true 186 | 187 | 188 | 189 | 190 | 191 | false 192 | 193 | 194 | 0x2 195 | 196 | 197 | false 198 | 199 | 200 | 201 | 202 | 203 | true 204 | 205 | 206 | 207 | 208 | 213 | 0 214 | 215 | 216 | 217 | 218 | 219 | false 220 | 221 | 222 | persist.vendor.ntp.svr_2 223 | 224 | 2 225 | 226 | 227 | 228 | 255.255.255.0 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 255.255.255.0 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | eth0 248 | dhcp 249 | 250 | 251 | 1 252 | 253 | -------------------------------------------------------------------------------- /frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.android.server.ethernet; 18 | 19 | import static android.net.ConnectivityManager.TYPE_ETHERNET; 20 | 21 | import android.content.Context; 22 | import android.net.IpConfiguration; 23 | import android.net.IpConfiguration.IpAssignment; 24 | import android.net.IpConfiguration.ProxySettings; 25 | import android.net.LinkProperties; 26 | import android.net.NetworkAgent; 27 | import android.net.NetworkCapabilities; 28 | import android.net.NetworkFactory; 29 | import android.net.NetworkInfo; 30 | import android.net.NetworkInfo.DetailedState; 31 | import android.net.NetworkRequest; 32 | import android.net.NetworkSpecifier; 33 | import android.net.StringNetworkSpecifier; 34 | import android.net.ip.IpClient; 35 | import android.net.ip.IpClient.ProvisioningConfiguration; 36 | import android.os.Handler; 37 | import android.text.TextUtils; 38 | import android.util.Log; 39 | 40 | import com.android.internal.util.IndentingPrintWriter; 41 | 42 | import java.io.FileDescriptor; 43 | import java.util.concurrent.ConcurrentHashMap; 44 | 45 | /** 46 | * {@link NetworkFactory} that represents Ethernet networks. 47 | * 48 | * This class reports a static network score of 70 when it is tracking an interface and that 49 | * interface's link is up, and a score of 0 otherwise. 50 | */ 51 | public class EthernetNetworkFactory extends NetworkFactory { 52 | private final static String TAG = EthernetNetworkFactory.class.getSimpleName(); 53 | final static boolean DBG = true; 54 | 55 | private final static int NETWORK_SCORE = 70; 56 | private static final String NETWORK_TYPE = "Ethernet"; 57 | 58 | private final ConcurrentHashMap mTrackingInterfaces = 59 | new ConcurrentHashMap<>(); 60 | private final Handler mHandler; 61 | private final Context mContext; 62 | 63 | public EthernetNetworkFactory(Handler handler, Context context, NetworkCapabilities filter) { 64 | super(handler.getLooper(), context, NETWORK_TYPE, filter); 65 | 66 | if (DBG) { 67 | Log.d(TAG, "EthernetNetworkFactory new"); 68 | } 69 | mHandler = handler; 70 | mContext = context; 71 | 72 | setScoreFilter(NETWORK_SCORE); 73 | } 74 | 75 | @Override 76 | public boolean acceptRequest(NetworkRequest request, int score) { 77 | if (DBG) { 78 | Log.d(TAG, "acceptRequest, request: " + request + ", score: " + score); 79 | } 80 | 81 | return networkForRequest(request) != null; 82 | } 83 | 84 | @Override 85 | protected void needNetworkFor(NetworkRequest networkRequest, int score) { 86 | NetworkInterfaceState network = networkForRequest(networkRequest); 87 | 88 | if (network == null) { 89 | Log.e(TAG, "needNetworkFor, failed to get a network for start" + networkRequest); 90 | return; 91 | } 92 | 93 | if (++network.refCount == 1) { 94 | Log.d(TAG, "+needNetworkFor, " + networkRequest); 95 | 96 | network.start(); 97 | } 98 | } 99 | 100 | @Override 101 | protected void releaseNetworkFor(NetworkRequest networkRequest) { 102 | NetworkInterfaceState network = networkForRequest(networkRequest); 103 | if (network == null) { 104 | Log.e(TAG, "needNetworkFor, failed to get a network for stop" + networkRequest); 105 | return; 106 | } 107 | 108 | if (--network.refCount == 1) { 109 | Log.d(TAG, "-needNetworkFor, " + networkRequest); 110 | network.stop(); 111 | } 112 | } 113 | 114 | /** 115 | * Returns an array of available interface names. The array is sorted: unrestricted interfaces 116 | * goes first, then sorted by name. 117 | */ 118 | String[] getAvailableInterfaces(boolean includeRestricted) { 119 | return mTrackingInterfaces.values() 120 | .stream() 121 | .filter(iface -> !iface.isRestricted() || includeRestricted) 122 | .sorted((iface1, iface2) -> { 123 | int r = Boolean.compare(iface1.isRestricted(), iface2.isRestricted()); 124 | return r == 0 ? iface1.name.compareTo(iface2.name) : r; 125 | }) 126 | .map(iface -> iface.name) 127 | .toArray(String[]::new); 128 | } 129 | 130 | void addInterface(String ifaceName, String hwAddress, NetworkCapabilities capabilities, 131 | IpConfiguration ipConfiguration) { 132 | if (mTrackingInterfaces.containsKey(ifaceName)) { 133 | Log.e(TAG, "Interface with name " + ifaceName + " already exists."); 134 | return; 135 | } 136 | 137 | if (DBG) { 138 | Log.d(TAG, "addInterface, iface: " + ifaceName + ", capabilities: " + capabilities); 139 | } 140 | 141 | NetworkInterfaceState iface = new NetworkInterfaceState( 142 | ifaceName, hwAddress, mHandler, mContext, capabilities); 143 | iface.setIpConfig(ipConfiguration); 144 | mTrackingInterfaces.put(ifaceName, iface); 145 | 146 | updateCapabilityFilter(); 147 | } 148 | 149 | private void updateCapabilityFilter() { 150 | NetworkCapabilities capabilitiesFilter = new NetworkCapabilities(); 151 | capabilitiesFilter.clearAll(); 152 | 153 | for (NetworkInterfaceState iface: mTrackingInterfaces.values()) { 154 | capabilitiesFilter.combineCapabilities(iface.mCapabilities); 155 | } 156 | 157 | if (DBG) Log.d(TAG, "updateCapabilityFilter: " + capabilitiesFilter); 158 | setCapabilityFilter(capabilitiesFilter); 159 | } 160 | 161 | void removeInterface(String interfaceName) { 162 | NetworkInterfaceState iface = mTrackingInterfaces.remove(interfaceName); 163 | if (DBG) { 164 | Log.d(TAG, "removeInterface iface=" + iface + " interfaceName=" + interfaceName); 165 | } 166 | if (iface != null) { 167 | iface.stop(); 168 | } 169 | 170 | updateCapabilityFilter(); 171 | } 172 | 173 | /** Returns true if state has been modified */ 174 | boolean updateInterfaceLinkState(String ifaceName, boolean up) { 175 | if (!mTrackingInterfaces.containsKey(ifaceName)) { 176 | return false; 177 | } 178 | 179 | if (DBG) { 180 | Log.d(TAG, "updateInterfaceLinkState, iface: " + ifaceName + ", up: " + up); 181 | } 182 | 183 | NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName); 184 | return iface.updateLinkState(up); 185 | } 186 | 187 | boolean hasInterface(String interfacName) { 188 | return mTrackingInterfaces.containsKey(interfacName); 189 | } 190 | 191 | void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) { 192 | NetworkInterfaceState network = mTrackingInterfaces.get(iface); 193 | if (network != null) { 194 | network.setIpConfig(ipConfiguration); 195 | } 196 | } 197 | 198 | private NetworkInterfaceState networkForRequest(NetworkRequest request) { 199 | String requestedIface = null; 200 | 201 | NetworkSpecifier specifier = request.networkCapabilities.getNetworkSpecifier(); 202 | if (specifier instanceof StringNetworkSpecifier) { 203 | requestedIface = ((StringNetworkSpecifier) specifier).specifier; 204 | } 205 | 206 | NetworkInterfaceState network = null; 207 | if (!TextUtils.isEmpty(requestedIface)) { 208 | NetworkInterfaceState n = mTrackingInterfaces.get(requestedIface); 209 | if (n != null && n.statisified(request.networkCapabilities)) { 210 | network = n; 211 | } 212 | } else { 213 | for (NetworkInterfaceState n : mTrackingInterfaces.values()) { 214 | if (n.statisified(request.networkCapabilities)) { 215 | network = n; 216 | break; 217 | } 218 | } 219 | } 220 | 221 | if (DBG) { 222 | Log.i(TAG, "networkForRequest, request: " + request + ", network: " + network); 223 | } 224 | 225 | return network; 226 | } 227 | 228 | private static class NetworkInterfaceState { 229 | final String name; 230 | 231 | private final String mHwAddress; 232 | private final NetworkCapabilities mCapabilities; 233 | private final Handler mHandler; 234 | private final Context mContext; 235 | private final NetworkInfo mNetworkInfo; 236 | 237 | private static String sTcpBufferSizes = null; // Lazy initialized. 238 | 239 | private boolean mLinkUp; 240 | private LinkProperties mLinkProperties = new LinkProperties(); 241 | 242 | private IpClient mIpClient; 243 | private NetworkAgent mNetworkAgent; 244 | private IpConfiguration mIpConfig; 245 | 246 | long refCount = 0; 247 | 248 | private final IpClient.Callback mIpClientCallback = new IpClient.Callback() { 249 | @Override 250 | public void onProvisioningSuccess(LinkProperties newLp) { 251 | mHandler.post(() -> onIpLayerStarted(newLp)); 252 | } 253 | 254 | @Override 255 | public void onProvisioningFailure(LinkProperties newLp) { 256 | mHandler.post(() -> onIpLayerStopped(newLp)); 257 | } 258 | 259 | @Override 260 | public void onLinkPropertiesChange(LinkProperties newLp) { 261 | mHandler.post(() -> updateLinkProperties(newLp)); 262 | } 263 | }; 264 | 265 | NetworkInterfaceState(String ifaceName, String hwAddress, Handler handler, Context context, 266 | NetworkCapabilities capabilities) { 267 | name = ifaceName; 268 | mCapabilities = capabilities; 269 | mHandler = handler; 270 | mContext = context; 271 | 272 | mHwAddress = hwAddress; 273 | mNetworkInfo = new NetworkInfo(TYPE_ETHERNET, 0, NETWORK_TYPE, ""); 274 | mNetworkInfo.setExtraInfo(mHwAddress); 275 | mNetworkInfo.setIsAvailable(true); 276 | } 277 | 278 | void setIpConfig(IpConfiguration ipConfig) { 279 | 280 | this.mIpConfig = ipConfig; 281 | } 282 | 283 | boolean statisified(NetworkCapabilities requestedCapabilities) { 284 | return requestedCapabilities.satisfiedByNetworkCapabilities(mCapabilities); 285 | } 286 | 287 | boolean isRestricted() { 288 | return mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 289 | } 290 | 291 | private void start() { 292 | if (mIpClient != null) { 293 | if (DBG) Log.d(TAG, "IpClient already started"); 294 | return; 295 | } 296 | if (DBG) { 297 | Log.d(TAG, String.format("starting IpClient(%s): mNetworkInfo=%s", name, 298 | mNetworkInfo)); 299 | } 300 | 301 | mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddress); 302 | 303 | mIpClient = new IpClient(mContext, name, mIpClientCallback); 304 | 305 | if (sTcpBufferSizes == null) { 306 | sTcpBufferSizes = mContext.getResources().getString( 307 | com.android.internal.R.string.config_ethernet_tcp_buffers); 308 | } 309 | 310 | provisionIpClient(mIpClient, mIpConfig, sTcpBufferSizes); 311 | 312 | } 313 | 314 | void onIpLayerStarted(LinkProperties linkProperties) { 315 | if (mNetworkAgent != null) { 316 | Log.e(TAG, "Already have a NetworkAgent - aborting new request"); 317 | stop(); 318 | return; 319 | } 320 | mLinkProperties = linkProperties; 321 | mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddress); 322 | mNetworkInfo.setIsAvailable(true); 323 | 324 | // Create our NetworkAgent. 325 | mNetworkAgent = new NetworkAgent(mHandler.getLooper(), mContext, 326 | NETWORK_TYPE, mNetworkInfo, mCapabilities, mLinkProperties, 327 | NETWORK_SCORE) { 328 | public void unwanted() { 329 | if (this == mNetworkAgent) { 330 | stop(); 331 | } else if (mNetworkAgent != null) { 332 | Log.d(TAG, "Ignoring unwanted as we have a more modern " + 333 | "instance"); 334 | } // Otherwise, we've already called stop. 335 | } 336 | }; 337 | } 338 | 339 | void onIpLayerStopped(LinkProperties linkProperties) { 340 | // This cannot happen due to provisioning timeout, because our timeout is 0. It can only 341 | // happen if we're provisioned and we lose provisioning. 342 | Log.e(TAG, "onIpLayerStopped"); 343 | stop(); 344 | start(); 345 | } 346 | 347 | void updateLinkProperties(LinkProperties linkProperties) { 348 | mLinkProperties = linkProperties; 349 | if (mNetworkAgent != null) { 350 | mNetworkAgent.sendLinkProperties(linkProperties); 351 | } 352 | } 353 | 354 | /** Returns true if state has been modified */ 355 | boolean updateLinkState(boolean up) { 356 | if (mLinkUp == up) return false; 357 | mLinkUp = up; 358 | 359 | Log.e(TAG, "updateLinkState"); 360 | stop(); 361 | if (up) { 362 | start(); 363 | } 364 | 365 | return true; 366 | } 367 | 368 | void stop() { 369 | if (mIpClient != null) { 370 | mIpClient.shutdown(); 371 | mIpClient.awaitShutdown(); 372 | mIpClient = null; 373 | } 374 | 375 | // ConnectivityService will only forget our NetworkAgent if we send it a NetworkInfo object 376 | // with a state of DISCONNECTED or SUSPENDED. So we can't simply clear our NetworkInfo here: 377 | // that sets the state to IDLE, and ConnectivityService will still think we're connected. 378 | // 379 | mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddress); 380 | if (mNetworkAgent != null) { 381 | updateAgent(); 382 | mNetworkAgent = null; 383 | } 384 | clear(); 385 | } 386 | 387 | private void updateAgent() { 388 | if (mNetworkAgent == null) return; 389 | if (DBG) { 390 | Log.i(TAG, "Updating mNetworkAgent with: " + 391 | mCapabilities + ", " + 392 | mNetworkInfo + ", " + 393 | mLinkProperties); 394 | } 395 | mNetworkAgent.sendNetworkCapabilities(mCapabilities); 396 | mNetworkAgent.sendNetworkInfo(mNetworkInfo); 397 | mNetworkAgent.sendLinkProperties(mLinkProperties); 398 | // never set the network score below 0. 399 | mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0); 400 | } 401 | 402 | private void clear() { 403 | mLinkProperties.clear(); 404 | mNetworkInfo.setDetailedState(DetailedState.IDLE, null, null); 405 | mNetworkInfo.setIsAvailable(false); 406 | } 407 | 408 | private static void provisionIpClient(IpClient ipClient, IpConfiguration config, 409 | String tcpBufferSizes) { 410 | if (config.getProxySettings() == ProxySettings.STATIC || 411 | config.getProxySettings() == ProxySettings.PAC) { 412 | ipClient.setHttpProxy(config.getHttpProxy()); 413 | } 414 | 415 | if (!TextUtils.isEmpty(tcpBufferSizes)) { 416 | ipClient.setTcpBufferSizes(tcpBufferSizes); 417 | } 418 | 419 | final ProvisioningConfiguration provisioningConfiguration; 420 | if (config.getIpAssignment() == IpAssignment.STATIC) { 421 | provisioningConfiguration = IpClient.buildProvisioningConfiguration() 422 | .withStaticConfiguration(config.getStaticIpConfiguration()) 423 | .build(); 424 | } else { 425 | provisioningConfiguration = IpClient.buildProvisioningConfiguration() 426 | .withProvisioningTimeoutMs(0) 427 | .build(); 428 | } 429 | 430 | ipClient.startProvisioning(provisioningConfiguration); 431 | } 432 | 433 | @Override 434 | public String toString() { 435 | return getClass().getSimpleName() + "{ " 436 | + "iface: " + name + ", " 437 | + "up: " + mLinkUp + ", " 438 | + "hwAddress: " + mHwAddress + ", " 439 | + "networkInfo: " + mNetworkInfo + ", " 440 | + "networkAgent: " + mNetworkAgent + ", " 441 | + "ipClient: " + mIpClient + "," 442 | + "linkProperties: " + mLinkProperties 443 | + "}"; 444 | } 445 | } 446 | 447 | void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) { 448 | super.dump(fd, pw, args); 449 | pw.println(getClass().getSimpleName()); 450 | pw.println("Tracking interfaces:"); 451 | pw.increaseIndent(); 452 | for (String iface: mTrackingInterfaces.keySet()) { 453 | NetworkInterfaceState ifaceState = mTrackingInterfaces.get(iface); 454 | pw.println(iface + ":" + ifaceState); 455 | pw.increaseIndent(); 456 | final IpClient ipClient = ifaceState.mIpClient; 457 | if (ipClient != null) { 458 | ipClient.dump(fd, pw, args); 459 | } else { 460 | pw.println("IpClient is null"); 461 | } 462 | pw.decreaseIndent(); 463 | } 464 | pw.decreaseIndent(); 465 | } 466 | } 467 | -------------------------------------------------------------------------------- /frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetServiceImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.android.server.ethernet; 18 | 19 | import android.content.Context; 20 | import android.content.pm.PackageManager; 21 | import android.net.EthernetManager; 22 | import android.net.IEthernetManager; 23 | import android.net.IEthernetServiceListener; 24 | import android.net.IpConfiguration; 25 | import android.os.Binder; 26 | import android.os.Handler; 27 | import android.os.HandlerThread; 28 | import android.os.Looper; 29 | import android.os.RemoteException; 30 | import android.util.Log; 31 | import android.util.PrintWriterPrinter; 32 | 33 | import com.android.internal.util.IndentingPrintWriter; 34 | 35 | import java.io.FileDescriptor; 36 | import java.io.PrintWriter; 37 | import java.util.concurrent.atomic.AtomicBoolean; 38 | 39 | import android.net.Uri; 40 | import android.provider.Settings.System; 41 | import android.net.StaticIpConfiguration; 42 | import android.net.LinkAddress; 43 | import java.net.InetAddress; 44 | import android.provider.Settings; 45 | /** 46 | * EthernetServiceImpl handles remote Ethernet operation requests by implementing 47 | * the IEthernetManager interface. 48 | */ 49 | public class EthernetServiceImpl extends IEthernetManager.Stub { 50 | private static final String TAG = "EthernetServiceImpl"; 51 | 52 | private final Context mContext; 53 | private final AtomicBoolean mStarted = new AtomicBoolean(false); 54 | 55 | private Handler mHandler; 56 | private EthernetTracker mTracker; 57 | 58 | public EthernetServiceImpl(Context context) { 59 | mContext = context; 60 | } 61 | 62 | private void enforceAccessPermission() { 63 | mContext.enforceCallingOrSelfPermission( 64 | android.Manifest.permission.ACCESS_NETWORK_STATE, 65 | "EthernetService"); 66 | } 67 | 68 | private void enforceConnectivityInternalPermission() { 69 | mContext.enforceCallingOrSelfPermission( 70 | android.Manifest.permission.CONNECTIVITY_INTERNAL, 71 | "ConnectivityService"); 72 | } 73 | 74 | private void enforceUseRestrictedNetworksPermission() { 75 | mContext.enforceCallingOrSelfPermission( 76 | android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS, 77 | "ConnectivityService"); 78 | } 79 | 80 | private boolean checkUseRestrictedNetworksPermission() { 81 | return mContext.checkCallingOrSelfPermission( 82 | android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS) 83 | == PackageManager.PERMISSION_GRANTED; 84 | } 85 | 86 | public void start() { 87 | Log.i(TAG, "Starting Ethernet service"); 88 | 89 | HandlerThread handlerThread = new HandlerThread("EthernetServiceThread"); 90 | handlerThread.start(); 91 | mHandler = new Handler(handlerThread.getLooper()); 92 | 93 | int enable = Settings.Global.getInt(mContext.getContentResolver(), 94 | Settings.Global.ETHERNET_ON, 0); 95 | if(enable != EthernetManager.ETHERNET_STATE_ENABLED) { 96 | Log.i(TAG, "Ethernet is not enable"); 97 | return; 98 | } 99 | 100 | mTracker = new EthernetTracker(mContext, mHandler); 101 | mTracker.start(); 102 | 103 | mStarted.set(true); 104 | } 105 | public void trackStart() { 106 | Log.i(TAG, "trackStart"); 107 | new Thread(new Runnable() { 108 | public void run() { 109 | Looper.prepare(); 110 | if(null == mTracker){ 111 | Log.i(TAG, "Starting EthernetTracker"); 112 | mTracker = new EthernetTracker(mContext, mHandler); 113 | mTracker.start(); 114 | mStarted.set(true); 115 | }else{ 116 | mTracker.enable(); 117 | } 118 | Looper.loop(); 119 | } 120 | }).start();; 121 | } 122 | 123 | public void trackStop() { 124 | Log.i(TAG, "trackStop"); 125 | new Thread(new Runnable() { 126 | public void run() { 127 | Looper.prepare(); 128 | mTracker.disable(); 129 | Looper.loop(); 130 | } 131 | }).start();; 132 | } 133 | 134 | @Override 135 | public String[] getAvailableInterfaces() throws RemoteException { 136 | return mTracker.getInterfaces(checkUseRestrictedNetworksPermission()); 137 | } 138 | 139 | /** 140 | * Get Ethernet configuration 141 | * @return the Ethernet Configuration, contained in {@link IpConfiguration}. 142 | */ 143 | @Override 144 | public IpConfiguration getConfiguration(String iface) { 145 | enforceAccessPermission(); 146 | 147 | if (mTracker.isRestrictedInterface(iface)) { 148 | enforceUseRestrictedNetworksPermission(); 149 | } 150 | 151 | return new IpConfiguration(mTracker.getIpConfiguration(iface)); 152 | } 153 | 154 | /** 155 | * Set Ethernet configuration 156 | */ 157 | @Override 158 | public void setConfiguration(String iface, IpConfiguration config) { 159 | if (!mStarted.get()) { 160 | Log.w(TAG, "System isn't ready enough to change ethernet configuration"); 161 | } 162 | 163 | enforceConnectivityInternalPermission(); 164 | 165 | if (mTracker.isRestrictedInterface(iface)) { 166 | enforceUseRestrictedNetworksPermission(); 167 | } 168 | 169 | // TODO: this does not check proxy settings, gateways, etc. 170 | // Fix this by making IpConfiguration a complete representation of static configuration. 171 | mTracker.updateIpConfiguration(iface, new IpConfiguration(config)); 172 | } 173 | 174 | /** 175 | * Indicates whether given interface is available. 176 | */ 177 | @Override 178 | public boolean isAvailable(String iface) { 179 | enforceAccessPermission(); 180 | 181 | if (mTracker.isRestrictedInterface(iface)) { 182 | enforceUseRestrictedNetworksPermission(); 183 | } 184 | 185 | return mTracker.isTrackingInterface(iface); 186 | } 187 | 188 | /** 189 | * Adds a listener. 190 | * @param listener A {@link IEthernetServiceListener} to add. 191 | */ 192 | public void addListener(IEthernetServiceListener listener) { 193 | if (listener == null) { 194 | throw new IllegalArgumentException("listener must not be null"); 195 | } 196 | enforceAccessPermission(); 197 | mTracker.addListener(listener, checkUseRestrictedNetworksPermission()); 198 | } 199 | 200 | /** 201 | * Removes a listener. 202 | * @param listener A {@link IEthernetServiceListener} to remove. 203 | */ 204 | public void removeListener(IEthernetServiceListener listener) { 205 | if (listener == null) { 206 | throw new IllegalArgumentException("listener must not be null"); 207 | } 208 | enforceAccessPermission(); 209 | mTracker.removeListener(listener); 210 | } 211 | 212 | @Override 213 | protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 214 | final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 215 | if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 216 | != PackageManager.PERMISSION_GRANTED) { 217 | pw.println("Permission Denial: can't dump EthernetService from pid=" 218 | + Binder.getCallingPid() 219 | + ", uid=" + Binder.getCallingUid()); 220 | return; 221 | } 222 | 223 | pw.println("Current Ethernet state: "); 224 | pw.increaseIndent(); 225 | mTracker.dump(fd, pw, args); 226 | pw.decreaseIndent(); 227 | 228 | pw.println("Handler:"); 229 | pw.increaseIndent(); 230 | mHandler.dump(new PrintWriterPrinter(pw), "EthernetServiceImpl"); 231 | pw.decreaseIndent(); 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetTracker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.android.server.ethernet; 18 | 19 | import android.annotation.Nullable; 20 | import android.content.Context; 21 | import android.net.IEthernetServiceListener; 22 | import android.net.InterfaceConfiguration; 23 | import android.net.IpConfiguration; 24 | import android.net.IpConfiguration.IpAssignment; 25 | import android.net.IpConfiguration.ProxySettings; 26 | import android.net.LinkAddress; 27 | import android.net.NetworkCapabilities; 28 | import android.net.StaticIpConfiguration; 29 | import android.os.Handler; 30 | import android.os.IBinder; 31 | import android.os.INetworkManagementService; 32 | import android.os.RemoteCallbackList; 33 | import android.os.RemoteException; 34 | import android.os.ServiceManager; 35 | import android.text.TextUtils; 36 | import android.util.ArrayMap; 37 | import android.util.Log; 38 | import android.provider.Settings; 39 | 40 | import com.android.internal.annotations.VisibleForTesting; 41 | import com.android.internal.util.IndentingPrintWriter; 42 | import com.android.server.net.BaseNetworkObserver; 43 | 44 | import java.io.FileDescriptor; 45 | import java.net.InetAddress; 46 | import java.util.ArrayList; 47 | import java.util.concurrent.ConcurrentHashMap; 48 | 49 | /** 50 | * Tracks Ethernet interfaces and manages interface configurations. 51 | * 52 | *

Interfaces may have different {@link android.net.NetworkCapabilities}. This mapping is defined 53 | * in {@code config_ethernet_interfaces}. Notably, some interfaces could be marked as restricted by 54 | * not specifying {@link android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED} flag. 55 | * Interfaces could have associated {@link android.net.IpConfiguration}. 56 | * Ethernet Interfaces may be present at boot time or appear after boot (e.g., for Ethernet adapters 57 | * connected over USB). This class supports multiple interfaces. When an interface appears on the 58 | * system (or is present at boot time) this class will start tracking it and bring it up. Only 59 | * interfaces whose names match the {@code config_ethernet_iface_regex} regular expression are 60 | * tracked. 61 | * 62 | *

All public or package private methods must be thread-safe unless stated otherwise. 63 | */ 64 | final class EthernetTracker { 65 | private final static String TAG = EthernetTracker.class.getSimpleName(); 66 | private final static boolean DBG = EthernetNetworkFactory.DBG; 67 | 68 | /** Product-dependent regular expression of interface names we track. */ 69 | private final String mIfaceMatch; 70 | 71 | /** Mapping between {iface name | mac address} -> {NetworkCapabilities} */ 72 | private final ConcurrentHashMap mNetworkCapabilities = 73 | new ConcurrentHashMap<>(); 74 | private final ConcurrentHashMap mIpConfigurations = 75 | new ConcurrentHashMap<>(); 76 | 77 | private final INetworkManagementService mNMService; 78 | private final Handler mHandler; 79 | private final EthernetNetworkFactory mFactory; 80 | private final EthernetConfigStore mConfigStore; 81 | private InterfaceObserver mInterfaceObserver; 82 | private boolean mEnabled; 83 | 84 | private final RemoteCallbackList mListeners = 85 | new RemoteCallbackList<>(); 86 | 87 | private volatile IpConfiguration mIpConfigForDefaultInterface; 88 | 89 | EthernetTracker(Context context, Handler handler) { 90 | if (DBG) { 91 | Log.d(TAG, "EthernetTracker new"); 92 | } 93 | mHandler = handler; 94 | 95 | // The services we use. 96 | IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 97 | mNMService = INetworkManagementService.Stub.asInterface(b); 98 | 99 | // Interface match regex. 100 | mIfaceMatch = context.getResources().getString( 101 | com.android.internal.R.string.config_ethernet_iface_regex); 102 | 103 | // Read default Ethernet interface configuration from resources 104 | final String[] interfaceConfigs = context.getResources().getStringArray( 105 | com.android.internal.R.array.config_ethernet_interfaces); 106 | for (String strConfig : interfaceConfigs) { 107 | parseEthernetConfig(strConfig); 108 | } 109 | 110 | mConfigStore = new EthernetConfigStore(); 111 | 112 | NetworkCapabilities nc = createNetworkCapabilities(true /* clear default capabilities */); 113 | mFactory = new EthernetNetworkFactory(handler, context, nc); 114 | mFactory.register(); 115 | } 116 | 117 | void start() { 118 | if (DBG) { 119 | Log.d(TAG, "EthernetTracker start"); 120 | } 121 | mConfigStore.read(); 122 | 123 | // Default interface is just the first one we want to track. 124 | mIpConfigForDefaultInterface = mConfigStore.getIpConfigurationForDefaultInterface(); 125 | final ArrayMap configs = mConfigStore.getIpConfigurations(); 126 | for (int i = 0; i < configs.size(); i++) { 127 | mIpConfigurations.put(configs.keyAt(i), configs.valueAt(i)); 128 | } 129 | 130 | mInterfaceObserver = new InterfaceObserver(); 131 | try { 132 | mNMService.registerObserver(mInterfaceObserver); 133 | } catch (RemoteException e) { 134 | Log.e(TAG, "Could not register InterfaceObserver " + e); 135 | } 136 | 137 | mEnabled = true; 138 | mHandler.post(this::trackAvailableInterfaces); 139 | } 140 | 141 | void enable(){ 142 | if (DBG) { 143 | Log.d(TAG, "EthernetTracker enable"); 144 | } 145 | 146 | //mFactory.register(); 147 | 148 | mEnabled = true; 149 | mHandler.post(this::trackAvailableInterfaces); 150 | if(isTrackingInterface(Settings.Global.INTERFACE_ETH0)){ 151 | updateInterfaceState(Settings.Global.INTERFACE_ETH0,true); 152 | } 153 | 154 | if(isTrackingInterface(Settings.Global.INTERFACE_ETH1)){ 155 | updateInterfaceState(Settings.Global.INTERFACE_ETH1,true); 156 | } 157 | } 158 | 159 | void disable(){ 160 | if (DBG) { 161 | Log.d(TAG, "EthernetTracker disable"); 162 | } 163 | updateInterfaceState(Settings.Global.INTERFACE_ETH0,false); 164 | updateInterfaceState(Settings.Global.INTERFACE_ETH1,false); 165 | 166 | //mFactory.unregister(); 167 | mEnabled = false; 168 | 169 | } 170 | 171 | void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) { 172 | if (DBG) { 173 | Log.i(TAG, "updateIpConfiguration, iface: " + iface + ", cfg: " + ipConfiguration); 174 | } 175 | 176 | mConfigStore.write(iface, ipConfiguration); 177 | mIpConfigurations.put(iface, ipConfiguration); 178 | 179 | mHandler.post(() -> mFactory.updateIpConfiguration(iface, ipConfiguration)); 180 | } 181 | 182 | IpConfiguration getIpConfiguration(String iface) { 183 | return mIpConfigurations.get(iface); 184 | } 185 | 186 | boolean isTrackingInterface(String iface) { 187 | return mFactory.hasInterface(iface); 188 | } 189 | 190 | String[] getInterfaces(boolean includeRestricted) { 191 | return mFactory.getAvailableInterfaces(includeRestricted); 192 | } 193 | 194 | /** 195 | * Returns true if given interface was configured as restricted (doesn't have 196 | * NET_CAPABILITY_NOT_RESTRICTED) capability. Otherwise, returns false. 197 | */ 198 | boolean isRestrictedInterface(String iface) { 199 | final NetworkCapabilities nc = mNetworkCapabilities.get(iface); 200 | return nc != null && !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 201 | } 202 | 203 | void addListener(IEthernetServiceListener listener, boolean canUseRestrictedNetworks) { 204 | mListeners.register(listener, new ListenerInfo(canUseRestrictedNetworks)); 205 | } 206 | 207 | void removeListener(IEthernetServiceListener listener) { 208 | mListeners.unregister(listener); 209 | } 210 | 211 | private void removeInterface(String iface) { 212 | mFactory.removeInterface(iface); 213 | } 214 | 215 | private void addInterface(String iface) { 216 | InterfaceConfiguration config = null; 217 | // Bring up the interface so we get link status indications. 218 | try { 219 | mNMService.setInterfaceUp(iface); 220 | config = mNMService.getInterfaceConfig(iface); 221 | } catch (RemoteException | IllegalStateException e) { 222 | // Either the system is crashing or the interface has disappeared. Just ignore the 223 | // error; we haven't modified any state because we only do that if our calls succeed. 224 | Log.e(TAG, "Error upping interface " + iface, e); 225 | } 226 | 227 | if (config == null) { 228 | Log.e(TAG, "Null interface config for " + iface + ". Bailing out."); 229 | return; 230 | } 231 | 232 | final String hwAddress = config.getHardwareAddress(); 233 | 234 | NetworkCapabilities nc = mNetworkCapabilities.get(iface); 235 | if (nc == null) { 236 | // Try to resolve using mac address 237 | nc = mNetworkCapabilities.get(hwAddress); 238 | if (nc == null) { 239 | nc = createDefaultNetworkCapabilities(); 240 | } 241 | } 242 | IpConfiguration ipConfiguration = mIpConfigurations.get(iface); 243 | if (ipConfiguration == null) { 244 | ipConfiguration = createDefaultIpConfiguration(); 245 | } 246 | 247 | Log.d(TAG, "Started tracking interface " + iface); 248 | mFactory.addInterface(iface, hwAddress, nc, ipConfiguration); 249 | 250 | if(iface.equals(Settings.Global.INTERFACE_ETH0)){ 251 | return; 252 | } 253 | 254 | if(iface.equals(Settings.Global.INTERFACE_ETH1)){ 255 | return; 256 | } 257 | // Note: if the interface already has link (e.g., if we crashed and got 258 | // restarted while it was running), we need to fake a link up notification so we 259 | // start configuring it. 260 | if (config.hasFlag("running")) { 261 | updateInterfaceState(iface, true); 262 | } 263 | } 264 | 265 | private void updateInterfaceState(String iface, boolean up) { 266 | if(!mEnabled && up){ 267 | return; 268 | } 269 | boolean modified = mFactory.updateInterfaceLinkState(iface, up); 270 | if (modified) { 271 | boolean restricted = isRestrictedInterface(iface); 272 | int n = mListeners.beginBroadcast(); 273 | for (int i = 0; i < n; i++) { 274 | try { 275 | if (restricted) { 276 | ListenerInfo listenerInfo = (ListenerInfo) mListeners.getBroadcastCookie(i); 277 | if (!listenerInfo.canUseRestrictedNetworks) { 278 | continue; 279 | } 280 | } 281 | mListeners.getBroadcastItem(i).onAvailabilityChanged(iface, up); 282 | } catch (RemoteException e) { 283 | // Do nothing here. 284 | } 285 | } 286 | mListeners.finishBroadcast(); 287 | } 288 | } 289 | 290 | private void maybeTrackInterface(String iface) { 291 | if (DBG) Log.i(TAG, "maybeTrackInterface " + iface); 292 | // If we don't already track this interface, and if this interface matches 293 | // our regex, start tracking it. 294 | if (!iface.matches(mIfaceMatch) || mFactory.hasInterface(iface)) { 295 | return; 296 | } 297 | 298 | if (mIpConfigForDefaultInterface != null) { 299 | updateIpConfiguration(iface, mIpConfigForDefaultInterface); 300 | mIpConfigForDefaultInterface = null; 301 | } 302 | 303 | addInterface(iface); 304 | } 305 | 306 | private void trackAvailableInterfaces() { 307 | try { 308 | final String[] ifaces = mNMService.listInterfaces(); 309 | for (String iface : ifaces) { 310 | maybeTrackInterface(iface); 311 | } 312 | } catch (RemoteException | IllegalStateException e) { 313 | Log.e(TAG, "Could not get list of interfaces " + e); 314 | } 315 | } 316 | 317 | 318 | private class InterfaceObserver extends BaseNetworkObserver { 319 | 320 | @Override 321 | public void interfaceLinkStateChanged(String iface, boolean up) { 322 | if (DBG) { 323 | Log.i(TAG, "interfaceLinkStateChanged, iface: " + iface + ", up: " + up); 324 | } 325 | mHandler.post(() -> updateInterfaceState(iface, up)); 326 | } 327 | 328 | @Override 329 | public void interfaceAdded(String iface) { 330 | mHandler.post(() -> maybeTrackInterface(iface)); 331 | } 332 | 333 | @Override 334 | public void interfaceRemoved(String iface) { 335 | mHandler.post(() -> removeInterface(iface)); 336 | } 337 | } 338 | 339 | private static class ListenerInfo { 340 | 341 | boolean canUseRestrictedNetworks = false; 342 | 343 | ListenerInfo(boolean canUseRestrictedNetworks) { 344 | this.canUseRestrictedNetworks = canUseRestrictedNetworks; 345 | } 346 | } 347 | 348 | private void parseEthernetConfig(String configString) { 349 | String[] tokens = configString.split(";"); 350 | String name = tokens[0]; 351 | String capabilities = tokens.length > 1 ? tokens[1] : null; 352 | NetworkCapabilities nc = createNetworkCapabilities( 353 | !TextUtils.isEmpty(capabilities) /* clear default capabilities */, capabilities); 354 | mNetworkCapabilities.put(name, nc); 355 | 356 | if (tokens.length > 2 && !TextUtils.isEmpty(tokens[2])) { 357 | IpConfiguration ipConfig = parseStaticIpConfiguration(tokens[2]); 358 | mIpConfigurations.put(name, ipConfig); 359 | } 360 | } 361 | 362 | private static NetworkCapabilities createDefaultNetworkCapabilities() { 363 | NetworkCapabilities nc = createNetworkCapabilities(false /* clear default capabilities */); 364 | nc.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 365 | nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 366 | nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); 367 | nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); 368 | nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); 369 | 370 | return nc; 371 | } 372 | 373 | private static NetworkCapabilities createNetworkCapabilities(boolean clearDefaultCapabilities) { 374 | return createNetworkCapabilities(clearDefaultCapabilities, null); 375 | } 376 | 377 | private static NetworkCapabilities createNetworkCapabilities( 378 | boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities) { 379 | 380 | NetworkCapabilities nc = new NetworkCapabilities(); 381 | if (clearDefaultCapabilities) { 382 | nc.clearAll(); // Remove default capabilities. 383 | } 384 | nc.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET); 385 | nc.setLinkUpstreamBandwidthKbps(100 * 1000); 386 | nc.setLinkDownstreamBandwidthKbps(100 * 1000); 387 | 388 | if (!TextUtils.isEmpty(commaSeparatedCapabilities)) { 389 | for (String strNetworkCapability : commaSeparatedCapabilities.split(",")) { 390 | if (!TextUtils.isEmpty(strNetworkCapability)) { 391 | nc.addCapability(Integer.valueOf(strNetworkCapability)); 392 | } 393 | } 394 | } 395 | 396 | return nc; 397 | } 398 | 399 | /** 400 | * Parses static IP configuration. 401 | * 402 | * @param staticIpConfig represents static IP configuration in the following format: {@code 403 | * ip= gateway= dns= 404 | * domains=} 405 | */ 406 | @VisibleForTesting 407 | static IpConfiguration parseStaticIpConfiguration(String staticIpConfig) { 408 | StaticIpConfiguration ipConfig = new StaticIpConfiguration(); 409 | 410 | for (String keyValueAsString : staticIpConfig.trim().split(" ")) { 411 | if (TextUtils.isEmpty(keyValueAsString)) continue; 412 | 413 | String[] pair = keyValueAsString.split("="); 414 | if (pair.length != 2) { 415 | throw new IllegalArgumentException("Unexpected token: " + keyValueAsString 416 | + " in " + staticIpConfig); 417 | } 418 | 419 | String key = pair[0]; 420 | String value = pair[1]; 421 | 422 | switch (key) { 423 | case "ip": 424 | ipConfig.ipAddress = new LinkAddress(value); 425 | break; 426 | case "domains": 427 | ipConfig.domains = value; 428 | break; 429 | case "gateway": 430 | ipConfig.gateway = InetAddress.parseNumericAddress(value); 431 | break; 432 | case "dns": { 433 | ArrayList dnsAddresses = new ArrayList<>(); 434 | for (String address: value.split(",")) { 435 | dnsAddresses.add(InetAddress.parseNumericAddress(address)); 436 | } 437 | ipConfig.dnsServers.addAll(dnsAddresses); 438 | break; 439 | } 440 | default : { 441 | throw new IllegalArgumentException("Unexpected key: " + key 442 | + " in " + staticIpConfig); 443 | } 444 | } 445 | } 446 | return new IpConfiguration(IpAssignment.STATIC, ProxySettings.NONE, ipConfig, null); 447 | } 448 | 449 | private static IpConfiguration createDefaultIpConfiguration() { 450 | return new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null); 451 | } 452 | 453 | private void postAndWaitForRunnable(Runnable r) { 454 | mHandler.runWithScissors(r, 2000L /* timeout */); 455 | } 456 | 457 | void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) { 458 | postAndWaitForRunnable(() -> { 459 | pw.println(getClass().getSimpleName()); 460 | pw.println("Ethernet interface name filter: " + mIfaceMatch); 461 | pw.println("Listeners: " + mListeners.getRegisteredCallbackCount()); 462 | pw.println("IP Configurations:"); 463 | pw.increaseIndent(); 464 | for (String iface : mIpConfigurations.keySet()) { 465 | pw.println(iface + ": " + mIpConfigurations.get(iface)); 466 | } 467 | pw.decreaseIndent(); 468 | pw.println(); 469 | 470 | pw.println("Network Capabilities:"); 471 | pw.increaseIndent(); 472 | for (String iface : mNetworkCapabilities.keySet()) { 473 | pw.println(iface + ": " + mNetworkCapabilities.get(iface)); 474 | } 475 | pw.decreaseIndent(); 476 | pw.println(); 477 | 478 | mFactory.dump(fd, pw, args); 479 | }); 480 | } 481 | } 482 | -------------------------------------------------------------------------------- /packages/apps/Settings/res/layout/ethernet_configure.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 17 | 18 | 19 | 20 | 21 | 28 | 29 | 33 | 34 | 40 | 41 | 42 | 48 | 49 | 50 | 51 | 58 | 62 | 63 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 88 | 89 | 96 | 97 | 102 | 103 | 110 | 111 | 116 | 117 | 118 | 125 | 126 | 131 | 132 | 139 | 140 | 145 | 146 | 153 | 154 | 159 | 160 | 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /packages/apps/Settings/src/com/android/settings/ethernet/EthernetDialog.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 SIMCOM Corp. 3 | * 4 | * The main interface to control ethernet setting param. 5 | * Athor: Mr. Tsao Bo, SIMCOM. 6 | * Restructured on 2020.11.10, for USB ethernet( A.K.A, eth1 ) connection. 7 | * 8 | */ 9 | 10 | package com.android.settings.ethernet; 11 | 12 | import com.android.settings.R; 13 | import com.android.settings.ethernet.ip.IPView; 14 | 15 | import android.app.AlertDialog; 16 | import android.content.Context; 17 | import android.content.DialogInterface; 18 | import android.os.Bundle; 19 | import android.view.View; 20 | import android.widget.Button; 21 | import android.widget.EditText; 22 | import android.widget.CompoundButton; 23 | import android.widget.RadioButton; 24 | import android.util.Log; 25 | import android.view.inputmethod.InputMethodManager; 26 | import android.net.IpConfiguration; 27 | import android.net.IpConfiguration.IpAssignment; 28 | import android.net.IpConfiguration.ProxySettings; 29 | import android.os.Environment; 30 | import android.util.SparseArray; 31 | import android.net.StaticIpConfiguration; 32 | import android.net.EthernetManager; 33 | import android.text.TextUtils; 34 | import android.net.LinkAddress; 35 | import android.net.NetworkUtils; 36 | import android.net.ConnectivityManager; 37 | import android.net.LinkProperties; 38 | import android.os.RemoteException; 39 | import com.android.settings.Utils; 40 | import android.widget.Toast; 41 | import android.net.EthernetManager; 42 | import android.provider.Settings.Global; 43 | import com.zanshang.wifi.ExtraWifiService; 44 | import android.provider.Settings; 45 | import android.widget.Button; 46 | 47 | 48 | import java.net.InetAddress; 49 | import java.net.Inet4Address; 50 | import java.net.UnknownHostException; 51 | import java.util.Iterator; 52 | import java.util.regex.Pattern; 53 | 54 | 55 | class EthernetDialog extends AlertDialog implements DialogInterface.OnClickListener, DialogInterface.OnShowListener, 56 | DialogInterface.OnDismissListener{ 57 | private final String TAG = "EthernetDialog"; 58 | private static final boolean localLOGV = true; 59 | 60 | 61 | private View mView; 62 | private RadioButton mIpTypeDhcp; 63 | private RadioButton mIpTypeManual; 64 | private RadioButton eth0Radio; 65 | private RadioButton eth1Radio; 66 | 67 | private StaticIpViews mStaticIpViews; 68 | private RJ45StaticIpViews mRJ45StaticIpViews; 69 | private UsbCardStaticIpViews mUsbCardStaticIpViews; 70 | 71 | 72 | private Context mContext; 73 | private EthernetManager mEthManager; 74 | private ConnectivityManager mCM; 75 | 76 | public EthernetDialog(Context context,EthernetManager EthManager,ConnectivityManager cm) { 77 | super(context); 78 | mContext = context; 79 | mEthManager = EthManager; 80 | mCM = cm; 81 | 82 | createDialogContent(); 83 | 84 | setOnShowListener(this); 85 | setOnDismissListener(this); 86 | 87 | } 88 | 89 | public void onShow(DialogInterface dialog) { 90 | if (localLOGV) Log.d(TAG, "onShow"); 91 | 92 | UpdateViewContent(); 93 | 94 | // soft keyboard pops up on the disabled EditText. Hide it. 95 | InputMethodManager imm = (InputMethodManager)mContext.getSystemService( 96 | Context.INPUT_METHOD_SERVICE); 97 | imm.hideSoftInputFromWindow(mView.getWindowToken(), 98 | InputMethodManager.HIDE_IMPLICIT_ONLY); 99 | 100 | /* Tsao Bo:The reason we listen click event on postive_button's View rather than the button */ 101 | /* is because we'd like to manually handle the dialog dismiss.*/ 102 | Button positive_button = getButton(BUTTON_POSITIVE); 103 | positive_button.setOnClickListener(new View.OnClickListener() { 104 | @Override 105 | public void onClick(View v) { 106 | handle_saveconf(); 107 | } 108 | }); 109 | } 110 | 111 | public void onClick(DialogInterface dialog, int which){ 112 | 113 | } 114 | 115 | public void onDismiss(DialogInterface dialog) { 116 | if (localLOGV) Log.d(TAG, "onDismiss"); 117 | } 118 | 119 | private void createDialogContent() { 120 | this.setTitle(R.string.eth_config_title); 121 | this.setView(mView = getLayoutInflater().inflate(R.layout.ethernet_configure, null)); 122 | 123 | eth0Radio = (RadioButton) mView.findViewById(R.id.eth0_radio); 124 | eth1Radio = (RadioButton) mView.findViewById(R.id.eth1_radio); 125 | 126 | mIpTypeDhcp = (RadioButton) mView.findViewById(R.id.dhcp_radio); 127 | mIpTypeManual = (RadioButton) mView.findViewById(R.id.manual_radio); 128 | 129 | IPView Ipaddr = (IPView)mView.findViewById(R.id.ipaddr_edit); 130 | IPView NetMask = (IPView)mView.findViewById(R.id.mask_edit); 131 | IPView Gw = (IPView)mView.findViewById(R.id.eth_gw_edit); 132 | IPView Dns1 = (IPView)mView.findViewById(R.id.eth_dns_edit1); 133 | IPView Dns2 = (IPView)mView.findViewById(R.id.eth_dns_edit2); 134 | 135 | mRJ45StaticIpViews = new RJ45StaticIpViews(Ipaddr,NetMask,Gw,Dns1,Dns2); 136 | mUsbCardStaticIpViews = new UsbCardStaticIpViews(Ipaddr,NetMask,Gw,Dns1,Dns2); 137 | 138 | String ifaceType = getInterfaceSetting(); 139 | if(ifaceType.equals(Settings.Global.INTERFACE_ETH0)){ 140 | mStaticIpViews = mRJ45StaticIpViews; 141 | }else{ 142 | mStaticIpViews = mUsbCardStaticIpViews; 143 | } 144 | mStaticIpViews.disableAllViews(); 145 | 146 | setButton(BUTTON_POSITIVE, mContext.getText(R.string.menu_save), (DialogInterface.OnClickListener)null); 147 | setButton(BUTTON_NEGATIVE, mContext.getText(R.string.menu_cancel), this); 148 | 149 | updateRadioButtonState(); 150 | 151 | setInverseBackgroundForced(true); 152 | 153 | 154 | eth0Radio.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 155 | @Override 156 | public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) { 157 | Log.i("eth0Radio","onCheckedChanged isChecked:"+isChecked); 158 | if(isChecked){ 159 | mStaticIpViews = mRJ45StaticIpViews; 160 | 161 | setInterfaceSetting(Settings.Global.INTERFACE_ETH0); 162 | 163 | updateIpTypeRadioButtonState(); 164 | mStaticIpViews.clearAllViews(); 165 | mStaticIpViews.loadSettings(); 166 | } 167 | } 168 | }); 169 | 170 | eth1Radio.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 171 | @Override 172 | public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) { 173 | Log.i("eth1Radio","onCheckedChanged isChecked:"+isChecked); 174 | if(isChecked){ 175 | mStaticIpViews = mUsbCardStaticIpViews; 176 | 177 | setInterfaceSetting(Settings.Global.INTERFACE_ETH1); 178 | 179 | updateIpTypeRadioButtonState(); 180 | mStaticIpViews.clearAllViews(); 181 | mStaticIpViews.loadSettings(); 182 | } 183 | } 184 | }); 185 | 186 | mIpTypeDhcp.setOnClickListener(new RadioButton.OnClickListener() { 187 | public void onClick(View v) { 188 | mStaticIpViews.setIpTypeSetting(Settings.Global.TYPE_DHCP); 189 | 190 | mStaticIpViews.disableAllViews(); 191 | mStaticIpViews.clearAllViews(); 192 | } 193 | }); 194 | 195 | mIpTypeManual.setOnClickListener(new RadioButton.OnClickListener() { 196 | public void onClick(View v) { 197 | mStaticIpViews.setIpTypeSetting(Settings.Global.TYPE_STATIC); 198 | 199 | mStaticIpViews.enableAllViews(); 200 | mStaticIpViews.clearAllViews(); 201 | mStaticIpViews.loadSettings(); 202 | } 203 | }); 204 | 205 | UpdateViewContent(); 206 | 207 | } 208 | 209 | private void UpdateViewContent() { 210 | int enable = Global.getInt(mContext.getContentResolver(), Global.ETHERNET_ON, EthernetManager.ETHERNET_STATE_UNKNOWN); 211 | if (localLOGV) Log.d(TAG, "UpdateViewContent enable=" + enable); 212 | 213 | if(enable == EthernetManager.ETHERNET_STATE_ENABLED) { 214 | String ifaceType = getInterfaceSetting(); 215 | 216 | IpConfiguration ipinfo = mEthManager.getConfiguration(ifaceType); 217 | 218 | if((ipinfo.ipAssignment == IpAssignment.DHCP) ||(ipinfo.ipAssignment == IpAssignment.UNASSIGNED) ) { 219 | mIpTypeDhcp.setChecked(true); 220 | mStaticIpViews.disableAllViews(); 221 | mStaticIpViews.clearAllViews(); 222 | } else { 223 | mIpTypeManual.setChecked(true); 224 | mStaticIpViews.enableAllViews(); 225 | 226 | StaticIpConfiguration staticConfig = ipinfo.getStaticIpConfiguration(); 227 | Log.d(TAG, "UpdateViewContent staticConfig=" + staticConfig); 228 | 229 | mStaticIpViews.updateViews(staticConfig); 230 | } 231 | } 232 | } 233 | 234 | private String updateIfaceTypeRadioButtonState(){ 235 | String ifaceType = getInterfaceSetting(); 236 | if(ifaceType.equals(Settings.Global.INTERFACE_ETH0)){ 237 | eth0Radio.setChecked(true); 238 | }else if(ifaceType.equals(Settings.Global.INTERFACE_ETH1)){ 239 | eth1Radio.setChecked(true); 240 | } 241 | return ifaceType; 242 | } 243 | 244 | private String updateIpTypeRadioButtonState(){ 245 | String ipType = mStaticIpViews.getIpTypeSetting(); 246 | if(ipType.equals(Settings.Global.TYPE_DHCP)){ 247 | mIpTypeDhcp.setChecked(true); 248 | mIpTypeManual.setChecked(false); 249 | }else if(ipType.equals(Settings.Global.TYPE_STATIC)){ 250 | mIpTypeDhcp.setChecked(false); 251 | mIpTypeManual.setChecked(true); 252 | } 253 | 254 | return ipType; 255 | } 256 | private void updateRadioButtonState(){ 257 | updateIfaceTypeRadioButtonState(); 258 | 259 | updateIpTypeRadioButtonState(); 260 | } 261 | 262 | private String getInterfaceSetting(){ 263 | String ifaceType = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.ETHERNET_IFACE_TYPE); 264 | 265 | return ifaceType; 266 | } 267 | 268 | private boolean setInterfaceSetting(String iface){ 269 | return Settings.Global.putString(mContext.getContentResolver(), Settings.Global.ETHERNET_IFACE_TYPE, iface); 270 | 271 | } 272 | 273 | private void handle_saveconf() { 274 | IpAssignment ipAssignment = (mIpTypeDhcp.isChecked() ? IpAssignment.DHCP:IpAssignment.STATIC); 275 | 276 | String iface; 277 | if(eth0Radio.isChecked()){ 278 | iface = Settings.Global.INTERFACE_ETH0; 279 | }else{ 280 | iface = Settings.Global.INTERFACE_ETH1; 281 | } 282 | 283 | if(IpAssignment.DHCP == ipAssignment){ 284 | mEthManager.setConfiguration(iface,new IpConfiguration(ipAssignment, ProxySettings.NONE, 285 | null, null)); 286 | dismiss(); 287 | }else{ 288 | StaticIpConfiguration staticIpConfiguration = mStaticIpViews.generateStaticIpConfiguration(); 289 | 290 | if(staticIpConfiguration == null){ 291 | Toast.makeText(mContext, R.string.eth_settings_error, Toast.LENGTH_SHORT).show(); 292 | }else{ 293 | mEthManager.setConfiguration(iface,new IpConfiguration(ipAssignment, ProxySettings.NONE, 294 | staticIpConfiguration, null)); 295 | Log.d(TAG,"mode static ip ++ staticIpConfiguration=" + staticIpConfiguration); 296 | 297 | mStaticIpViews.saveSettings(); 298 | dismiss(); 299 | } 300 | 301 | } 302 | 303 | } 304 | 305 | 306 | private abstract class StaticIpViews{ 307 | private final String TAG = "StaticIpViews"; 308 | 309 | protected IPView mIpaddr; 310 | protected IPView mNetMask; 311 | protected IPView mGw; 312 | protected IPView mDns1; 313 | protected IPView mDns2; 314 | 315 | 316 | public StaticIpViews(IPView ipaddr, IPView netMask, IPView gateway, IPView dns1, IPView dns2){ 317 | mIpaddr = ipaddr; 318 | mNetMask = netMask; 319 | mGw = gateway; 320 | mDns1 = dns1; 321 | mDns2 = dns2; 322 | } 323 | 324 | public void updateViews(StaticIpConfiguration staticIpConfig ){ 325 | if (staticIpConfig != null) { 326 | if (staticIpConfig.ipAddress != null) { 327 | mIpaddr.setIp(staticIpConfig.ipAddress.getAddress().getHostAddress()); 328 | 329 | String prefix=interMask2String(staticIpConfig.ipAddress.getPrefixLength()); 330 | Log.d(TAG, "updateViews prefix=" + prefix); 331 | mNetMask.setIp(prefix); 332 | } 333 | 334 | if (staticIpConfig.gateway != null) { 335 | mGw.setIp(staticIpConfig.gateway.getHostAddress()); 336 | } 337 | 338 | Iterator dnsIterator = staticIpConfig.dnsServers.iterator(); 339 | if(dnsIterator.hasNext()){ 340 | InetAddress ia = dnsIterator.next(); 341 | mDns1.setIp(ia.getHostAddress()); 342 | } 343 | if(dnsIterator.hasNext()){ 344 | InetAddress ia = dnsIterator.next(); 345 | mDns2.setIp(ia.getHostAddress()); 346 | } 347 | 348 | } 349 | } 350 | 351 | public void enableAllViews(){ 352 | setAllViewsEnabled(true); 353 | } 354 | 355 | public void disableAllViews(){ 356 | setAllViewsEnabled(false); 357 | } 358 | 359 | private void setAllViewsEnabled(boolean enabled){ 360 | mIpaddr.setEnabled(enabled); 361 | mNetMask.setEnabled(enabled); 362 | mGw.setEnabled(enabled); 363 | mDns1.setEnabled(enabled); 364 | mDns2.setEnabled(enabled); 365 | } 366 | 367 | public void clearAllViews(){ 368 | mIpaddr.clear(); 369 | mNetMask.clear(); 370 | mGw.clear(); 371 | mDns1.clear(); 372 | mDns2.clear(); 373 | } 374 | 375 | public abstract void saveSettings(); 376 | 377 | public abstract void loadSettings(); 378 | 379 | public abstract String getIpTypeSetting(); 380 | 381 | public abstract boolean setIpTypeSetting(String ipType); 382 | 383 | public void readSettingsToIPView(IPView ipv, String settingString){ 384 | String data = Global.getString(mContext.getContentResolver(), settingString); 385 | if(data != null && isIpAddress(data)) { 386 | ipv.setIp(data); 387 | } 388 | } 389 | 390 | public StaticIpConfiguration generateStaticIpConfiguration(){ 391 | 392 | String ipaddr = mIpaddr.getText(); 393 | String netMask = mNetMask.getText(); 394 | String gateway = mGw.getText(); 395 | String dns1 = mDns1.getText(); 396 | String dns2 = mDns2.getText(); 397 | 398 | InvalidInputHandler invalidInputHandler = new InvalidInputHandler(); 399 | StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); 400 | 401 | if (TextUtils.isEmpty(ipaddr)) { 402 | invalidInputHandler.addResult(ConfigErrorCodeEnum.CONFIG_STR_EMPTY); 403 | }else{ 404 | Inet4Address inetAddr = getIPv4Address(ipaddr); 405 | 406 | if (inetAddr == null || inetAddr.equals(Inet4Address.ANY)) { 407 | invalidInputHandler.addResult(ConfigErrorCodeEnum.CONFIG_INVAILD_IP); 408 | }else{ 409 | 410 | int networkPrefixLength = -1; 411 | try { 412 | networkPrefixLength = maskStr2InetMask(netMask); 413 | staticIpConfiguration.ipAddress = new LinkAddress(inetAddr, networkPrefixLength); 414 | } catch (NumberFormatException e) { 415 | // Set the hint as default after user types in ip address 416 | invalidInputHandler.addResult(ConfigErrorCodeEnum.CONFI_ERROR); 417 | } catch (IllegalArgumentException e) { 418 | invalidInputHandler.addResult(ConfigErrorCodeEnum.CONFI_ERROR); 419 | } 420 | } 421 | } 422 | 423 | if (!TextUtils.isEmpty(gateway)) { 424 | InetAddress gatewayAddr = getIPv4Address(gateway); 425 | if (gatewayAddr == null) { 426 | invalidInputHandler.addResult(ConfigErrorCodeEnum.CONFIG_INVAILD_GATEWAY); 427 | } 428 | if (gatewayAddr.isMulticastAddress()) { 429 | invalidInputHandler.addResult(ConfigErrorCodeEnum.CONFIG_INVAILD_GATEWAY); 430 | } 431 | staticIpConfiguration.gateway = gatewayAddr; 432 | } 433 | 434 | InetAddress dnsAddr = null; 435 | if (dns1 != null && !TextUtils.isEmpty(dns1)) { 436 | dnsAddr = getIPv4Address(dns1); 437 | if (dnsAddr == null) { 438 | invalidInputHandler.addResult(ConfigErrorCodeEnum.CONFIG_INVAILD_DNS); 439 | } 440 | staticIpConfiguration.dnsServers.add(dnsAddr); 441 | } 442 | 443 | if (dns2 != null && !TextUtils.isEmpty(dns2)) { 444 | dnsAddr = getIPv4Address(dns2); 445 | if (dnsAddr == null) { 446 | invalidInputHandler.addResult(ConfigErrorCodeEnum.CONFIG_INVAILD_DNS); 447 | } 448 | staticIpConfiguration.dnsServers.add(dnsAddr); 449 | } 450 | 451 | Log.d(TAG, "generateStaticIpConfiguration result=" + invalidInputHandler.getResults()); 452 | if(0 == invalidInputHandler.getResults()){ 453 | return staticIpConfiguration; 454 | }else{ 455 | return null; 456 | } 457 | } 458 | 459 | public String interMask2String(int prefixLength) { 460 | String netMask = null; 461 | int inetMask = prefixLength; 462 | 463 | int part = inetMask / 8; 464 | int remainder = inetMask % 8; 465 | int sum = 0; 466 | 467 | for (int i = 8; i > 8 - remainder; i--) { 468 | sum = sum + (int) Math.pow(2, i - 1); 469 | } 470 | 471 | if (part == 0) { 472 | netMask = sum + ".0.0.0"; 473 | } else if (part == 1) { 474 | netMask = "255." + sum + ".0.0"; 475 | } else if (part == 2) { 476 | netMask = "255.255." + sum + ".0"; 477 | } else if (part == 3) { 478 | netMask = "255.255.255." + sum; 479 | } else if (part == 4) { 480 | netMask = "255.255.255.255"; 481 | } 482 | 483 | return netMask; 484 | } 485 | 486 | /* 487 | * convert subMask string to prefix length 488 | */ 489 | public int maskStr2InetMask(String maskStr) { 490 | StringBuffer sb ; 491 | String str; 492 | int inetmask = 0; 493 | int count = 0; 494 | /* 495 | * check the subMask format 496 | */ 497 | Pattern pattern = Pattern.compile("(^((\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])$)|^(\\d|[1-2]\\d|3[0-2])$"); 498 | if (pattern.matcher(maskStr).matches() == false) { 499 | Log.e(TAG,"subMask is error"); 500 | return 0; 501 | } 502 | 503 | String[] ipSegment = maskStr.split("\\."); 504 | for(int n =0; n 255) || (block < 0)) { 540 | return false; 541 | } 542 | } catch (NumberFormatException e) { 543 | return false; 544 | } 545 | 546 | numBlocks++; 547 | 548 | start = end + 1; 549 | end = value.indexOf('.', start); 550 | } 551 | return numBlocks == 4; 552 | } 553 | 554 | } 555 | 556 | private class RJ45StaticIpViews extends StaticIpViews{ 557 | public RJ45StaticIpViews (IPView ipaddr, IPView netMask, IPView gateway, IPView dns1, IPView dns2){ 558 | super(ipaddr,netMask,gateway,dns1,dns2); 559 | } 560 | 561 | @Override 562 | public void saveSettings(){ 563 | Global.putString(mContext.getContentResolver(), Global.RJ45_STATIC_IP, 564 | mIpaddr.getText()); 565 | Global.putString(mContext.getContentResolver(), Global.RJ45_STATIC_NETMASK, 566 | mNetMask.getText().toString()); 567 | Global.putString(mContext.getContentResolver(), Global.RJ45_STATIC_GATEWAY, 568 | mGw.getText()); 569 | Global.putString(mContext.getContentResolver(), Global.RJ45_STATIC_DNS1, 570 | mDns1.getText()); 571 | Global.putString(mContext.getContentResolver(), Global.RJ45_STATIC_DNS2, 572 | mDns2.getText()); 573 | } 574 | 575 | @Override 576 | public void loadSettings(){ 577 | String ipType = getIpTypeSetting(); 578 | if (localLOGV) Log.d(TAG, "ipType =" + ipType ); 579 | 580 | if(ipType.equals(Settings.Global.TYPE_STATIC)){ 581 | readSettingsToIPView(mIpaddr,Global.RJ45_STATIC_IP); 582 | readSettingsToIPView(mNetMask,Global.RJ45_STATIC_NETMASK); 583 | readSettingsToIPView(mGw,Global.RJ45_STATIC_GATEWAY); 584 | readSettingsToIPView(mDns1,Global.RJ45_STATIC_DNS1); 585 | readSettingsToIPView(mDns2,Global.RJ45_STATIC_DNS2); 586 | enableAllViews(); 587 | }else{ 588 | disableAllViews(); 589 | clearAllViews(); 590 | } 591 | } 592 | 593 | @Override 594 | public String getIpTypeSetting(){ 595 | String ipType = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.ETHERNET_IP_TYPE_ETH0); 596 | 597 | return ipType; 598 | } 599 | 600 | @Override 601 | public boolean setIpTypeSetting(String ipType){ 602 | return Settings.Global.putString(mContext.getContentResolver(), Settings.Global.ETHERNET_IP_TYPE_ETH0, ipType); 603 | } 604 | 605 | } 606 | 607 | private class UsbCardStaticIpViews extends StaticIpViews{ 608 | public UsbCardStaticIpViews (IPView ipaddr, IPView netMask, IPView gateway, IPView dns1, IPView dns2){ 609 | super(ipaddr,netMask,gateway,dns1,dns2); 610 | } 611 | 612 | @Override 613 | public void saveSettings(){ 614 | Global.putString(mContext.getContentResolver(), Global.USB_CARD_STATIC_IP, 615 | mIpaddr.getText()); 616 | Global.putString(mContext.getContentResolver(), Global.USB_CARD_STATIC_NETMASK, 617 | mNetMask.getText().toString()); 618 | Global.putString(mContext.getContentResolver(), Global.USB_CARD_STATIC_GATEWAY, 619 | mGw.getText()); 620 | Global.putString(mContext.getContentResolver(), Global.USB_CARD_STATIC_DNS1, 621 | mDns1.getText()); 622 | Global.putString(mContext.getContentResolver(), Global.USB_CARD_STATIC_DNS2, 623 | mDns2.getText()); 624 | } 625 | 626 | @Override 627 | public void loadSettings(){ 628 | String ipType = getIpTypeSetting(); 629 | if (localLOGV) Log.d(TAG, "ipType =" + ipType ); 630 | 631 | if(ipType.equals(Settings.Global.TYPE_STATIC)){ 632 | readSettingsToIPView(mIpaddr,Global.USB_CARD_STATIC_IP); 633 | readSettingsToIPView(mNetMask,Global.USB_CARD_STATIC_NETMASK); 634 | readSettingsToIPView(mGw,Global.USB_CARD_STATIC_GATEWAY); 635 | readSettingsToIPView(mDns1,Global.USB_CARD_STATIC_DNS1); 636 | readSettingsToIPView(mDns2,Global.USB_CARD_STATIC_DNS2); 637 | enableAllViews(); 638 | }else{ 639 | disableAllViews(); 640 | clearAllViews(); 641 | } 642 | 643 | } 644 | 645 | @Override 646 | public String getIpTypeSetting(){ 647 | String ipType = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.ETHERNET_IP_TYPE_ETH1); 648 | 649 | return ipType; 650 | } 651 | 652 | @Override 653 | public boolean setIpTypeSetting(String ipType){ 654 | return Settings.Global.putString(mContext.getContentResolver(), Settings.Global.ETHERNET_IP_TYPE_ETH1, ipType); 655 | } 656 | } 657 | 658 | private class InvalidInputHandler{ 659 | 660 | public static final int STR_EMPTY_MASK = ~0x01; 661 | private int mResults; 662 | 663 | public InvalidInputHandler(){ 664 | mResults = ConfigErrorCodeEnum.CONFIG_OK.getCode(); 665 | } 666 | 667 | public void addResult(ConfigErrorCodeEnum resultEnum){ 668 | mResults |=resultEnum.getCode(); 669 | } 670 | 671 | public int getResults(){ 672 | return mResults; 673 | } 674 | 675 | public void popupIndication(){ 676 | 677 | } 678 | 679 | } 680 | 681 | 682 | public static enum ConfigErrorCodeEnum{ 683 | CONFIG_OK(0,0), 684 | CONFIG_STR_EMPTY(0x01, R.string.eth_settings_empty), 685 | CONFIG_INVAILD_IP(0x02, R.string.eth_settings_invalid_ip_address), 686 | CONFIG_INVAILD_GATEWAY(0x04, R.string.eth_settings_invalid_gateway), 687 | CONFIG_INVAILD_DNS(0x08, R.string.eth_settings_invalid_dns), 688 | CONFI_ERROR(0x10, R.string.eth_settings_error); 689 | 690 | private int mCode; 691 | private int mTextId; 692 | 693 | private ConfigErrorCodeEnum(int code, int textId){ 694 | mCode = code; 695 | mTextId = textId; 696 | } 697 | 698 | public int getCode(){ 699 | return mCode; 700 | } 701 | 702 | public static int getTextIdByCode(int code ){ 703 | int rTextId = 0; 704 | for(ConfigErrorCodeEnum errorCode:values()){ 705 | if(errorCode.mCode == code){ 706 | rTextId = errorCode.mTextId; 707 | break; 708 | } 709 | } 710 | 711 | return rTextId; 712 | } 713 | } 714 | 715 | 716 | } 717 | -------------------------------------------------------------------------------- /packages/apps/Settings/src/com/android/settings/ethernet/EthernetEnabler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.android.settings.ethernet; 18 | 19 | import android.content.ContentResolver; 20 | import android.content.Context; 21 | import android.content.Intent; 22 | import android.content.IntentFilter; 23 | import android.os.Bundle; 24 | import android.os.RemoteException; 25 | import android.os.SystemProperties; 26 | import android.preference.ListPreference; 27 | import android.preference.Preference; 28 | import android.preference.PreferenceScreen; 29 | import android.provider.Settings; 30 | import android.provider.Settings.SettingNotFoundException; 31 | import android.util.AttributeSet; 32 | import android.util.Log; 33 | import android.view.View; 34 | import android.preference.CheckBoxPreference; 35 | 36 | import java.util.ArrayList; 37 | import com.android.settings.SettingsPreferenceFragment; 38 | import com.android.settings.R; 39 | import com.android.settings.widget.SwitchBar; 40 | import com.android.settings.widget.SwitchBarController; 41 | import com.android.settings.SettingsActivity; 42 | import android.widget.Switch; 43 | import android.net.EthernetManager; 44 | import android.provider.Settings; 45 | 46 | public class EthernetEnabler implements SwitchBarController.OnSwitchChangeListener { 47 | private final String TAG = "EthernetEnabler"; 48 | private Context mContext; 49 | private SwitchBarController mSwitchBarController; 50 | private EthernetDialog mEthDialog = null; 51 | private EthernetManager mEthManager; 52 | public void setConfigDialog(EthernetDialog Dialog) { 53 | mEthDialog = Dialog; 54 | } 55 | 56 | public EthernetEnabler(Context context, SwitchBarController switchWidget,EthernetManager ethernetManager) { 57 | mContext = context; 58 | mSwitchBarController = switchWidget; 59 | mEthManager = ethernetManager; 60 | setupSwitchBar(); 61 | } 62 | 63 | public void resume(Context context) { 64 | Log.d(TAG,"resume "); 65 | mContext = context; 66 | } 67 | 68 | public void pause() { 69 | Log.d(TAG,"pause "); 70 | } 71 | 72 | public void setupSwitchBar() { 73 | int enable = Settings.Global.getInt(mContext.getContentResolver(),Settings.Global.ETHERNET_ON,EthernetManager.ETHERNET_STATE_UNKNOWN); 74 | Log.d(TAG,"setupSwitchBar enable="+ enable); 75 | if(enable == EthernetManager.ETHERNET_STATE_ENABLED) { 76 | mSwitchBarController.setChecked(true); 77 | } else { 78 | mSwitchBarController.setChecked(false); 79 | } 80 | mSwitchBarController.setListener(this); 81 | mSwitchBarController.startListening(); 82 | mSwitchBarController.setupView(); 83 | 84 | } 85 | 86 | public void teardownSwitchBar() { 87 | Log.d(TAG,"teardownSwitchBar "); 88 | mSwitchBarController.stopListening(); 89 | mSwitchBarController.teardownView(); 90 | } 91 | 92 | @Override 93 | public boolean onSwitchToggled( boolean isChecked) { 94 | Log.d(TAG,"onSwitchToggled isChecked= " + isChecked); 95 | if(isChecked) { 96 | if(mEthManager != null){ 97 | mEthManager.start(); 98 | } 99 | Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.ETHERNET_ON,EthernetManager.ETHERNET_STATE_ENABLED); 100 | } else { 101 | if(mEthManager != null){ 102 | mEthManager.stop(); 103 | } 104 | Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.ETHERNET_ON,EthernetManager.ETHERNET_STATE_DISABLED); 105 | } 106 | return true; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /packages/apps/Settings/src/com/android/settings/ethernet/EthernetSettings.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.android.settings.ethernet; 18 | 19 | import android.content.ContentResolver; 20 | import android.content.Context; 21 | import android.content.Intent; 22 | import android.content.IntentFilter; 23 | import android.os.Bundle; 24 | import android.os.RemoteException; 25 | import android.os.SystemProperties; 26 | import android.support.v7.preference.Preference; 27 | import android.support.v7.preference.Preference.OnPreferenceChangeListener; 28 | import android.support.v7.preference.PreferenceScreen; 29 | import android.provider.Settings; 30 | import android.provider.Settings.SettingNotFoundException; 31 | import android.util.AttributeSet; 32 | import android.util.Log; 33 | import android.view.View; 34 | import android.preference.CheckBoxPreference; 35 | 36 | import java.util.ArrayList; 37 | 38 | import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 39 | import com.android.settings.dashboard.SummaryLoader; 40 | import com.android.settings.SettingsPreferenceFragment; 41 | import com.android.settings.R; 42 | import com.android.settings.widget.SwitchBar; 43 | import com.android.settings.widget.SwitchBarController; 44 | import com.android.settings.SettingsActivity; 45 | 46 | import android.widget.Switch; 47 | import android.app.Activity; 48 | import android.app.ActivityManager; 49 | import android.net.DhcpInfo; 50 | import android.net.EthernetManager; 51 | import android.content.Context; 52 | import android.net.ConnectivityManager; 53 | import android.widget.Toast; 54 | import android.os.Looper; 55 | 56 | public class EthernetSettings extends SettingsPreferenceFragment implements OnPreferenceChangeListener{ 57 | private static final String TAG = "EthernetSettings"; 58 | private EthernetEnabler mEthEnabler; 59 | private static final String KEY_CONF_ETH = "ethernet_config"; 60 | private EthernetDialog mEthernetDialog = null; 61 | private Preference mEthConfigPref; 62 | private ConnectivityManager mCM; 63 | private DhcpInfo mDhcpinfo; 64 | 65 | @Override 66 | public void onCreate(Bundle savedInstanceState) { 67 | super.onCreate(savedInstanceState); 68 | addPreferencesFromResource(R.xml.ethernet_settings); 69 | final PreferenceScreen preferenceScreen = getPreferenceScreen(); 70 | mEthConfigPref = preferenceScreen.findPreference(KEY_CONF_ETH); 71 | } 72 | 73 | @Override 74 | public void onStart() { 75 | super.onStart(); 76 | // On/off switch is hidden for Setup Wizard (returns null) 77 | mEthEnabler = createEthernetEnabler(); 78 | mCM = (ConnectivityManager)getActivity().getSystemService( 79 | Context.CONNECTIVITY_SERVICE); 80 | mEthernetDialog = new EthernetDialog(getActivity(), 81 | (EthernetManager)getSystemService(Context.ETHERNET_SERVICE), mCM); 82 | mEthEnabler.setConfigDialog(mEthernetDialog); 83 | } 84 | 85 | @Override 86 | public void onResume() { 87 | super.onResume(); 88 | final Activity activity = getActivity(); 89 | if (mEthEnabler != null) { 90 | mEthEnabler.resume(activity); 91 | } 92 | } 93 | 94 | @Override 95 | public void onPause() { 96 | super.onPause(); 97 | if (mEthEnabler != null) { 98 | mEthEnabler.pause(); 99 | } 100 | } 101 | 102 | @Override 103 | public void onDestroyView() { 104 | super.onDestroyView(); 105 | 106 | if (mEthEnabler != null) { 107 | mEthEnabler.teardownSwitchBar(); 108 | } 109 | } 110 | 111 | @Override 112 | public int getMetricsCategory() { 113 | return MetricsEvent.ETHERNET; 114 | } 115 | 116 | /** 117 | * @return new EthernetEnabler or null 118 | */ 119 | /* package */ 120 | EthernetEnabler createEthernetEnabler() { 121 | final SettingsActivity activity = (SettingsActivity) getActivity(); 122 | SwitchBar bar = activity.getSwitchBar(); 123 | return new EthernetEnabler(activity, new SwitchBarController(activity.getSwitchBar()), 124 | (EthernetManager)getSystemService(Context.ETHERNET_SERVICE)); 125 | } 126 | 127 | @Override 128 | public boolean onPreferenceChange(Preference preference, Object newValue) { 129 | return true; 130 | } 131 | 132 | @Override 133 | public boolean onPreferenceTreeClick(Preference preference) { 134 | if (preference == mEthConfigPref) { 135 | final SettingsActivity activity = (SettingsActivity) getActivity(); 136 | if(activity.getSwitchBar().isChecked()) { 137 | if(mEthernetDialog != null) 138 | mEthernetDialog.show(); 139 | } else { 140 | Toast.makeText(getActivity(), R.string.eth_open_ethernet_tip, Toast.LENGTH_LONG).show(); 141 | } 142 | } 143 | return super.onPreferenceTreeClick(preference); 144 | } 145 | 146 | private static class SummaryProvider implements SummaryLoader.SummaryProvider { 147 | 148 | private final Context mContext; 149 | private final SummaryLoader mSummaryLoader; 150 | 151 | public SummaryProvider(Context context, SummaryLoader summaryLoader) { 152 | mContext = context; 153 | mSummaryLoader = summaryLoader; 154 | } 155 | 156 | @Override 157 | public void setListening(boolean listening) { 158 | if (listening) { 159 | int enable = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.ETHERNET_ON, 0); 160 | if(enable == EthernetManager.ETHERNET_STATE_ENABLED) { 161 | mSummaryLoader.setSummary(this, mContext.getString(R.string.eth_state_on)); 162 | } else { 163 | mSummaryLoader.setSummary(this, mContext.getString(R.string.eth_state_off)); 164 | } 165 | } 166 | } 167 | } 168 | 169 | public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY 170 | = new SummaryLoader.SummaryProviderFactory() { 171 | @Override 172 | public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity, 173 | SummaryLoader summaryLoader) { 174 | return new SummaryProvider(activity, summaryLoader); 175 | } 176 | }; 177 | } 178 | -------------------------------------------------------------------------------- /packages/apps/Settings/src/com/android/settings/ethernet/ip/AbsEditText.java: -------------------------------------------------------------------------------- 1 | package com.android.settings.ethernet.ip; 2 | 3 | import android.content.Context; 4 | import android.text.InputFilter; 5 | import android.text.InputType; 6 | import android.text.method.NumberKeyListener; 7 | import android.util.AttributeSet; 8 | import android.widget.EditText; 9 | 10 | public abstract class AbsEditText extends EditText { 11 | public AbsEditText(Context context) { 12 | this(context,null,0); 13 | } 14 | 15 | public AbsEditText(Context context, AttributeSet attrs) { 16 | this(context, attrs,0); 17 | } 18 | 19 | public AbsEditText(Context context, AttributeSet attrs, int defStyleAttr) { 20 | super(context, attrs, defStyleAttr); 21 | setMaxLength(); 22 | addInputFilter(); 23 | } 24 | 25 | protected void setMaxLength(){ 26 | setFilters(new InputFilter[]{new InputFilter.LengthFilter(getMaxLength())}); 27 | } 28 | 29 | protected void addInputFilter(){ 30 | setKeyListener(new NumberKeyListener() { 31 | @Override 32 | protected char[] getAcceptedChars() { 33 | return getInputFilterAcceptedChars(); 34 | } 35 | 36 | @Override 37 | public int getInputType() { 38 | return InputType.TYPE_CLASS_NUMBER; 39 | } 40 | }); 41 | } 42 | 43 | public abstract int getMaxLength(); 44 | 45 | public abstract char[] getInputFilterAcceptedChars(); 46 | 47 | public abstract boolean checkInputValue(); 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /packages/apps/Settings/src/com/android/settings/ethernet/ip/AbsEditTextGroup.java: -------------------------------------------------------------------------------- 1 | package com.android.settings.ethernet.ip; 2 | 3 | import android.content.Context; 4 | import android.text.Editable; 5 | import android.text.TextUtils; 6 | import android.text.TextWatcher; 7 | import android.util.AttributeSet; 8 | import android.util.Log; 9 | import android.view.Gravity; 10 | import android.view.KeyEvent; 11 | import android.view.View; 12 | import android.widget.LinearLayout; 13 | import android.widget.TextView; 14 | import android.widget.Toast; 15 | 16 | import com.android.settings.R; 17 | 18 | import java.util.ArrayList; 19 | 20 | public abstract class AbsEditTextGroup extends LinearLayout implements TextWatcher { 21 | 22 | protected float sp16 = 16.0f; 23 | protected int dp4 = 4; 24 | private ArrayList editTexts = new ArrayList(); 25 | 26 | public AbsEditTextGroup(Context context) { 27 | this(context, null, 0); 28 | } 29 | 30 | public AbsEditTextGroup(Context context, AttributeSet attrs) { 31 | this(context, attrs, 0); 32 | } 33 | 34 | public AbsEditTextGroup(Context context, AttributeSet attrs, int defStyleAttr) { 35 | super(context, attrs, defStyleAttr); 36 | addViews(); 37 | buildListener(); 38 | } 39 | 40 | protected void addViews() { 41 | for (int i = 0; i < getChildCount(); i++) { 42 | if (i%2==0) { 43 | AbsEditText absEditText= createAbsEditText(); 44 | editTexts.add(absEditText); 45 | addView(absEditText); 46 | } else { 47 | addView(createSemicolonTextView()); 48 | } 49 | } 50 | } 51 | 52 | protected AbsEditText createAbsEditText() { 53 | 54 | AbsEditText absEditText = getAbsEditText(); 55 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT); 56 | params.weight = 1; 57 | absEditText.setLayoutParams(params); 58 | absEditText.setTextSize(sp16); 59 | absEditText.setTextColor(0xFF222222); 60 | absEditText.setGravity(Gravity.CENTER); 61 | absEditText.setPadding(dp4, dp4, dp4, dp4); 62 | absEditText.setSingleLine(); 63 | absEditText.setFocusableInTouchMode(true); 64 | absEditText.setBackgroundColor(0xFFFFFFFF); 65 | applyEditTextTheme(absEditText); 66 | return absEditText; 67 | } 68 | 69 | protected TextView createSemicolonTextView() { 70 | TextView textView = new TextView(getContext()); 71 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT); 72 | textView.setLayoutParams(params); 73 | textView.setTextSize(sp16); 74 | textView.setTextColor(0xFF444444); 75 | textView.setText(getSemicolomText()); 76 | applySemicolonTextViewTheme(textView); 77 | return textView; 78 | } 79 | 80 | protected void buildListener() { 81 | for (int i = 0; i < editTexts.size(); i++) { 82 | editTexts.get(i).addTextChangedListener(this); 83 | if(i!=0){ 84 | editTexts.get(i).setOnKeyListener(new OnDelKeyListener(editTexts.get(i-1), editTexts.get(i))); 85 | } 86 | } 87 | } 88 | 89 | @Override 90 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 91 | 92 | } 93 | 94 | @Override 95 | public void onTextChanged(CharSequence s, int start, int before, int count) { 96 | android.util.Log.i("zhouyj", "start = " + start + " before = " + before + " count = " + count); 97 | } 98 | 99 | @Override 100 | public void afterTextChanged(Editable s) { 101 | String text = s.toString().trim(); 102 | if (text.length() > 0 && Integer.parseInt(text.toString().trim()) > 255) { 103 | s.delete(text.length() - 2, 1); 104 | Toast.makeText(getContext(), R.string.eth_settings_error, Toast.LENGTH_SHORT).show(); 105 | } else if (text.length() == getDelMaxLength()) { 106 | for (int i=0; i< editTexts.size()-1; i++){ 107 | if(editTexts.get(i).hasFocus()){ 108 | editTexts.get(i).clearFocus(); 109 | editTexts.get(i+1).requestFocus(); 110 | break; 111 | } 112 | } 113 | } 114 | } 115 | 116 | public boolean checkInputValue(AbsEditText... params) { 117 | boolean result = true; 118 | for (int i = 0; i < params.length - 1; i++) { 119 | if (!params[i].checkInputValue()) { 120 | result = false; 121 | break; 122 | } 123 | } 124 | 125 | return result; 126 | } 127 | 128 | public void setIp(String ip) { 129 | if (!TextUtils.isEmpty(ip)) { 130 | String[] ips = ip.split("\\" + getSemicolomText()); 131 | for (int i = 0; i < editTexts.size(); i++) { 132 | editTexts.get(i).setText(ips[i]); 133 | } 134 | } 135 | } 136 | 137 | public String getText() { 138 | StringBuffer sb = new StringBuffer(); 139 | for (int i = 0; i < editTexts.size(); i++) { 140 | String ip = editTexts.get(i).getText().toString(); 141 | if (!TextUtils.isEmpty(ip)) { 142 | sb.append(ip); 143 | if (i != editTexts.size() -1) { 144 | sb.append(getSemicolomText()); 145 | } 146 | } 147 | } 148 | return sb.toString(); 149 | } 150 | 151 | public void clear() { 152 | for (int i = 0; i < editTexts.size(); i++) { 153 | editTexts.get(i).setText(""); 154 | } 155 | } 156 | 157 | class OnDelKeyListener implements View.OnKeyListener { 158 | 159 | private AbsEditText clearEditText; 160 | private AbsEditText requestEditText; 161 | 162 | public OnDelKeyListener(AbsEditText requestEditText, AbsEditText clearEditText){ 163 | this.requestEditText = requestEditText; 164 | this.clearEditText = clearEditText; 165 | } 166 | @Override 167 | public boolean onKey(View v, int keyCode, KeyEvent event) { 168 | if (keyCode == KeyEvent.KEYCODE_DEL 169 | && event.getAction() == KeyEvent.ACTION_DOWN 170 | && clearEditText.getSelectionStart() == 0) { 171 | clearEditText.clearFocus(); 172 | requestEditText.requestFocus(); 173 | requestEditText.setSelection(requestEditText.length()); 174 | return true; 175 | } 176 | return false; 177 | } 178 | } 179 | 180 | public abstract int getChildCount(); 181 | 182 | public abstract AbsEditText getAbsEditText(); 183 | 184 | public abstract String getSemicolomText(); 185 | 186 | public abstract int getDelMaxLength(); 187 | 188 | public abstract void applySemicolonTextViewTheme(TextView semicolonTextView); 189 | 190 | public abstract void applyEditTextTheme(AbsEditText absEditText); 191 | 192 | 193 | } 194 | -------------------------------------------------------------------------------- /packages/apps/Settings/src/com/android/settings/ethernet/ip/IPEditText.java: -------------------------------------------------------------------------------- 1 | package com.android.settings.ethernet.ip; 2 | 3 | import android.content.Context; 4 | import android.text.InputFilter; 5 | import android.text.InputType; 6 | import android.text.method.NumberKeyListener; 7 | import android.util.AttributeSet; 8 | import android.widget.EditText; 9 | 10 | public class IPEditText extends AbsEditText { 11 | 12 | public IPEditText(Context context) { 13 | this(context, null, 0); 14 | } 15 | 16 | public IPEditText(Context context, AttributeSet attrs) { 17 | this(context, attrs, 0); 18 | } 19 | 20 | public IPEditText(Context context, AttributeSet attrs, int defStyleAttr) { 21 | super(context, attrs, defStyleAttr); 22 | } 23 | 24 | @Override 25 | public int getMaxLength() { 26 | return 3; 27 | } 28 | 29 | @Override 30 | public char[] getInputFilterAcceptedChars() { 31 | return new char[]{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; 32 | } 33 | 34 | @Override 35 | public boolean checkInputValue() { 36 | return getText().length() != 0; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/apps/Settings/src/com/android/settings/ethernet/ip/IPView.java: -------------------------------------------------------------------------------- 1 | package com.android.settings.ethernet.ip; 2 | 3 | import android.content.Context; 4 | import android.text.Editable; 5 | import android.text.TextWatcher; 6 | import android.util.AttributeSet; 7 | import android.view.Gravity; 8 | import android.view.KeyEvent; 9 | import android.view.View; 10 | import android.widget.LinearLayout; 11 | import android.widget.TextView; 12 | 13 | import java.util.ArrayList; 14 | 15 | public class IPView extends AbsEditTextGroup { 16 | public IPView(Context context) { 17 | super(context); 18 | } 19 | 20 | public IPView(Context context, AttributeSet attrs) { 21 | super(context, attrs); 22 | } 23 | 24 | public IPView(Context context, AttributeSet attrs, int defStyleAttr) { 25 | super(context, attrs, defStyleAttr); 26 | } 27 | 28 | @Override 29 | public void setEnabled(boolean enabled) { 30 | super.setEnabled(enabled); 31 | for (int i = 0; i < getChildCount(); i++) { 32 | if (i % 2 == 0) { 33 | AbsEditText absEditText= (AbsEditText) getChildAt(i); 34 | absEditText.setEnabled(enabled); 35 | } 36 | } 37 | } 38 | 39 | @Override 40 | public int getChildCount() { 41 | return 7; 42 | } 43 | 44 | @Override 45 | public AbsEditText getAbsEditText() { 46 | return new IPEditText(getContext()); 47 | } 48 | 49 | @Override 50 | public String getSemicolomText() { 51 | return "."; 52 | } 53 | 54 | @Override 55 | public int getDelMaxLength() { 56 | return 3; 57 | } 58 | 59 | @Override 60 | public void applySemicolonTextViewTheme(TextView semicolonTextView) { 61 | semicolonTextView.setPadding(0,0,0,5); 62 | semicolonTextView.getPaint().setFakeBoldText(true); 63 | semicolonTextView.setBackgroundColor(0xFFFFFFFF); 64 | semicolonTextView.setGravity(Gravity.BOTTOM); 65 | } 66 | 67 | @Override 68 | public void applyEditTextTheme(AbsEditText absEditText) { 69 | 70 | } 71 | 72 | } 73 | --------------------------------------------------------------------------------