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.tv.settings.connectivity; 18 19 import com.android.tv.settings.R; 20 import com.android.tv.settings.form.FormPage; 21 22 import android.content.Context; 23 import android.net.IpConfiguration.IpAssignment; 24 import android.net.IpConfiguration.ProxySettings; 25 import android.net.IpConfiguration; 26 import android.net.LinkAddress; 27 import android.net.NetworkUtils; 28 import android.net.ProxyInfo; 29 import android.net.RouteInfo; 30 import android.net.StaticIpConfiguration; 31 import android.net.wifi.WifiConfiguration; 32 import android.os.Bundle; 33 import android.text.TextUtils; 34 35 import java.net.InetAddress; 36 import java.net.Inet4Address; 37 import java.util.Collection; 38 import java.util.Iterator; 39 40 /** 41 * Handles the form page flow of setting advanced options. 42 */ 43 public class AdvancedWifiOptionsFlow { 44 45 public interface PageHandler { 46 void addPage(WifiFormPageType formPageType); 47 48 void removePage(FormPage formPage); 49 50 boolean choiceChosen(FormPage formPage, int choiceResourceId); 51 } 52 53 public static final int RESULT_UNKNOWN_PAGE = 0; 54 public static final int RESULT_PAGE_HANDLED = 1; 55 public static final int RESULT_ALL_PAGES_COMPLETE = 2; 56 57 private final Context mContext; 58 private final PageHandler mPageHandler; 59 private final boolean mAskFirst; 60 private final NetworkConfiguration mInitialConfiguration; 61 private FormPage mAdvancedOptionsPage; 62 private FormPage mProxySettingsPage; 63 private FormPage mIpSettingsPage; 64 private FormPage mProxyHostnamePage; 65 private FormPage mProxyPortPage; 66 private FormPage mProxyBypassPage; 67 private FormPage mIpAddressPage; 68 private FormPage mGatewayPage; 69 private FormPage mNetworkPrefixLengthPage; 70 private FormPage mDns1Page; 71 private FormPage mDns2Page; 72 private IpConfiguration mIpConfiguration; 73 private boolean mSettingsFlow; 74 75 public AdvancedWifiOptionsFlow(Context context, PageHandler pageHandler, 76 NetworkConfiguration initialConfiguration) { 77 mContext = context; 78 mPageHandler = pageHandler; 79 mAskFirst = false; 80 mSettingsFlow = true; 81 mInitialConfiguration = initialConfiguration; 82 mIpConfiguration = (initialConfiguration != null) ? 83 mInitialConfiguration.getIpConfiguration() : 84 new IpConfiguration(); 85 } 86 87 public AdvancedWifiOptionsFlow(Context context, PageHandler pageHandler, boolean askFirst, 88 NetworkConfiguration initialConfiguration) { 89 mContext = context; 90 mPageHandler = pageHandler; 91 mAskFirst = askFirst; 92 mSettingsFlow = false; 93 mInitialConfiguration = initialConfiguration; 94 mIpConfiguration = (initialConfiguration != null) ? 95 mInitialConfiguration.getIpConfiguration() : 96 new IpConfiguration(); 97 } 98 99 public WifiFormPageType getInitialPage() { 100 return (mAskFirst) ? WifiFormPageType.ADVANCED_OPTIONS : WifiFormPageType.PROXY_SETTINGS; 101 } 102 103 public WifiFormPageType getInitialProxySettingsPage() { 104 return WifiFormPageType.PROXY_SETTINGS; 105 } 106 107 public WifiFormPageType getInitialIpSettingsPage() { 108 return WifiFormPageType.IP_SETTINGS; 109 } 110 111 /** 112 * @param formPageType the type of page that completed. 113 * @param formPage the page that complete. 114 * @return RESULT_PAGE_HANDLED if the page has been handled. 115 * RESULT_UNKNOWN_PAGE if the page is unrecognized and was ignored. 116 * RESULT_ALL_PAGES_COMPLETE if all pages have been completed. 117 */ 118 public int handlePageComplete(WifiFormPageType formPageType, FormPage formPage) { 119 120 switch (formPageType) { 121 case ADVANCED_OPTIONS: 122 mAdvancedOptionsPage = formPage; 123 if (mPageHandler.choiceChosen(formPage, R.string.wifi_action_advanced_no)) { 124 processProxySettings(); 125 processIpSettings(); 126 return RESULT_ALL_PAGES_COMPLETE; 127 } else { 128 mPageHandler.addPage(WifiFormPageType.PROXY_SETTINGS); 129 } 130 break; 131 case PROXY_SETTINGS: 132 mProxySettingsPage = formPage; 133 if (mPageHandler.choiceChosen(formPage, R.string.wifi_action_proxy_none)) { 134 processProxySettings(); 135 if (mSettingsFlow) { 136 return RESULT_ALL_PAGES_COMPLETE; 137 } else { 138 mPageHandler.addPage(WifiFormPageType.IP_SETTINGS); 139 } 140 } else { 141 mPageHandler.addPage(WifiFormPageType.PROXY_HOSTNAME); 142 } 143 break; 144 case PROXY_HOSTNAME: 145 mProxyHostnamePage = formPage; 146 mPageHandler.addPage(WifiFormPageType.PROXY_PORT); 147 break; 148 case PROXY_PORT: 149 mProxyPortPage = formPage; 150 mPageHandler.addPage(WifiFormPageType.PROXY_BYPASS); 151 break; 152 case PROXY_BYPASS: 153 mProxyBypassPage = formPage; 154 int proxySettingsResult = processProxySettings(); 155 if (proxySettingsResult == 0) { 156 if (mSettingsFlow) { 157 return RESULT_ALL_PAGES_COMPLETE; 158 } else { 159 mPageHandler.addPage(WifiFormPageType.IP_SETTINGS); 160 } 161 } else { 162 mPageHandler.addPage(WifiFormPageType.PROXY_SETTINGS_INVALID); 163 } 164 break; 165 case PROXY_SETTINGS_INVALID: 166 mPageHandler.removePage(mProxySettingsPage); 167 mPageHandler.removePage(mProxyHostnamePage); 168 mPageHandler.removePage(mProxyPortPage); 169 mPageHandler.removePage(mProxyBypassPage); 170 mPageHandler.addPage(WifiFormPageType.PROXY_SETTINGS); 171 break; 172 case IP_SETTINGS: 173 mIpSettingsPage = formPage; 174 if (mPageHandler.choiceChosen(formPage, R.string.wifi_action_dhcp)) { 175 processIpSettings(); 176 return RESULT_ALL_PAGES_COMPLETE; 177 } else { 178 mPageHandler.addPage(WifiFormPageType.IP_ADDRESS); 179 } 180 break; 181 case IP_ADDRESS: 182 mIpAddressPage = formPage; 183 mPageHandler.addPage(WifiFormPageType.GATEWAY); 184 break; 185 case GATEWAY: 186 mGatewayPage = formPage; 187 mPageHandler.addPage(WifiFormPageType.NETWORK_PREFIX_LENGTH); 188 break; 189 case NETWORK_PREFIX_LENGTH: 190 mNetworkPrefixLengthPage = formPage; 191 mPageHandler.addPage(WifiFormPageType.DNS1); 192 break; 193 case DNS1: 194 mDns1Page = formPage; 195 mPageHandler.addPage(WifiFormPageType.DNS2); 196 break; 197 case DNS2: 198 mDns2Page = formPage; 199 int ipSettingsResult = processIpSettings(); 200 if (ipSettingsResult == 0) { 201 return RESULT_ALL_PAGES_COMPLETE; 202 } else { 203 mPageHandler.addPage(WifiFormPageType.IP_SETTINGS_INVALID); 204 } 205 break; 206 case IP_SETTINGS_INVALID: 207 mPageHandler.removePage(mIpSettingsPage); 208 mPageHandler.removePage(mIpAddressPage); 209 mPageHandler.removePage(mGatewayPage); 210 mPageHandler.removePage(mDns1Page); 211 mPageHandler.removePage(mDns2Page); 212 mPageHandler.addPage(WifiFormPageType.IP_SETTINGS); 213 break; 214 default: 215 return RESULT_UNKNOWN_PAGE; 216 } 217 return RESULT_PAGE_HANDLED; 218 } 219 220 public FormPage getPreviousPage(WifiFormPageType formPageType) { 221 switch (formPageType) { 222 case ADVANCED_OPTIONS: 223 return mAdvancedOptionsPage; 224 case PROXY_SETTINGS: 225 if (mProxySettingsPage == null && getInitialProxyInfo() != null) { 226 return createFormPage(R.string.wifi_action_proxy_manual); 227 } 228 return mProxySettingsPage; 229 case PROXY_HOSTNAME: 230 if (mProxyHostnamePage == null && getInitialProxyInfo() != null) { 231 return createFormPage(getInitialProxyInfo().getHost()); 232 } 233 return mProxyHostnamePage; 234 case PROXY_PORT: 235 if (mProxyPortPage == null && getInitialProxyInfo() != null) { 236 return createFormPage(Integer.toString(getInitialProxyInfo().getPort())); 237 } 238 return mProxyPortPage; 239 case PROXY_BYPASS: 240 if (mProxyBypassPage == null && getInitialProxyInfo() != null) { 241 return createFormPage(getInitialProxyInfo().getExclusionListAsString()); 242 } 243 return mProxyBypassPage; 244 case IP_SETTINGS: 245 if (mIpSettingsPage == null && getInitialLinkAddress() != null) { 246 return createFormPage(R.string.wifi_action_static); 247 } 248 return mIpSettingsPage; 249 case IP_ADDRESS: 250 if (mIpAddressPage == null && getInitialLinkAddress() != null) { 251 return createFormPage(getInitialLinkAddress().getAddress().getHostAddress()); 252 } 253 return mIpAddressPage; 254 case GATEWAY: 255 if (mGatewayPage == null && getInitialGateway() != null) { 256 return createFormPage(getInitialGateway().getHostAddress()); 257 } 258 return mGatewayPage; 259 case NETWORK_PREFIX_LENGTH: 260 if (mNetworkPrefixLengthPage == null && getInitialLinkAddress() != null) { 261 return createFormPage( 262 Integer.toString(getInitialLinkAddress().getNetworkPrefixLength())); 263 } 264 return mNetworkPrefixLengthPage; 265 case DNS1: 266 if (mDns1Page == null && getInitialDns(0) != null) { 267 return createFormPage(getInitialDns(0).getHostAddress()); 268 } 269 return mDns1Page; 270 case DNS2: 271 if (mDns2Page == null && getInitialDns(1) != null) { 272 return createFormPage(getInitialDns(1).getHostAddress()); 273 } 274 return mDns2Page; 275 case IP_SETTINGS_INVALID: 276 case PROXY_SETTINGS_INVALID: 277 default: 278 return null; 279 } 280 } 281 282 public boolean isEmptyTextAllowed(WifiFormPageType formPageType) { 283 switch (formPageType) { 284 case PROXY_BYPASS: 285 case DNS1: 286 case DNS2: 287 case GATEWAY: 288 return true; 289 default: 290 return false; 291 } 292 } 293 294 private IpConfiguration getCurrentIpConfiguration() { 295 return mIpConfiguration; 296 } 297 298 public void updateConfiguration(WifiConfiguration configuration) { 299 configuration.setIpConfiguration(mIpConfiguration); 300 } 301 302 public void updateConfiguration(NetworkConfiguration configuration) { 303 configuration.setIpConfiguration(mIpConfiguration); 304 } 305 306 private InetAddress getInitialDns(int index) { 307 try { 308 return mInitialConfiguration.getIpConfiguration().getStaticIpConfiguration() 309 .dnsServers.get(index); 310 } catch (IndexOutOfBoundsException|NullPointerException e) { 311 return null; 312 } 313 } 314 315 private InetAddress getInitialGateway() { 316 try { 317 return mInitialConfiguration.getIpConfiguration().getStaticIpConfiguration().gateway; 318 } catch (NullPointerException e) { 319 return null; 320 } 321 } 322 323 private LinkAddress getInitialLinkAddress() { 324 try { 325 return mInitialConfiguration.getIpConfiguration().getStaticIpConfiguration().ipAddress; 326 } catch (NullPointerException e) { 327 return null; 328 } 329 } 330 331 private ProxyInfo getInitialProxyInfo() { 332 try { 333 return mInitialConfiguration.getIpConfiguration().getHttpProxy(); 334 } catch (NullPointerException e) { 335 return null; 336 } 337 } 338 339 private FormPage createFormPage(int resultStringResourceId) { 340 return createFormPage(mContext.getString(resultStringResourceId).toUpperCase()); 341 } 342 343 private FormPage createFormPage(String resultString) { 344 Bundle result = new Bundle(); 345 result.putString(FormPage.DATA_KEY_SUMMARY_STRING, resultString); 346 FormPage formPage = FormPage.createTextInputForm(resultString); 347 formPage.complete(result); 348 return formPage; 349 } 350 351 private int processProxySettings() { 352 boolean hasProxySettings = (mAdvancedOptionsPage == null || !mPageHandler.choiceChosen( 353 mAdvancedOptionsPage, R.string.wifi_action_advanced_no)) 354 && !mPageHandler.choiceChosen(mProxySettingsPage, R.string.wifi_action_proxy_none); 355 mIpConfiguration.setProxySettings(hasProxySettings ? 356 ProxySettings.STATIC : ProxySettings.NONE); 357 if (hasProxySettings) { 358 String host = mProxyHostnamePage.getDataSummary(); 359 String portStr = mProxyPortPage.getDataSummary(); 360 String exclusionList = mProxyBypassPage.getDataSummary(); 361 int port = 0; 362 int result = 0; 363 try { 364 port = Integer.parseInt(portStr); 365 result = WifiConfigHelper.validate(host, portStr, exclusionList); 366 } catch (NumberFormatException e) { 367 result = R.string.proxy_error_invalid_port; 368 } 369 if (result == 0) { 370 mIpConfiguration.setHttpProxy(new ProxyInfo(host, port, exclusionList)); 371 } else { 372 return result; 373 } 374 } else { 375 mIpConfiguration.setHttpProxy(null); 376 } 377 378 return 0; 379 } 380 381 private int processIpSettings() { 382 boolean hasIpSettings = (mAdvancedOptionsPage == null || !mPageHandler.choiceChosen( 383 mAdvancedOptionsPage, R.string.wifi_action_advanced_no)) 384 && !mPageHandler.choiceChosen(mIpSettingsPage, R.string.wifi_action_dhcp); 385 mIpConfiguration.setIpAssignment(hasIpSettings ? IpAssignment.STATIC : IpAssignment.DHCP); 386 387 if (hasIpSettings) { 388 StaticIpConfiguration staticConfig = new StaticIpConfiguration(); 389 mIpConfiguration.setStaticIpConfiguration(staticConfig); 390 391 String ipAddr = mIpAddressPage.getDataSummary(); 392 if (TextUtils.isEmpty(ipAddr)) 393 return R.string.wifi_ip_settings_invalid_ip_address; 394 395 Inet4Address inetAddr = null; 396 try { 397 inetAddr = (Inet4Address) NetworkUtils.numericToInetAddress(ipAddr); 398 } catch (IllegalArgumentException|ClassCastException e) { 399 return R.string.wifi_ip_settings_invalid_ip_address; 400 } 401 402 int networkPrefixLength = -1; 403 try { 404 networkPrefixLength = Integer.parseInt(mNetworkPrefixLengthPage.getDataSummary()); 405 if (networkPrefixLength < 0 || networkPrefixLength > 32) { 406 return R.string.wifi_ip_settings_invalid_network_prefix_length; 407 } 408 staticConfig.ipAddress = new LinkAddress(inetAddr, networkPrefixLength); 409 } catch (NumberFormatException e) { 410 return R.string.wifi_ip_settings_invalid_ip_address; 411 } 412 413 String gateway = mGatewayPage.getDataSummary(); 414 if (!TextUtils.isEmpty(gateway)) { 415 try { 416 staticConfig.gateway = 417 (Inet4Address) NetworkUtils.numericToInetAddress(gateway); 418 } catch (IllegalArgumentException|ClassCastException e) { 419 return R.string.wifi_ip_settings_invalid_gateway; 420 } 421 } 422 423 String dns1 = mDns1Page.getDataSummary(); 424 if (!TextUtils.isEmpty(dns1)) { 425 try { 426 staticConfig.dnsServers.add( 427 (Inet4Address) NetworkUtils.numericToInetAddress(dns1)); 428 } catch (IllegalArgumentException|ClassCastException e) { 429 return R.string.wifi_ip_settings_invalid_dns; 430 } 431 } 432 433 String dns2 = mDns2Page.getDataSummary(); 434 if (!TextUtils.isEmpty(dns2)) { 435 try { 436 staticConfig.dnsServers.add( 437 (Inet4Address) NetworkUtils.numericToInetAddress(dns1)); 438 } catch (IllegalArgumentException|ClassCastException e) { 439 return R.string.wifi_ip_settings_invalid_dns; 440 } 441 } 442 } else { 443 mIpConfiguration.setStaticIpConfiguration(null); 444 } 445 return 0; 446 } 447 } 448