/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.tv.settings.connectivity; import com.android.tv.settings.connectivity.ConnectivityListener; import com.android.tv.settings.connectivity.SaveWifiConfigurationFragment.Listener; import com.android.tv.settings.connectivity.setup.MessageWizardFragment; import com.android.tv.settings.form.FormPage; import android.app.Activity; import android.app.Fragment; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.wifi.SupplicantState; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import java.util.List; /** * Connects to the wifi network specified by the given configuration. */ public class ConnectToWifiFragment extends MessageWizardFragment implements ConnectivityListener.Listener { public interface Listener { void onConnectToWifiCompleted(int reason); } private static final String TAG = "ConnectToWifiFragment"; private static final boolean DEBUG = false; public static final int RESULT_SUCCESS = 0; public static final int RESULT_UNKNOWN_ERROR= 1; public static final int RESULT_TIMEOUT = 2; public static final int RESULT_BAD_AUTHENTICATION = 3; public static final int RESULT_REJECTED_BY_AP = 4; private static final String EXTRA_CONFIGURATION = "configuration"; private static final int MSG_TIMEOUT = 1; private static final int CONNECTION_TIMEOUT = 15000; public static ConnectToWifiFragment newInstance(String title, boolean showProgressIndicator, WifiConfiguration configuration) { ConnectToWifiFragment fragment = new ConnectToWifiFragment(); Bundle args = new Bundle(); args.putParcelable(EXTRA_CONFIGURATION, configuration); addArguments(args, title, showProgressIndicator); fragment.setArguments(args); return fragment; } private Listener mListener; private ConnectivityListener mConnectivityListener; private WifiConfiguration mWifiConfiguration; private WifiManager mWifiManager; private Handler mHandler; private BroadcastReceiver mReceiver; private boolean mWasAssociating; private boolean mWasAssociated; private boolean mWasHandshaking; private boolean mConnected; @Override public void onAttach(Activity activity) { if (activity instanceof Listener) { mListener = (Listener) activity; } else { throw new IllegalArgumentException("Activity must implement " + "ConnectToWifiFragment.Listener to use this fragment."); } super.onAttach(activity); } @Override public void onDetach() { super.onDetach(); mListener = null; } @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); mConnectivityListener = new ConnectivityListener(getActivity(), this); mWifiConfiguration = (WifiConfiguration) getArguments().getParcelable(EXTRA_CONFIGURATION); mWifiManager = ((WifiManager) getActivity().getSystemService(Context.WIFI_SERVICE)); mHandler = new Handler() { @Override public void handleMessage(Message msg) { if (DEBUG) Log.d(TAG, "Timeout waiting on supplicant state change"); if (isNetworkConnected()) { if (DEBUG) Log.d(TAG, "Fake timeout; we're actually connected"); mConnected = true; notifyListener(RESULT_SUCCESS); } else { if (DEBUG) Log.d(TAG, "Timeout is real; telling the listener"); notifyListener(RESULT_TIMEOUT); } } }; IntentFilter filter = new IntentFilter(); filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(intent.getAction())) { SupplicantState state = (SupplicantState) intent.getParcelableExtra( WifiManager.EXTRA_NEW_STATE); if (DEBUG) { Log.d(TAG, "Got supplicant state: " + state.name()); } switch (state) { case ASSOCIATING: mWasAssociating = true; break; case ASSOCIATED: mWasAssociated = true; break; case COMPLETED: // this just means the supplicant has connected, now // we wait for the rest of the framework to catch up break; case DISCONNECTED: case DORMANT: if (mWasAssociated || mWasHandshaking) { notifyListener(mWasHandshaking ? RESULT_BAD_AUTHENTICATION : RESULT_UNKNOWN_ERROR); } break; case INTERFACE_DISABLED: case UNINITIALIZED: notifyListener(RESULT_UNKNOWN_ERROR); break; case FOUR_WAY_HANDSHAKE: case GROUP_HANDSHAKE: mWasHandshaking = true; break; case INACTIVE: if (mWasAssociating && !mWasAssociated) { // If we go inactive after 'associating' without ever having // been 'associated', the AP(s) must have rejected us. notifyListener(RESULT_REJECTED_BY_AP); break; } case INVALID: case SCANNING: default: return; } mHandler.removeMessages(MSG_TIMEOUT); mHandler.sendEmptyMessageDelayed(MSG_TIMEOUT, CONNECTION_TIMEOUT); } } }; getActivity().registerReceiver(mReceiver, filter); mConnectivityListener.start(); if (isNetworkConnected()) { mConnected = true; notifyListener(RESULT_SUCCESS); } else { int networkId = mWifiManager.addNetwork(mWifiConfiguration); if (networkId == -1) { if (DEBUG) { Log.d(TAG, "Failed to add network!"); } notifyListener(RESULT_UNKNOWN_ERROR); } else if (!mWifiManager.enableNetwork(networkId, true)) { if (DEBUG) { Log.d(TAG, "Failed to enable network id " + networkId + "!"); } notifyListener(RESULT_UNKNOWN_ERROR); } else if (!mWifiManager.reconnect()) { if (DEBUG) { Log.d(TAG, "Failed to reconnect!"); } notifyListener(RESULT_UNKNOWN_ERROR); } else { mHandler.sendEmptyMessageDelayed(MSG_TIMEOUT, CONNECTION_TIMEOUT); } } } @Override public void onDestroy() { if (!mConnected) { mWifiManager.disconnect(); } getActivity().unregisterReceiver(mReceiver); mConnectivityListener.stop(); mHandler.removeMessages(MSG_TIMEOUT); super.onDestroy(); } @Override public void onConnectivityChange(Intent intent) { if (DEBUG) Log.d(TAG, "Connectivity changed"); if (isNetworkConnected()) { mConnected = true; notifyListener(RESULT_SUCCESS); } } private void notifyListener(int result) { if (mListener != null) { mListener.onConnectToWifiCompleted(result); mListener = null; } } private boolean isNetworkConnected() { ConnectivityManager connMan = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo netInfo = connMan.getActiveNetworkInfo(); if (netInfo == null) { if (DEBUG) Log.d(TAG, "NetworkInfo is null; network is not connected"); return false; } if (DEBUG) Log.d(TAG, "NetworkInfo: " + netInfo.toString()); if (netInfo.isConnected() && netInfo.getType() == ConnectivityManager.TYPE_WIFI) { WifiInfo currentConnection = mWifiManager.getConnectionInfo(); if (DEBUG) { Log.d(TAG, "Connected to " + ((currentConnection == null) ? "nothing" : currentConnection.getSSID())); } if (currentConnection != null && currentConnection.getSSID().equals(mWifiConfiguration.SSID)) { return true; } } else { if (DEBUG) Log.d(TAG, "Network is not connected"); } return false; } }