1c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse/* 2c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse * Copyright 2014, The Android Open Source Project 3c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse * 4c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse * Licensed under the Apache License, Version 2.0 (the "License"); 5c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse * you may not use this file except in compliance with the License. 6c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse * You may obtain a copy of the License at 7c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse * 8c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse * http://www.apache.org/licenses/LICENSE-2.0 9c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse * 10c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse * Unless required by applicable law or agreed to in writing, software 11c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse * distributed under the License is distributed on an "AS IS" BASIS, 12c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse * See the License for the specific language governing permissions and 14c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse * limitations under the License. 15c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse */ 16c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse 17c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnsepackage com.android.managedprovisioning.task; 18c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse 19c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnseimport android.content.Context; 20326bcfdd72218a2d3b35d8e1ca80b8e36263402eSander Alewijnseimport android.content.Intent; 21326bcfdd72218a2d3b35d8e1ca80b8e36263402eSander Alewijnseimport android.net.ConnectivityManager; 22326bcfdd72218a2d3b35d8e1ca80b8e36263402eSander Alewijnseimport android.net.NetworkInfo; 23c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnseimport android.net.wifi.WifiManager; 244b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnseimport android.os.Handler; 254b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnseimport android.os.HandlerThread; 264b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnseimport android.os.Looper; 2777bac595693aa1aa6e4832f278d5b3b35a3ffd53Steven Ngimport android.support.annotation.Nullable; 28c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnseimport android.text.TextUtils; 29c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse 30a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnseimport java.lang.Thread; 31a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse 32c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnseimport com.android.managedprovisioning.NetworkMonitor; 33c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnseimport com.android.managedprovisioning.ProvisionLogger; 34c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnseimport com.android.managedprovisioning.WifiConfig; 35d1784bd4d917bb36125e6faf125a2425c343838bSteven Ngimport com.android.managedprovisioning.common.Utils; 36d1784bd4d917bb36125e6faf125a2425c343838bSteven Ngimport com.android.managedprovisioning.model.WifiInfo; 3774d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse 38c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse/** 39c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse * Adds a wifi network to system. 40c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse */ 41c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnsepublic class AddWifiNetworkTask implements NetworkMonitor.Callback { 42a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse private static final int RETRY_SLEEP_DURATION_BASE_MS = 500; 43a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse private static final int RETRY_SLEEP_MULTIPLIER = 2; 44a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse private static final int MAX_RETRIES = 6; 45663445f060e9226a235e43f3b30c60bf9aa9d84eJukka Zitting private static final int RECONNECT_TIMEOUT_MS = 60000; 46a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse 4728bffd6424a3d9f2dbefe6c7d6144f3a4edee3bcSander Alewijnse private final Context mContext; 4877bac595693aa1aa6e4832f278d5b3b35a3ffd53Steven Ng @Nullable 4974d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse private final WifiInfo mWifiInfo; 5028bffd6424a3d9f2dbefe6c7d6144f3a4edee3bcSander Alewijnse private final Callback mCallback; 5128bffd6424a3d9f2dbefe6c7d6144f3a4edee3bcSander Alewijnse 52c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse private WifiManager mWifiManager; 5302b28903a2695617866138c5ebe23a8c66ee9714Sander Alewijnse private NetworkMonitor mNetworkMonitor; 54a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse private WifiConfig mWifiConfig; 55a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse 564b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse private Handler mHandler; 574b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse private boolean mTaskDone = false; 584b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse 59a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse private int mDurationNextSleep = RETRY_SLEEP_DURATION_BASE_MS; 60a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse private int mRetriesLeft = MAX_RETRIES; 61c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse 62ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz private final Utils mUtils = new Utils(); 63ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz 644b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse /** 654b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse * @throws IllegalArgumentException if the {@code ssid} parameter is empty. 664b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse */ 6774d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse public AddWifiNetworkTask(Context context, WifiInfo wifiInfo, Callback callback) { 6828bffd6424a3d9f2dbefe6c7d6144f3a4edee3bcSander Alewijnse mCallback = callback; 69c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse mContext = context; 7074d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse mWifiInfo = wifiInfo; 71c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); 72a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse mWifiConfig = new WifiConfig(mWifiManager); 734b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse 744b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse HandlerThread thread = new HandlerThread("Timeout thread", 754b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse android.os.Process.THREAD_PRIORITY_BACKGROUND); 764b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse thread.start(); 774b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse Looper looper = thread.getLooper(); 784b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse mHandler = new Handler(looper); 79c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse } 80c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse 81c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse public void run() { 8277bac595693aa1aa6e4832f278d5b3b35a3ffd53Steven Ng if (mWifiInfo == null) { 83ccd60165065172486fff32b581a0fb4d724b2991Julia Reynolds mCallback.onSuccess(); 84ccd60165065172486fff32b581a0fb4d724b2991Julia Reynolds return; 85ccd60165065172486fff32b581a0fb4d724b2991Julia Reynolds } 86c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse if (!enableWifi()) { 87c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse ProvisionLogger.loge("Failed to enable wifi"); 88c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse mCallback.onError(); 89c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse return; 90c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse } 91c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse 924b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse if (isConnectedToSpecifiedWifi()) { 93326bcfdd72218a2d3b35d8e1ca80b8e36263402eSander Alewijnse mCallback.onSuccess(); 944b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse return; 95326bcfdd72218a2d3b35d8e1ca80b8e36263402eSander Alewijnse } 964b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse 974b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse mNetworkMonitor = new NetworkMonitor(mContext, this); 984b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse connectToProvidedNetwork(); 99326bcfdd72218a2d3b35d8e1ca80b8e36263402eSander Alewijnse } 100326bcfdd72218a2d3b35d8e1ca80b8e36263402eSander Alewijnse 101326bcfdd72218a2d3b35d8e1ca80b8e36263402eSander Alewijnse private void connectToProvidedNetwork() { 10274d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse int netId = mWifiConfig.addNetwork(mWifiInfo.ssid, mWifiInfo.hidden, mWifiInfo.securityType, 10374d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse mWifiInfo.password, mWifiInfo.proxyHost, mWifiInfo.proxyPort, 10474d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse mWifiInfo.proxyBypassHosts, mWifiInfo.pacUrl); 105c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse 106c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse if (netId == -1) { 107c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse ProvisionLogger.loge("Failed to save network."); 108a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse if (mRetriesLeft > 0) { 109a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse ProvisionLogger.loge("Retrying in " + mDurationNextSleep + " ms."); 110a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse try { 111a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse Thread.sleep(mDurationNextSleep); 112a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse } catch (InterruptedException e) { 113a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse ProvisionLogger.loge("Retry interrupted."); 114a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse } 115a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse mDurationNextSleep *= RETRY_SLEEP_MULTIPLIER; 116a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse mRetriesLeft--; 117a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse connectToProvidedNetwork(); 118a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse return; 119a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse } else { 120a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse ProvisionLogger.loge("Already retried " + MAX_RETRIES + " times." 121a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse + " Quit retrying and report error."); 122a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse mCallback.onError(); 123a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse return; 124a09c2cf61a19a642a86b1032cb50a61d2630c564Sander Alewijnse } 1254b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse } 1264b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse 1274b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse // Network was successfully saved, now connect to it. 1284b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse if (!mWifiManager.reconnect()) { 1294b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse ProvisionLogger.loge("Unable to connect to wifi"); 1304b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse mCallback.onError(); 1314b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse return; 132c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse } 133c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse 134326bcfdd72218a2d3b35d8e1ca80b8e36263402eSander Alewijnse // NetworkMonitor will call onNetworkConnected when in Wifi mode. 1354b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse // Post time out event in case the NetworkMonitor doesn't call back. 1364b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse mHandler.postDelayed(new Runnable() { 1374b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse public void run(){ 1384b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse synchronized(this) { 1394b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse if (mTaskDone) return; 1404b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse mTaskDone = true; 1414b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse } 1424b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse ProvisionLogger.loge("Setting up wifi connection timed out."); 1434b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse mCallback.onError(); 1444b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse return; 1454b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse } 1464b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse }, RECONNECT_TIMEOUT_MS); 147c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse } 148c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse 149c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse private boolean enableWifi() { 1504b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse return mWifiManager != null 1514b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse && (mWifiManager.isWifiEnabled() || mWifiManager.setWifiEnabled(true)); 152c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse } 153c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse 154c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse @Override 155c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse public void onNetworkConnected() { 1564b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse if (isConnectedToSpecifiedWifi()) { 1574b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse synchronized(this) { 1584b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse if (mTaskDone) return; 1594b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse mTaskDone = true; 1604b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse } 1614b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse 162c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse ProvisionLogger.logd("Connected to the correct network"); 1634b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse 1644b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse // Remove time out callback. 1654b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse mHandler.removeCallbacksAndMessages(null); 1664b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse 1674b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse cleanUp(); 16802b28903a2695617866138c5ebe23a8c66ee9714Sander Alewijnse mCallback.onSuccess(); 1694b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse return; 170c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse } 171c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse } 172c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse 173326bcfdd72218a2d3b35d8e1ca80b8e36263402eSander Alewijnse @Override 174326bcfdd72218a2d3b35d8e1ca80b8e36263402eSander Alewijnse public void onNetworkDisconnected() { 175326bcfdd72218a2d3b35d8e1ca80b8e36263402eSander Alewijnse 176326bcfdd72218a2d3b35d8e1ca80b8e36263402eSander Alewijnse } 177326bcfdd72218a2d3b35d8e1ca80b8e36263402eSander Alewijnse 178d70438542632a1c8df15bdd9d91bfee52bf2b655Sander Alewijnse public void cleanUp() { 17928bffd6424a3d9f2dbefe6c7d6144f3a4edee3bcSander Alewijnse if (mNetworkMonitor != null) { 18028bffd6424a3d9f2dbefe6c7d6144f3a4edee3bcSander Alewijnse mNetworkMonitor.close(); 18128bffd6424a3d9f2dbefe6c7d6144f3a4edee3bcSander Alewijnse mNetworkMonitor = null; 18228bffd6424a3d9f2dbefe6c7d6144f3a4edee3bcSander Alewijnse } 18328bffd6424a3d9f2dbefe6c7d6144f3a4edee3bcSander Alewijnse } 18428bffd6424a3d9f2dbefe6c7d6144f3a4edee3bcSander Alewijnse 1854b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse private boolean isConnectedToSpecifiedWifi() { 186ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz return mUtils.isConnectedToWifi(mContext) 187afc4e4710d5170cf3fd07d23aaa445b21ee5c782Sudheer Shanka && mWifiManager != null 1884b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse && mWifiManager.getConnectionInfo() != null 18974d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse && mWifiInfo.ssid.equals(mWifiManager.getConnectionInfo().getSSID()); 1904b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse } 1914b2782a61e68948b6f20a4a3139f7c8eb77de265Sander Alewijnse 192c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse public abstract static class Callback { 193c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse public abstract void onSuccess(); 194c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse public abstract void onError(); 195c775738a923c5cb9db3ad558b4cba85ee84b0e4dSander Alewijnse } 1969643319ce223e09e7bb3450095939a92be00e3c4Sander Alewijnse} 197