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