wifi 连接,我们从 点击连接开始分析。
首先看到 onActivityCreate() 方法中写了三个Listener。(看名字就知道是监听者模式)
而这一切似乎都和 这个 WifiManager.java 息息相关。
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
mConnectListener = new WifiManager.ActionListener() {
@Override
public void onSuccess() {
}
@Override
public void onFailure(int reason) {
Activity activity = getActivity();
if (activity != null) {
Toast.makeText(activity,
R.string.wifi_failed_connect_message,
Toast.LENGTH_SHORT).show();
}
}
};
mSaveListener = new WifiManager.ActionListener() {
@Override
public void onSuccess() {
}
@Override
public void onFailure(int reason) {
Activity activity = getActivity();
if (activity != null) {
Toast.makeText(activity,
R.string.wifi_failed_save_message,
Toast.LENGTH_SHORT).show();
}
}
};
mForgetListener = new WifiManager.ActionListener() {
@Override
public void onSuccess() {
}
@Override
public void onFailure(int reason) {
Activity activity = getActivity();
if (activity != null) {
Toast.makeText(activity,
R.string.wifi_failed_forget_message,
Toast.LENGTH_SHORT).show();
}
}
};
......
}
我们再找找注册这些监听的地方:
发现有两种连接方式:
protected void connect(final WifiConfiguration config) {
mWifiManager.connect(config, mConnectListener);
}
protected void connect(final int networkId) {
mWifiManager.connect(networkId, mConnectListener);
}
在这儿被调用
@Override
public boolean onContextItemSelected(MenuItem item) {
// 我们再找找这个 mSelectedAccessPoint 变量在哪儿赋值
if (mSelectedAccessPoint == null) {
return super.onContextItemSelected(item);
}
switch (item.getItemId()) {
// 最终发现,连接的方法在这儿被调用。very good!
case MENU_ID_CONNECT: {
if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
connect(mSelectedAccessPoint.networkId);
} else if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE) {
/** Bypass dialog for unsecured networks */
mSelectedAccessPoint.generateOpenNetworkConfig();
connect(mSelectedAccessPoint.getConfig());
} else {
showDialog(mSelectedAccessPoint, true);
}
return true;
}
case MENU_ID_FORGET: {
forget();
return true;
}
case MENU_ID_MODIFY: {
showDialog(mSelectedAccessPoint, true);
return true;
}
case MENU_ID_WRITE_NFC:
showDialog(WRITE_NFC_DIALOG_ID);
return true;
}
return super.onContextItemSelected(item);
}
最终发现,mSelectedAccessPoint 在这个方法中赋值
@Override
public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
if (preference instanceof AccessPoint) {
// 这个变量就是指当前点击的 wifi
mSelectedAccessPoint = (AccessPoint) preference;
/** Bypass dialog for unsecured, unsaved, and inactive networks */
if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE &&
mSelectedAccessPoint.networkId == INVALID_NETWORK_ID &&
!mSelectedAccessPoint.isActive()) {
mSelectedAccessPoint.generateOpenNetworkConfig();
if (!savedNetworksExist) {
savedNetworksExist = true;
getActivity().invalidateOptionsMenu();
}
connect(mSelectedAccessPoint.getConfig());
} else {
showDialog(mSelectedAccessPoint, false);
}
} else {
return super.onPreferenceTreeClick(screen, preference);
}
return true;
}
继续追踪 connect 方法:注释很多哈
/**
* Connect to a network with the given configuration. The network also
* gets added to the supplicant configuration.
*
* For a new network, this function is used instead of a
* sequence of addNetwork(), enableNetwork(), saveConfiguration() and
* reconnect()
*
* @param config the set of variables that describe the configuration,
* contained in a {@link WifiConfiguration} object.
* @param listener for callbacks on success or failure. Can be null.
* @throws IllegalStateException if the WifiManager instance needs to be
* initialized again
*
* @hide
*/
public void connect(WifiConfiguration config, ActionListener listener) {
if (config == null) throw new IllegalArgumentException("config cannot be null");
validateChannel();
// Use INVALID_NETWORK_ID for arg1 when passing a config object
// arg1 is used to pass network id when the network already exists
sAsyncChannel.sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
putListener(listener), config);
}
/**
* Connect to a network with the given networkId.
*
* This function is used instead of a enableNetwork(), saveConfiguration() and
* reconnect()
*
* @param networkId the network id identifiying the network in the
* supplicant configuration list
* @param listener for callbacks on success or failure. Can be null.
* @throws IllegalStateException if the WifiManager instance needs to be
* initialized again
* @hide
*/
public void connect(int networkId, ActionListener listener) {
if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
validateChannel();
sAsyncChannel.sendMessage(CONNECT_NETWORK, networkId, putListener(listener));
}
继续追踪;原来 sAsyncChannel 是在这儿被创建的。
private void init() {
synchronized (sThreadRefLock) {
if (++sThreadRefCount == 1) {
Messenger messenger = getWifiServiceMessenger();
if (messenger == null) {
sAsyncChannel = null;
return;
}
sHandlerThread = new HandlerThread("WifiManager");
// 就是在这儿
sAsyncChannel = new AsyncChannel();
sConnected = new CountDownLatch(1);
sHandlerThread.start();
Handler handler = new ServiceHandler(sHandlerThread.getLooper());
// 这个connect 方法就是初始化的作用
sAsyncChannel.connect(mContext, handler, messenger);
try {
sConnected.await();
} catch (InterruptedException e) {
Log.e(TAG, "interrupted wait at init");
}
}
}
}
然后我们回头看 它的 sendMessage() 方法到底干了什么。
public void sendMessage(int what, int arg1, int mListener, Object obj) {
Message msg = Message.obtain();
msg.what = what;
msg.arg1 = arg1;
// 我们的监听
msg.mListener= mListener;
msg.obj = obj;
sendMessage(msg);
}
继续吧。
/**
* Send a message to the destination handler.
*
* @param msg
*/
public void sendMessage(Message msg) {
msg.replyTo = mSrcMessenger;
try {
mDstMessenger.send(msg);
} catch (RemoteException e) {
replyDisconnected(STATUS_SEND_UNSUCCESSFUL);
}
}
找找这个 mDstMessenger 是从哪儿来的?
connected 方法,是不是很熟悉。刚刚在我们的 init()方法中。
public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
if (DBG) log("connected srcHandler to the dstMessenger E");
// Initialize source fields
mSrcContext = srcContext;
mSrcHandler = srcHandler;
mSrcMessenger = new Messenger(mSrcHandler);
// Initialize destination fields
mDstMessenger = dstMessenger;
if (DBG) log("connected srcHandler to the dstMessenger X");
}
private void init() {
synchronized (sThreadRefLock) {
if (++sThreadRefCount == 1) {
// 最终发现
Messenger messenger = getWifiServiceMessenger();
再往下看看吧!
public Messenger getWifiServiceMessenger() {
try {
return mService.getWifiServiceMessenger();
} catch (RemoteException e) {
return null;
} catch (SecurityException e) {
return null;
}
}
追踪 mService.在这儿赋值。
public WifiManager(Context context, IWifiManager service) {
mContext = context;
mService = service;
init();
}
找找 WifiManager 初始化的地方:
Binder 进程间通信,咱就不再深究了。wifi 毕竟最终还是和硬件交互。
registerService(WIFI_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(WIFI_SERVICE);
IWifiManager service = IWifiManager.Stub.asInterface(b);
return new WifiManager(ctx.getOuterContext(), service);
}});
连接成功,失败都是在回调中处理。其它的好像也没有什么了。