1 /* 2 * Copyright (C) 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.tv.settings.connectivity; 18 19 import com.android.tv.settings.connectivity.ConnectivityListener; 20 import com.android.tv.settings.connectivity.SaveWifiConfigurationFragment.Listener; 21 import com.android.tv.settings.connectivity.setup.MessageWizardFragment; 22 import com.android.tv.settings.form.FormPage; 23 24 import android.app.Activity; 25 import android.app.Fragment; 26 import android.content.BroadcastReceiver; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.IntentFilter; 30 import android.net.ConnectivityManager; 31 import android.net.NetworkInfo; 32 import android.net.wifi.SupplicantState; 33 import android.net.wifi.WifiConfiguration; 34 import android.net.wifi.WifiInfo; 35 import android.net.wifi.WifiManager; 36 import android.os.Bundle; 37 import android.os.Handler; 38 import android.os.Message; 39 import android.util.Log; 40 41 import java.util.List; 42 43 /** 44 * Connects to the wifi network specified by the given configuration. 45 */ 46 public class ConnectToWifiFragment extends MessageWizardFragment 47 implements ConnectivityListener.Listener { 48 49 public interface Listener { onConnectToWifiCompleted(int reason)50 void onConnectToWifiCompleted(int reason); 51 } 52 53 private static final String TAG = "ConnectToWifiFragment"; 54 private static final boolean DEBUG = false; 55 56 public static final int RESULT_SUCCESS = 0; 57 public static final int RESULT_UNKNOWN_ERROR= 1; 58 public static final int RESULT_TIMEOUT = 2; 59 public static final int RESULT_BAD_AUTHENTICATION = 3; 60 public static final int RESULT_REJECTED_BY_AP = 4; 61 62 private static final String EXTRA_CONFIGURATION = "configuration"; 63 private static final int MSG_TIMEOUT = 1; 64 private static final int CONNECTION_TIMEOUT = 15000; 65 newInstance(String title, boolean showProgressIndicator, WifiConfiguration configuration)66 public static ConnectToWifiFragment newInstance(String title, boolean showProgressIndicator, 67 WifiConfiguration configuration) { 68 ConnectToWifiFragment fragment = new ConnectToWifiFragment(); 69 Bundle args = new Bundle(); 70 args.putParcelable(EXTRA_CONFIGURATION, configuration); 71 addArguments(args, title, showProgressIndicator); 72 fragment.setArguments(args); 73 return fragment; 74 } 75 76 private Listener mListener; 77 private ConnectivityListener mConnectivityListener; 78 private WifiConfiguration mWifiConfiguration; 79 private WifiManager mWifiManager; 80 private Handler mHandler; 81 private BroadcastReceiver mReceiver; 82 private boolean mWasAssociating; 83 private boolean mWasAssociated; 84 private boolean mWasHandshaking; 85 private boolean mConnected; 86 87 @Override onAttach(Activity activity)88 public void onAttach(Activity activity) { 89 if (activity instanceof Listener) { 90 mListener = (Listener) activity; 91 } else { 92 throw new IllegalArgumentException("Activity must implement " 93 + "ConnectToWifiFragment.Listener to use this fragment."); 94 } 95 super.onAttach(activity); 96 } 97 98 @Override onDetach()99 public void onDetach() { 100 super.onDetach(); 101 mListener = null; 102 } 103 104 @Override onCreate(Bundle icicle)105 public void onCreate(Bundle icicle) { 106 super.onCreate(icicle); 107 108 mConnectivityListener = new ConnectivityListener(getActivity(), this); 109 mWifiConfiguration = (WifiConfiguration) getArguments().getParcelable(EXTRA_CONFIGURATION); 110 mWifiManager = ((WifiManager) getActivity().getSystemService(Context.WIFI_SERVICE)); 111 mHandler = new Handler() { 112 @Override 113 public void handleMessage(Message msg) { 114 if (DEBUG) Log.d(TAG, "Timeout waiting on supplicant state change"); 115 if (isNetworkConnected()) { 116 if (DEBUG) Log.d(TAG, "Fake timeout; we're actually connected"); 117 mConnected = true; 118 notifyListener(RESULT_SUCCESS); 119 } else { 120 if (DEBUG) Log.d(TAG, "Timeout is real; telling the listener"); 121 notifyListener(RESULT_TIMEOUT); 122 } 123 } 124 }; 125 126 IntentFilter filter = new IntentFilter(); 127 filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); 128 mReceiver = new BroadcastReceiver() { 129 @Override 130 public void onReceive(Context context, Intent intent) { 131 if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(intent.getAction())) { 132 SupplicantState state = (SupplicantState) intent.getParcelableExtra( 133 WifiManager.EXTRA_NEW_STATE); 134 if (DEBUG) { 135 Log.d(TAG, "Got supplicant state: " + state.name()); 136 } 137 switch (state) { 138 case ASSOCIATING: 139 mWasAssociating = true; 140 break; 141 case ASSOCIATED: 142 mWasAssociated = true; 143 break; 144 case COMPLETED: 145 // this just means the supplicant has connected, now 146 // we wait for the rest of the framework to catch up 147 break; 148 case DISCONNECTED: 149 case DORMANT: 150 if (mWasAssociated || mWasHandshaking) { 151 notifyListener(mWasHandshaking ? RESULT_BAD_AUTHENTICATION 152 : RESULT_UNKNOWN_ERROR); 153 } 154 break; 155 case INTERFACE_DISABLED: 156 case UNINITIALIZED: 157 notifyListener(RESULT_UNKNOWN_ERROR); 158 break; 159 case FOUR_WAY_HANDSHAKE: 160 case GROUP_HANDSHAKE: 161 mWasHandshaking = true; 162 break; 163 case INACTIVE: 164 if (mWasAssociating && !mWasAssociated) { 165 // If we go inactive after 'associating' without ever having 166 // been 'associated', the AP(s) must have rejected us. 167 notifyListener(RESULT_REJECTED_BY_AP); 168 break; 169 } 170 case INVALID: 171 case SCANNING: 172 default: 173 return; 174 } 175 mHandler.removeMessages(MSG_TIMEOUT); 176 mHandler.sendEmptyMessageDelayed(MSG_TIMEOUT, CONNECTION_TIMEOUT); 177 } 178 } 179 }; 180 getActivity().registerReceiver(mReceiver, filter); 181 mConnectivityListener.start(); 182 183 if (isNetworkConnected()) { 184 mConnected = true; 185 notifyListener(RESULT_SUCCESS); 186 } else { 187 int networkId = mWifiManager.addNetwork(mWifiConfiguration); 188 if (networkId == -1) { 189 if (DEBUG) { 190 Log.d(TAG, "Failed to add network!"); 191 } 192 notifyListener(RESULT_UNKNOWN_ERROR); 193 } else if (!mWifiManager.enableNetwork(networkId, true)) { 194 if (DEBUG) { 195 Log.d(TAG, "Failed to enable network id " + networkId + "!"); 196 } 197 notifyListener(RESULT_UNKNOWN_ERROR); 198 } else if (!mWifiManager.reconnect()) { 199 if (DEBUG) { 200 Log.d(TAG, "Failed to reconnect!"); 201 } 202 notifyListener(RESULT_UNKNOWN_ERROR); 203 } else { 204 mHandler.sendEmptyMessageDelayed(MSG_TIMEOUT, CONNECTION_TIMEOUT); 205 } 206 } 207 } 208 209 @Override onDestroy()210 public void onDestroy() { 211 if (!mConnected) { 212 mWifiManager.disconnect(); 213 } 214 getActivity().unregisterReceiver(mReceiver); 215 mConnectivityListener.stop(); 216 mHandler.removeMessages(MSG_TIMEOUT); 217 super.onDestroy(); 218 } 219 220 @Override onConnectivityChange(Intent intent)221 public void onConnectivityChange(Intent intent) { 222 if (DEBUG) Log.d(TAG, "Connectivity changed"); 223 if (isNetworkConnected()) { 224 mConnected = true; 225 notifyListener(RESULT_SUCCESS); 226 } 227 } 228 notifyListener(int result)229 private void notifyListener(int result) { 230 if (mListener != null) { 231 mListener.onConnectToWifiCompleted(result); 232 mListener = null; 233 } 234 } 235 isNetworkConnected()236 private boolean isNetworkConnected() { 237 ConnectivityManager connMan = 238 (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); 239 NetworkInfo netInfo = connMan.getActiveNetworkInfo(); 240 if (netInfo == null) { 241 if (DEBUG) Log.d(TAG, "NetworkInfo is null; network is not connected"); 242 return false; 243 } 244 245 if (DEBUG) Log.d(TAG, "NetworkInfo: " + netInfo.toString()); 246 if (netInfo.isConnected() && netInfo.getType() == ConnectivityManager.TYPE_WIFI) { 247 WifiInfo currentConnection = mWifiManager.getConnectionInfo(); 248 if (DEBUG) { 249 Log.d(TAG, "Connected to " 250 + ((currentConnection == null) ? "nothing" : currentConnection.getSSID())); 251 } 252 if (currentConnection != null 253 && currentConnection.getSSID().equals(mWifiConfiguration.SSID)) { 254 return true; 255 } 256 } else { 257 if (DEBUG) Log.d(TAG, "Network is not connected"); 258 } 259 return false; 260 } 261 } 262