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