Home | History | Annotate | Download | only in hotspot2
      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 
     17 package com.android.server.wifi.hotspot2;
     18 
     19 import android.content.BroadcastReceiver;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.IntentFilter;
     23 import android.net.ConnectivityManager;
     24 import android.net.LinkProperties;
     25 import android.net.Network;
     26 import android.net.NetworkCapabilities;
     27 import android.net.NetworkRequest;
     28 import android.net.wifi.WifiConfiguration;
     29 import android.net.wifi.WifiManager;
     30 import android.net.wifi.WifiSsid;
     31 import android.os.Handler;
     32 import android.text.TextUtils;
     33 import android.util.Log;
     34 
     35 /**
     36  * Responsible for setup/monitor on Wi-Fi state and connection to the OSU AP.
     37  */
     38 public 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