1/* 2 * Copyright 2017 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 17package com.android.server.wifi.hotspot2; 18 19import android.content.BroadcastReceiver; 20import android.content.Context; 21import android.content.Intent; 22import android.content.IntentFilter; 23import android.net.ConnectivityManager; 24import android.net.LinkProperties; 25import android.net.Network; 26import android.net.NetworkCapabilities; 27import android.net.NetworkRequest; 28import android.net.wifi.WifiConfiguration; 29import android.net.wifi.WifiManager; 30import android.net.wifi.WifiSsid; 31import android.os.Handler; 32import android.text.TextUtils; 33import android.util.Log; 34 35/** 36 * Responsible for setup/monitor on Wi-Fi state and connection to the OSU AP. 37 */ 38public class OsuNetworkConnection { 39 private static final String TAG = "OsuNetworkConnection"; 40 private static final int TIMEOUT_MS = 10000; 41 42 private final Context mContext; 43 44 private boolean mVerboseLoggingEnabled = false; 45 private WifiManager mWifiManager; 46 private ConnectivityManager mConnectivityManager; 47 private ConnectivityCallbacks mConnectivityCallbacks; 48 private Callbacks mCallbacks; 49 private Handler mHandler; 50 private Network mNetwork = null; 51 private boolean mConnected = false; 52 private int mNetworkId = -1; 53 private boolean mWifiEnabled = false; 54 55 /** 56 * Callbacks on Wi-Fi connection state changes. 57 */ 58 public interface Callbacks { 59 /** 60 * Invoked when network connection is established with IP connectivity. 61 * 62 * @param network {@link Network} associated with the connected network. 63 */ 64 void onConnected(Network network); 65 66 /** 67 * Invoked when the targeted network is disconnected. 68 */ 69 void onDisconnected(); 70 71 /** 72 * Invoked when a timer tracking connection request is not reset by successfull connection. 73 */ 74 void onTimeOut(); 75 76 /** 77 * Invoked when Wifi is enabled. 78 */ 79 void onWifiEnabled(); 80 81 /** 82 * Invoked when Wifi is disabled. 83 */ 84 void onWifiDisabled(); 85 } 86 87 /** 88 * Create an instance of {@link NetworkConnection} for the specified Wi-Fi network. 89 * @param context The application context 90 */ 91 public OsuNetworkConnection(Context context) { 92 mContext = context; 93 } 94 95 /** 96 * Called to initialize tracking of wifi state and network events by registering for the 97 * corresponding intents. 98 */ 99 public void init(Handler handler) { 100 IntentFilter filter = new IntentFilter(); 101 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 102 BroadcastReceiver receiver = new BroadcastReceiver() { 103 @Override 104 public void onReceive(Context context, Intent intent) { 105 String action = intent.getAction(); 106 if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 107 int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 108 WifiManager.WIFI_STATE_UNKNOWN); 109 if (state == WifiManager.WIFI_STATE_DISABLED && mWifiEnabled) { 110 mWifiEnabled = false; 111 if (mCallbacks != null) mCallbacks.onWifiDisabled(); 112 } 113 if (state == WifiManager.WIFI_STATE_ENABLED && !mWifiEnabled) { 114 mWifiEnabled = true; 115 if (mCallbacks != null) mCallbacks.onWifiEnabled(); 116 } 117 } 118 } 119 }; 120 mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); 121 mContext.registerReceiver(receiver, filter, null, handler); 122 mWifiEnabled = mWifiManager.isWifiEnabled(); 123 mConnectivityManager = 124 (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 125 mConnectivityCallbacks = new ConnectivityCallbacks(); 126 mHandler = handler; 127 } 128 129 /** 130 * Disconnect, if required in the two cases 131 * - still connected to the OSU AP 132 * - connection to OSU AP was requested and in progress 133 */ 134 public void disconnectIfNeeded() { 135 if (mNetworkId < 0) { 136 if (mVerboseLoggingEnabled) { 137 Log.v(TAG, "No connection to tear down"); 138 } 139 return; 140 } 141 mWifiManager.removeNetwork(mNetworkId); 142 mNetworkId = -1; 143 mNetwork = null; 144 mConnected = false; 145 } 146 147 /** 148 * Register for network and Wifi state events 149 * @param callbacks The callbacks to be invoked on network change events 150 */ 151 public void setEventCallback(Callbacks callbacks) { 152 mCallbacks = callbacks; 153 } 154 155 /** 156 * Connect to a OSU Wi-Fi network specified by the given SSID. The security type of the Wi-Fi 157 * network is either open or OSEN (OSU Server-only authenticated layer 2 Encryption Network). 158 * When network access identifier is provided, OSEN is used. 159 * 160 * @param ssid The SSID to connect to 161 * @param nai Network access identifier of the network 162 * 163 * @return boolean true if connection was successfully initiated 164 */ 165 public boolean connect(WifiSsid ssid, String nai) { 166 if (mConnected) { 167 if (mVerboseLoggingEnabled) { 168 // Already connected 169 Log.v(TAG, "Connect called twice"); 170 } 171 return true; 172 } 173 if (!mWifiEnabled) { 174 Log.w(TAG, "Wifi is not enabled"); 175 return false; 176 } 177 WifiConfiguration config = new WifiConfiguration(); 178 config.SSID = "\"" + ssid.toString() + "\""; 179 if (TextUtils.isEmpty(nai)) { 180 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 181 } else { 182 // TODO: Handle OSEN. 183 Log.w(TAG, "OSEN not supported"); 184 return false; 185 } 186 mNetworkId = mWifiManager.addNetwork(config); 187 if (mNetworkId < 0) { 188 Log.e(TAG, "Unable to add network"); 189 return false; 190 } 191 NetworkRequest networkRequest = null; 192 networkRequest = new NetworkRequest.Builder() 193 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build(); 194 mConnectivityManager.requestNetwork(networkRequest, mConnectivityCallbacks, mHandler, 195 TIMEOUT_MS); 196 if (!mWifiManager.enableNetwork(mNetworkId, true)) { 197 Log.e(TAG, "Unable to enable network " + mNetworkId); 198 disconnectIfNeeded(); 199 return false; 200 } 201 if (mVerboseLoggingEnabled) { 202 Log.v(TAG, "Current network ID " + mNetworkId); 203 } 204 return true; 205 } 206 207 /** 208 * Method to update logging level in this class 209 * @param verbose more than 0 enables verbose logging 210 */ 211 public void enableVerboseLogging(int verbose) { 212 mVerboseLoggingEnabled = verbose > 0 ? true : false; 213 } 214 215 private class ConnectivityCallbacks extends ConnectivityManager.NetworkCallback { 216 @Override 217 public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) { 218 if (mVerboseLoggingEnabled) { 219 Log.v(TAG, "onLinkPropertiesChanged for network=" + network 220 + " isProvisioned?" + linkProperties.isProvisioned()); 221 } 222 if (linkProperties.isProvisioned() && mNetwork == null) { 223 mNetwork = network; 224 mConnected = true; 225 if (mCallbacks != null) { 226 mCallbacks.onConnected(network); 227 } 228 } 229 } 230 231 @Override 232 public void onUnavailable() { 233 if (mVerboseLoggingEnabled) { 234 Log.v(TAG, "onUnvailable "); 235 } 236 if (mCallbacks != null) { 237 mCallbacks.onTimeOut(); 238 } 239 } 240 241 @Override 242 public void onLost(Network network) { 243 if (mVerboseLoggingEnabled) { 244 Log.v(TAG, "onLost " + network); 245 } 246 if (network != mNetwork) { 247 Log.w(TAG, "Irrelevant network lost notification"); 248 return; 249 } 250 if (mCallbacks != null) { 251 mCallbacks.onDisconnected(); 252 } 253 } 254 } 255} 256 257