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