Home | History | Annotate | Download | only in osu
      1 /*
      2  * Copyright (C) 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.osu;
     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.Network;
     24 import android.net.NetworkInfo;
     25 import android.net.wifi.WifiConfiguration;
     26 import android.net.wifi.WifiInfo;
     27 import android.net.wifi.WifiManager;
     28 import android.net.wifi.WifiSsid;
     29 import android.os.Handler;
     30 import android.text.TextUtils;
     31 import android.util.Log;
     32 
     33 import java.io.IOException;
     34 
     35 /**
     36  * Responsible for setup/monitor on a Wi-Fi connection.
     37  */
     38 public class NetworkConnection {
     39     private static final String TAG = "OSU_NetworkConnection";
     40 
     41     private final WifiManager mWifiManager;
     42     private final Callbacks mCallbacks;
     43     private final int mNetworkId;
     44     private boolean mConnected = false;
     45 
     46     /**
     47      * Callbacks on Wi-Fi connection state changes.
     48      */
     49     public interface Callbacks {
     50         /**
     51          * Invoked when network connection is established with IP connectivity.
     52          *
     53          * @param network {@link Network} associated with the connected network.
     54          */
     55         public void onConnected(Network network);
     56 
     57         /**
     58          * Invoked when the targeted network is disconnected.
     59          */
     60         public void onDisconnected();
     61 
     62         /**
     63          * Invoked when network connection is not established within the pre-defined timeout.
     64          */
     65         public void onTimeout();
     66     }
     67 
     68     /**
     69      * Create an instance of {@link NetworkConnection} for the specified Wi-Fi network.
     70      * The Wi-Fi network (specified by its SSID) will be added/enabled as part of this object
     71      * creation.
     72      *
     73      * {@link #teardown} will need to be invoked once you're done with this connection,
     74      * to remove the given Wi-Fi network from the framework.
     75      *
     76      * @param context The application context
     77      * @param handler The handler to dispatch the processing of received broadcast intents
     78      * @param ssid The SSID to connect to
     79      * @param nai The network access identifier associated with the AP
     80      * @param callbacks The callbacks to be invoked on network change events
     81      * @throws IOException when failed to add/enable the specified Wi-Fi network
     82      */
     83     public NetworkConnection(Context context, Handler handler, WifiSsid ssid, String nai,
     84             Callbacks callbacks) throws IOException {
     85         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
     86         mCallbacks = callbacks;
     87         mNetworkId = connect(ssid, nai);
     88 
     89         // TODO(zqiu): setup alarm to timed out the connection attempt.
     90 
     91         IntentFilter filter = new IntentFilter();
     92         filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
     93         BroadcastReceiver receiver = new BroadcastReceiver() {
     94             @Override
     95             public void onReceive(Context context, Intent intent) {
     96                 String action = intent.getAction();
     97                 if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
     98                     handleNetworkStateChanged(
     99                             intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO),
    100                             intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO));
    101                 }
    102             }
    103         };
    104         // Provide a Handler so that the onReceive call will be run on the specified handler
    105         // thread instead of the main thread.
    106         context.registerReceiver(receiver, filter, null, handler);
    107     }
    108 
    109     /**
    110      * Teardown the network connection by removing the network.
    111      */
    112     public void teardown() {
    113         mWifiManager.removeNetwork(mNetworkId);
    114     }
    115 
    116     /**
    117      * Connect to a OSU Wi-Fi network specified by the given SSID. The security type of the Wi-Fi
    118      * network is either open or OSEN (OSU Server-only authenticated layer 2 Encryption Network).
    119      * When network access identifier is provided, OSEN is used.
    120      *
    121      * @param ssid The SSID to connect to
    122      * @param nai Network access identifier of the network
    123      *
    124      * @return unique ID associated with the network
    125      * @throws IOException
    126      */
    127     private int connect(WifiSsid ssid, String nai) throws IOException {
    128         WifiConfiguration config = new WifiConfiguration();
    129         config.SSID = "\"" + ssid.toString() + "\"";
    130         if (TextUtils.isEmpty(nai)) {
    131             config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
    132         } else {
    133             // TODO(zqiu): configuration setup for OSEN.
    134         }
    135         int networkId = mWifiManager.addNetwork(config);
    136         if (networkId < 0) {
    137             throw new IOException("Failed to add OSU network");
    138         }
    139         if (!mWifiManager.enableNetwork(networkId, true)) {
    140             throw new IOException("Failed to enable OSU network");
    141         }
    142         return networkId;
    143     }
    144 
    145     /**
    146      * Handle network state changed events.
    147      *
    148      * @param networkInfo {@link NetworkInfo} indicating the current network state
    149      * @param wifiInfo {@link WifiInfo} associated with the current network when connected
    150      */
    151     private void handleNetworkStateChanged(NetworkInfo networkInfo, WifiInfo wifiInfo) {
    152         if (networkInfo == null) {
    153             Log.e(TAG, "NetworkInfo not provided for network state changed event");
    154             return;
    155         }
    156         switch (networkInfo.getDetailedState()) {
    157             case CONNECTED:
    158                 handleConnectedEvent(wifiInfo);
    159                 break;
    160             case DISCONNECTED:
    161                 handleDisconnectedEvent();
    162                 break;
    163             default:
    164                 Log.d(TAG, "Ignore uninterested state: " + networkInfo.getDetailedState());
    165                 break;
    166         }
    167     }
    168 
    169     /**
    170      * Handle network connected event.
    171      *
    172      * @param wifiInfo {@link WifiInfo} associated with the current connection
    173      */
    174     private void handleConnectedEvent(WifiInfo wifiInfo) {
    175         if (mConnected) {
    176             // No-op if already connected.
    177             return;
    178         }
    179         if (wifiInfo == null) {
    180             Log.e(TAG, "WifiInfo not provided for connected event");
    181             return;
    182         }
    183         if (wifiInfo.getNetworkId() != mNetworkId) {
    184             return;
    185         }
    186         Network network = mWifiManager.getCurrentNetwork();
    187         if (network == null) {
    188             Log.e(TAG, "Current network is not set");
    189             return;
    190         }
    191         mConnected = true;
    192         mCallbacks.onConnected(network);
    193     }
    194 
    195     /**
    196      * Handle network disconnected event.
    197      */
    198     private void handleDisconnectedEvent() {
    199         if (!mConnected) {
    200             // No-op if not connected, most likely a disconnect event for a different network.
    201             return;
    202         }
    203         mConnected = false;
    204         mCallbacks.onDisconnected();
    205     }
    206 }
    207