Home | History | Annotate | Download | only in task
      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 
     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
     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
     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
    104     public int getStatusMsgId() {
    105         return R.string.progress_connect_to_wifi;
    106     }
    107 
    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 
    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 
    161     private boolean enableWifi() {
    162         return mWifiManager.isWifiEnabled() || mWifiManager.setWifiEnabled(true);
    163     }
    164 
    165     @Override
    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 
    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 
    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