• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 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.managedprovisioning.task;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.net.ConnectivityManager;
22 import android.net.NetworkInfo;
23 import android.net.wifi.WifiManager;
24 import android.os.Handler;
25 import android.os.HandlerThread;
26 import android.os.Looper;
27 import android.text.TextUtils;
28 
29 import java.lang.Thread;
30 
31 import com.android.managedprovisioning.NetworkMonitor;
32 import com.android.managedprovisioning.ProvisionLogger;
33 import com.android.managedprovisioning.WifiConfig;
34 
35 /**
36  * Adds a wifi network to system.
37  */
38 public class AddWifiNetworkTask implements NetworkMonitor.Callback {
39     private static final int RETRY_SLEEP_DURATION_BASE_MS = 500;
40     private static final int RETRY_SLEEP_MULTIPLIER = 2;
41     private static final int MAX_RETRIES = 6;
42     private static final int RECONNECT_TIMEOUT_MS = 30000;
43 
44     private final Context mContext;
45     private final String mSsid;
46     private final boolean mHidden;
47     private final String mSecurityType;
48     private final String mPassword;
49     private final String mProxyHost;
50     private final int mProxyPort;
51     private final String mProxyBypassHosts;
52     private final String mPacUrl;
53     private final Callback mCallback;
54 
55     private WifiManager mWifiManager;
56     private NetworkMonitor mNetworkMonitor;
57     private WifiConfig mWifiConfig;
58 
59     private Handler mHandler;
60     private boolean mTaskDone = false;
61 
62     private int mDurationNextSleep = RETRY_SLEEP_DURATION_BASE_MS;
63     private int mRetriesLeft = MAX_RETRIES;
64 
65     /**
66      * @throws IllegalArgumentException if the {@code ssid} parameter is empty.
67      */
AddWifiNetworkTask(Context context, String ssid, boolean hidden, String securityType, String password, String proxyHost, int proxyPort, String proxyBypassHosts, String pacUrl, Callback callback)68     public AddWifiNetworkTask(Context context, String ssid, boolean hidden, String securityType,
69             String password, String proxyHost, int proxyPort, String proxyBypassHosts,
70             String pacUrl, Callback callback) {
71         mCallback = callback;
72         mContext = context;
73         if (TextUtils.isEmpty(ssid)) {
74             throw new IllegalArgumentException("The ssid must be non-empty.");
75         }
76         mSsid = ssid;
77         mHidden = hidden;
78         mSecurityType = securityType;
79         mPassword = password;
80         mProxyHost = proxyHost;
81         mProxyPort = proxyPort;
82         mProxyBypassHosts = proxyBypassHosts;
83         mPacUrl = pacUrl;
84         mWifiManager  = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
85         mWifiConfig = new WifiConfig(mWifiManager);
86 
87         HandlerThread thread = new HandlerThread("Timeout thread",
88                 android.os.Process.THREAD_PRIORITY_BACKGROUND);
89         thread.start();
90         Looper looper = thread.getLooper();
91         mHandler = new Handler(looper);
92     }
93 
run()94     public void run() {
95         if (!enableWifi()) {
96             ProvisionLogger.loge("Failed to enable wifi");
97             mCallback.onError();
98             return;
99         }
100 
101         if (isConnectedToSpecifiedWifi()) {
102             mCallback.onSuccess();
103             return;
104         }
105 
106         mNetworkMonitor = new NetworkMonitor(mContext, this);
107         connectToProvidedNetwork();
108     }
109 
connectToProvidedNetwork()110     private void connectToProvidedNetwork() {
111         int netId = mWifiConfig.addNetwork(mSsid, mHidden, mSecurityType, mPassword, mProxyHost,
112                 mProxyPort, mProxyBypassHosts, mPacUrl);
113 
114         if (netId == -1) {
115             ProvisionLogger.loge("Failed to save network.");
116             if (mRetriesLeft > 0) {
117                 ProvisionLogger.loge("Retrying in " + mDurationNextSleep + " ms.");
118                 try {
119                     Thread.sleep(mDurationNextSleep);
120                 } catch (InterruptedException e) {
121                     ProvisionLogger.loge("Retry interrupted.");
122                 }
123                 mDurationNextSleep *= RETRY_SLEEP_MULTIPLIER;
124                 mRetriesLeft--;
125                 connectToProvidedNetwork();
126                 return;
127             } else {
128                 ProvisionLogger.loge("Already retried " +  MAX_RETRIES + " times."
129                         + " Quit retrying and report error.");
130                 mCallback.onError();
131                 return;
132             }
133         }
134 
135         // Network was successfully saved, now connect to it.
136         if (!mWifiManager.reconnect()) {
137             ProvisionLogger.loge("Unable to connect to wifi");
138             mCallback.onError();
139             return;
140         }
141 
142         // NetworkMonitor will call onNetworkConnected when in Wifi mode.
143         // Post time out event in case the NetworkMonitor doesn't call back.
144         mHandler.postDelayed(new Runnable() {
145                 public void run(){
146                     synchronized(this) {
147                         if (mTaskDone) return;
148                         mTaskDone = true;
149                     }
150                     ProvisionLogger.loge("Setting up wifi connection timed out.");
151                     mCallback.onError();
152                     return;
153                 }
154             }, RECONNECT_TIMEOUT_MS);
155     }
156 
enableWifi()157     private boolean enableWifi() {
158         return mWifiManager != null
159                 && (mWifiManager.isWifiEnabled() || mWifiManager.setWifiEnabled(true));
160     }
161 
162     @Override
onNetworkConnected()163     public void onNetworkConnected() {
164         if (isConnectedToSpecifiedWifi()) {
165             synchronized(this) {
166                 if (mTaskDone) return;
167                 mTaskDone = true;
168             }
169 
170             ProvisionLogger.logd("Connected to the correct network");
171 
172             // Remove time out callback.
173             mHandler.removeCallbacksAndMessages(null);
174 
175             cleanUp();
176             mCallback.onSuccess();
177             return;
178         }
179     }
180 
181     @Override
onNetworkDisconnected()182     public void onNetworkDisconnected() {
183 
184     }
185 
cleanUp()186     public void cleanUp() {
187         if (mNetworkMonitor != null) {
188             mNetworkMonitor.close();
189             mNetworkMonitor = null;
190         }
191     }
192 
isConnectedToSpecifiedWifi()193     private boolean isConnectedToSpecifiedWifi() {
194         return NetworkMonitor.isConnectedToWifi(mContext)
195                 && mWifiManager.getConnectionInfo() != null
196                 && mSsid.equals(mWifiManager.getConnectionInfo().getSSID());
197     }
198 
isConnectedToWifi(Context context)199     public static boolean isConnectedToWifi(Context context) {
200         ConnectivityManager cm =
201                 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
202         NetworkInfo info = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
203         return info.isConnected();
204     }
205 
getWifiPickIntent()206     public static Intent getWifiPickIntent() {
207         Intent wifiIntent = new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK);
208         wifiIntent.putExtra("only_access_points", true);
209         wifiIntent.putExtra("extra_prefs_show_button_bar", true);
210         wifiIntent.putExtra("wifi_enable_next_on_connect", true);
211         return wifiIntent;
212     }
213 
214     public abstract static class Callback {
onSuccess()215         public abstract void onSuccess();
onError()216         public abstract void onError();
217     }
218 }
219