• 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 static com.android.internal.util.Preconditions.checkNotNull;
20 
21 import android.content.Context;
22 import android.net.wifi.WifiConfiguration;
23 import android.net.wifi.WifiInfo;
24 import android.net.wifi.WifiManager;
25 import android.os.Handler;
26 
27 import com.android.internal.annotations.VisibleForTesting;
28 import com.android.managedprovisioning.R;
29 import com.android.managedprovisioning.common.ProvisionLogger;
30 import com.android.managedprovisioning.common.Utils;
31 import com.android.managedprovisioning.model.ProvisioningParams;
32 import com.android.managedprovisioning.task.wifi.NetworkMonitor;
33 import com.android.managedprovisioning.task.wifi.WifiConfigurationProvider;
34 
35 /**
36  * Adds a wifi network to the system and waits for it to successfully connect. If the system does
37  * not support wifi, the adding or connection times out {@link #error(int)} will be called.
38  */
39 public class AddWifiNetworkTask extends AbstractProvisioningTask
40         implements NetworkMonitor.NetworkConnectedCallback {
41     private static final int RETRY_SLEEP_DURATION_BASE_MS = 500;
42     private static final int RETRY_SLEEP_MULTIPLIER = 2;
43     private static final int MAX_RETRIES = 6;
44     private static final int RECONNECT_TIMEOUT_MS = 60000;
45     @VisibleForTesting  static final int ADD_NETWORK_FAIL = -1;
46 
47     private final WifiConfigurationProvider mWifiConfigurationProvider;
48     private final WifiManager mWifiManager;
49     private final NetworkMonitor mNetworkMonitor;
50 
51     private Handler mHandler;
52     private boolean mTaskDone = false;
53 
54     private final Utils mUtils;
55     private Runnable mTimeoutRunnable;
56     private Injector mInjector;
57 
AddWifiNetworkTask( Context context, ProvisioningParams provisioningParams, Callback callback)58     public AddWifiNetworkTask(
59             Context context,
60             ProvisioningParams provisioningParams,
61             Callback callback) {
62         this(
63                 new NetworkMonitor(context),
64                 new WifiConfigurationProvider(),
65                 context, provisioningParams, callback, new Utils(), new Injector());
66     }
67 
68     @VisibleForTesting
AddWifiNetworkTask( NetworkMonitor networkMonitor, WifiConfigurationProvider wifiConfigurationProvider, Context context, ProvisioningParams provisioningParams, Callback callback, Utils utils, Injector injector)69     AddWifiNetworkTask(
70             NetworkMonitor networkMonitor,
71             WifiConfigurationProvider wifiConfigurationProvider,
72             Context context,
73             ProvisioningParams provisioningParams,
74             Callback callback,
75             Utils utils,
76             Injector injector) {
77         super(context, provisioningParams, callback);
78 
79         mNetworkMonitor = checkNotNull(networkMonitor);
80         mWifiConfigurationProvider = checkNotNull(wifiConfigurationProvider);
81         mWifiManager  = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
82         mUtils = checkNotNull(utils);
83         mInjector = checkNotNull(injector);
84     }
85 
86     @Override
run(int userId)87     public void run(int userId) {
88         if (mProvisioningParams.wifiInfo == null) {
89             success();
90             return;
91         }
92 
93         if (mWifiManager == null || !enableWifi()) {
94             ProvisionLogger.loge("Failed to enable wifi");
95             error(0);
96             return;
97         }
98 
99         if (isConnectedToSpecifiedWifi()) {
100             success();
101             return;
102         }
103 
104         mTaskDone = false;
105         mHandler = new Handler();
106         mNetworkMonitor.startListening(this);
107         connectToProvidedNetwork();
108     }
109 
110     @Override
getStatusMsgId()111     public int getStatusMsgId() {
112         return R.string.progress_connect_to_wifi;
113     }
114 
connectToProvidedNetwork()115     private void connectToProvidedNetwork() {
116         WifiConfiguration wifiConf =
117                 mWifiConfigurationProvider.generateWifiConfiguration(mProvisioningParams.wifiInfo);
118 
119         if (wifiConf == null) {
120             ProvisionLogger.loge("WifiConfiguration is null");
121             error(0);
122             return;
123         }
124 
125         int netId = tryAddingNetwork(wifiConf);
126 
127         if (netId == ADD_NETWORK_FAIL) {
128             ProvisionLogger.loge("Unable to add network after trying " +  MAX_RETRIES + " times.");
129             error(0);
130             return;
131         }
132 
133         // Setting disableOthers to 'true' should trigger a connection attempt.
134         mWifiManager.enableNetwork(netId, true);
135         mWifiManager.saveConfiguration();
136 
137         // Network was successfully saved, now connect to it.
138         if (!mWifiManager.reconnect()) {
139             ProvisionLogger.loge("Unable to connect to wifi");
140             error(0);
141             return;
142         }
143 
144         // NetworkMonitor will call onNetworkConnected when in Wifi mode.
145         // Post time out event in case the NetworkMonitor doesn't call back.
146         mTimeoutRunnable = () -> finishTask(false);
147         mHandler.postDelayed(mTimeoutRunnable, RECONNECT_TIMEOUT_MS);
148     }
149 
tryAddingNetwork(WifiConfiguration wifiConf)150     private int tryAddingNetwork(WifiConfiguration wifiConf) {
151         int netId = mWifiManager.addNetwork(wifiConf);
152         int retriesLeft = MAX_RETRIES;
153         int durationNextSleep = RETRY_SLEEP_DURATION_BASE_MS;
154 
155         while(netId == -1 && retriesLeft > 0) {
156             ProvisionLogger.loge("Retrying in " + durationNextSleep + " ms.");
157             try {
158                 mInjector.threadSleep(durationNextSleep);
159             } catch (InterruptedException e) {
160                 ProvisionLogger.loge("Retry interrupted.");
161             }
162             durationNextSleep *= RETRY_SLEEP_MULTIPLIER;
163             retriesLeft--;
164             netId = mWifiManager.addNetwork(wifiConf);
165         }
166         return netId;
167     }
168 
enableWifi()169     private boolean enableWifi() {
170         return mWifiManager.isWifiEnabled() || mWifiManager.setWifiEnabled(true);
171     }
172 
173     @Override
onNetworkConnected()174     public void onNetworkConnected() {
175         ProvisionLogger.logd("onNetworkConnected");
176         if (isConnectedToSpecifiedWifi()) {
177             ProvisionLogger.logd("Connected to the correct network");
178             finishTask(true);
179             // Remove time out callback.
180             mHandler.removeCallbacks(mTimeoutRunnable);
181         }
182     }
183 
finishTask(boolean isSuccess)184     private synchronized void finishTask(boolean isSuccess) {
185         if (mTaskDone) {
186             return;
187         }
188 
189         mTaskDone = true;
190         mNetworkMonitor.stopListening();
191         if (isSuccess) {
192             success();
193         } else {
194             error(0);
195         }
196     }
197 
isConnectedToSpecifiedWifi()198     private boolean isConnectedToSpecifiedWifi() {
199         if (!mUtils.isConnectedToWifi(mContext)) {
200             ProvisionLogger.logd("Not connected to WIFI");
201             return false;
202         }
203         WifiInfo connectionInfo = mWifiManager.getConnectionInfo();
204         if (connectionInfo == null) {
205             ProvisionLogger.logd("connection info is null");
206             return false;
207         }
208         String connectedSSID = mWifiManager.getConnectionInfo().getSSID();
209         if (!mProvisioningParams.wifiInfo.ssid.equals(connectedSSID)) {
210             ProvisionLogger.logd("Wanted to connect SSID " + mProvisioningParams.wifiInfo.ssid
211                     + ", but it is now connected to " + connectedSSID);
212             return false;
213         }
214         return true;
215     }
216 
217     @VisibleForTesting
218     static class Injector {
threadSleep(long milliseconds)219         public void threadSleep(long milliseconds) throws InterruptedException {
220             Thread.sleep(milliseconds);
221         }
222     }
223 }
224