前言:最近在看WiFi相关的知识,发现WiFi direct是一种连接方式,WiFi直连(一种类似于蓝牙的传输应用)和WFD(Wifi Display)都会用到,先学习一下设置里比较熟悉的WifiP2pSettings。
WiFi P2P是Wi-Fi联盟推出的一项重要技术规范。 该规范的商品名为Wi-Fi Direct, 它支持多个Wi-Fi设备在没有AP的情况下相互连接。相对应的在连接同一个AP的情况下互相连接的叫做TDLS。WiFi联盟推出了名为TDLS(Tunneled Direct Link Setup,通道直接链路建立)的无线标准,这项标准允许两款设备通过WiFi网络进行点对点直连,与早起提倡的WiFi Direct相似,不过功能则更加完善。
Settings里对应WiFi p2p主要就是WifiP2pSettings
路径:packages/apps/Settings/src/com/android/settings/wifi/p2p/WifiP2pSettings.java
WifiP2pSettings是个fragment,内部最先调用的是onActivityCreated。
@Override
public void onActivityCreated(Bundle savedInstanceState) {
final Activity activity = getActivity();
mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
if (mWifiP2pManager != null) {
mChannel = mWifiP2pManager.initialize(activity.getApplicationContext(),
getActivity().getMainLooper(), null);
if (mChannel == null) {
//Failure to set up connection
Log.e(TAG, "Failed to set up connection with wifi p2p service");
mWifiP2pManager = null;
}
} else {
Log.e(TAG, "mWifiP2pManager is null !");
}
if (savedInstanceState != null && savedInstanceState.containsKey(SAVE_DIALOG_PEER)) {
WifiP2pDevice device = savedInstanceState.getParcelable(SAVE_DIALOG_PEER);
mSelectedWifiPeer = new WifiP2pPeer(getPrefContext(), device);
}
if (savedInstanceState != null && savedInstanceState.containsKey(SAVE_DEVICE_NAME)) {
mSavedDeviceName = savedInstanceState.getString(SAVE_DEVICE_NAME);
}
if (savedInstanceState != null && savedInstanceState.containsKey(SAVE_SELECTED_GROUP)) {
mSelectedGroupName = savedInstanceState.getString(SAVE_SELECTED_GROUP);
}
mRenameListener = new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
if (mWifiP2pManager != null) {
String name = mDeviceNameText.getText().toString();
if (name != null) {
for (int i = 0; i < name.length(); i++) {
char cur = name.charAt(i);
if(!Character.isDigit(cur) && !Character.isLetter(cur)
&& cur != '-' && cur != '_' && cur != ' ') {
Toast.makeText(getActivity(),
R.string.wifi_p2p_failed_rename_message,
Toast.LENGTH_LONG).show();
return;
}
}
}
mWifiP2pManager.setDeviceName(mChannel,
mDeviceNameText.getText().toString(),
new WifiP2pManager.ActionListener() {
public void onSuccess() {
if (DBG) Log.d(TAG, " device rename success");
}
public void onFailure(int reason) {
Toast.makeText(getActivity(),
R.string.wifi_p2p_failed_rename_message,
Toast.LENGTH_LONG).show();
}
});
}
}
}
};
//disconnect dialog listener
mDisconnectListener = new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
if (mWifiP2pManager != null) {
mWifiP2pManager.removeGroup(mChannel, new WifiP2pManager.ActionListener() {
public void onSuccess() {
if (DBG) Log.d(TAG, " remove group success");
}
public void onFailure(int reason) {
if (DBG) Log.d(TAG, " remove group fail " + reason);
}
});
}
}
}
};
//cancel connect dialog listener
mCancelConnectListener = new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
if (mWifiP2pManager != null) {
mWifiP2pManager.cancelConnect(mChannel,
new WifiP2pManager.ActionListener() {
public void onSuccess() {
if (DBG) Log.d(TAG, " cancel connect success");
}
public void onFailure(int reason) {
if (DBG) Log.d(TAG, " cancel connect fail " + reason);
}
});
}
}
}
};
//delete persistent group dialog listener
mDeleteGroupListener = new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
if (mWifiP2pManager != null) {
if (mSelectedGroup != null) {
if (DBG) Log.d(TAG, " deleting group " + mSelectedGroup.getGroupName());
mWifiP2pManager.deletePersistentGroup(mChannel,
mSelectedGroup.getNetworkId(),
new WifiP2pManager.ActionListener() {
public void onSuccess() {
if (DBG) Log.d(TAG, " delete group success");
}
public void onFailure(int reason) {
if (DBG) Log.d(TAG, " delete group fail " + reason);
}
});
mSelectedGroup = null;
} else {
if (DBG) Log.w(TAG, " No selected group to delete!");
}
}
} else if (which == DialogInterface.BUTTON_NEGATIVE) {
if (DBG) {
Log.d(TAG, " forgetting selected group " + mSelectedGroup.getGroupName());
}
mSelectedGroup = null;
}
}
};
super.onActivityCreated(savedInstanceState);
}
主要干了两个事:
1.初始化了
mChannel = mWifiP2pManager.initialize(activity.getApplicationContext(),
getActivity().getMainLooper(), null);
2.初始化了四个listener,分别是mRenameListener mDisconnectListener mCancelConnectListener mDeleteGroupListener
这里主要继续看下WifiP2pManager.initialize的方法做了什么操作。
WifiP2pManager
/**
* Registers the application with the Wi-Fi framework. This function
* must be the first to be called before any p2p operations are performed.
*
* @param srcContext is the context of the source
* @param srcLooper is the Looper on which the callbacks are receivied
* @param listener for callback at loss of framework communication. Can be null.
* @return Channel instance that is necessary for performing any further p2p operations
*/
public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
Binder binder = new Binder();
Channel channel = initalizeChannel(srcContext, srcLooper, listener, getMessenger(binder),
binder);
return channel;
}
private Channel initalizeChannel(Context srcContext, Looper srcLooper, ChannelListener listener,
Messenger messenger, Binder binder) {
if (messenger == null) return null;
Channel c = new Channel(srcContext, srcLooper, listener, binder, this);
if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger)
== AsyncChannel.STATUS_SUCCESSFUL) {
return c;
} else {
c.close();
return null;
}
}
/**
* Get a reference to WifiP2pService handler. This is used to establish
* an AsyncChannel communication with WifiService
*
* @param binder A binder for the service to associate with this client.
*
* @return Messenger pointing to the WifiP2pService handler
* @hide
*/
public Messenger getMessenger(Binder binder) {
try {
return mService.getMessenger(binder);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
这里用到了AsyncChannel,简单来说就是将WifiP2pManager$Channel$P2pHandler和WifiP2pServiceImpl$ClientHandler连接上,以便后续的message通讯。
@Override
public void onResume() {
super.onResume();
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION);
final PreferenceScreen preferenceScreen = getPreferenceScreen();
getActivity().registerReceiver(mReceiver, mIntentFilter);
if (mWifiP2pManager != null) {
mWifiP2pManager.requestPeers(mChannel, WifiP2pSettings.this);
}
}
做了两件事情
1.注册了6个广播的监听器
2.调用WifiP2pManager.requestPeers来获取周围可连接设备,填充UI。
广播接收器代码如下:
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
mWifiP2pEnabled = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE,
WifiP2pManager.WIFI_P2P_STATE_DISABLED) == WifiP2pManager.WIFI_P2P_STATE_ENABLED;
handleP2pStateChanged();
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
mPeers = (WifiP2pDeviceList) intent.getParcelableExtra(
WifiP2pManager.EXTRA_P2P_DEVICE_LIST);
handlePeersChanged();
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
if (mWifiP2pManager == null) return;
NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(
WifiP2pManager.EXTRA_NETWORK_INFO);
WifiP2pInfo wifip2pinfo = (WifiP2pInfo) intent.getParcelableExtra(
WifiP2pManager.EXTRA_WIFI_P2P_INFO);
if (networkInfo.isConnected()) {
if (DBG) Log.d(TAG, "Connected");
} else if (mLastGroupFormed != true) {
//start a search when we are disconnected
//but not on group removed broadcast event
startSearch();
}
mLastGroupFormed = wifip2pinfo.groupFormed;
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
mThisDevice = (WifiP2pDevice) intent.getParcelableExtra(
WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);
if (DBG) Log.d(TAG, "Update device info: " + mThisDevice);
mThisDevicePreferenceController.updateDeviceName(mThisDevice);
} else if (WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action)) {
int discoveryState = intent.getIntExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE,
WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED);
if (DBG) Log.d(TAG, "Discovery state changed: " + discoveryState);
if (discoveryState == WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED) {
updateSearchMenu(true);
} else {
updateSearchMenu(false);
}
} else if (WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION.equals(action)) {
if (mWifiP2pManager != null) {
mWifiP2pManager.requestPersistentGroupInfo(mChannel, WifiP2pSettings.this);
}
}
}
};
发现在接收到WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION消息的时候会调用startSearch方法
private void startSearch() {
if (mWifiP2pManager != null && !mWifiP2pSearching) {
mWifiP2pManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
public void onSuccess() {
}
public void onFailure(int reason) {
if (DBG) Log.d(TAG, " discover fail " + reason);
}
});
}
}
WifiP2pManager
/**
* Initiate peer discovery. A discovery process involves scanning for available Wi-Fi peers
* for the purpose of establishing a connection.
*
* The function call immediately returns after sending a discovery request
* to the framework. The application is notified of a success or failure to initiate
* discovery through listener callbacks {@link ActionListener#onSuccess} or
* {@link ActionListener#onFailure}.
*
*
The discovery remains active until a connection is initiated or
* a p2p group is formed. Register for {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent to
* determine when the framework notifies of a change as peers are discovered.
*
*
Upon receiving a {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent, an application
* can request for the list of peers using {@link #requestPeers}.
*
* @param c is the channel created at {@link #initialize}
* @param listener for callbacks on success or failure. Can be null.
*/
public void discoverPeers(Channel c, ActionListener listener) {
checkChannel(c);
c.mAsyncChannel.sendMessage(DISCOVER_PEERS, 0, c.putListener(listener));
}
看API注释里讲
观察到WifiP2pSettings里有监听这个消息做mPeers和界面的刷新处理。
WifiP2pSettings:
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
mPeers = (WifiP2pDeviceList) intent.getParcelableExtra(
WifiP2pManager.EXTRA_P2P_DEVICE_LIST);
handlePeersChanged();
之前梳理过了这个DISCOVER_PEERS消息会发送给WifiP2pServiceImpl来继续处理。
WifiP2pServiceImpl:
/**
* Handles client connections
*/
private class ClientHandler extends WifiHandler {
ClientHandler(String tag, android.os.Looper looper) {
super(tag, looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case WifiP2pManager.SET_DEVICE_NAME:
case WifiP2pManager.SET_WFD_INFO:
case WifiP2pManager.DISCOVER_PEERS:
case WifiP2pManager.STOP_DISCOVERY:
case WifiP2pManager.CONNECT:
case WifiP2pManager.CANCEL_CONNECT:
case WifiP2pManager.CREATE_GROUP:
case WifiP2pManager.REMOVE_GROUP:
case WifiP2pManager.START_LISTEN:
case WifiP2pManager.STOP_LISTEN:
case WifiP2pManager.SET_CHANNEL:
case WifiP2pManager.START_WPS:
case WifiP2pManager.ADD_LOCAL_SERVICE:
case WifiP2pManager.REMOVE_LOCAL_SERVICE:
case WifiP2pManager.CLEAR_LOCAL_SERVICES:
case WifiP2pManager.DISCOVER_SERVICES:
case WifiP2pManager.ADD_SERVICE_REQUEST:
case WifiP2pManager.REMOVE_SERVICE_REQUEST:
case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
case WifiP2pManager.REQUEST_PEERS:
case WifiP2pManager.REQUEST_CONNECTION_INFO:
case WifiP2pManager.REQUEST_GROUP_INFO:
case WifiP2pManager.DELETE_PERSISTENT_GROUP:
case WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO:
mP2pStateMachine.sendMessage(Message.obtain(msg));
break;
default:
Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg);
break;
}
}
}
熟悉的状态机P2pEnabledState会做如下处理:
case WifiP2pManager.DISCOVER_PEERS:
if (mDiscoveryBlocked) {
replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
WifiP2pManager.BUSY);
break;
}
// do not send service discovery request while normal find operation.
clearSupplicantServiceRequest();
if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {
replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED);
sendP2pDiscoveryChangedBroadcast(true);
} else {
replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
WifiP2pManager.ERROR);
}
break;
// Set a two minute discover timeout to avoid STA scans from being blocked
private static final int DISCOVER_TIMEOUT_S = 120;
有个120s的timeout限制。
WifiNative:
/**
* Initiate a P2P service discovery with a (optional) timeout.
*
* @param timeout Max time to be spent is peforming discovery.
* Set to 0 to indefinely continue discovery untill and explicit
* |stopFind| is sent.
* @return boolean value indicating whether operation was successful.
*/
public boolean p2pFind(int timeout) {
return mSupplicantP2pIfaceHal.find(timeout);
}
SupplicantP2pIfaceHal:
/**
* Initiate a P2P service discovery with a (optional) timeout.
*
* @param timeout Max time to be spent is peforming discovery.
* Set to 0 to indefinely continue discovery untill and explicit
* |stopFind| is sent.
* @return boolean value indicating whether operation was successful.
*/
public boolean find(int timeout) {
synchronized (mLock) {
if (!checkSupplicantP2pIfaceAndLogFailure("find")) return false;
if (timeout < 0) {
Log.e(TAG, "Invalid timeout value: " + timeout);
return false;
}
SupplicantResult result = new SupplicantResult("find(" + timeout + ")");
try {
result.setResult(mISupplicantP2pIface.find(timeout));
} catch (RemoteException e) {
Log.e(TAG, "ISupplicantP2pIface exception: " + e);
supplicantServiceDiedHandler();
}
return result.isSuccess();
}
}
WifiP2pManager:
/**
* Request the current list of peers.
*
* @param c is the channel created at {@link #initialize}
* @param listener for callback when peer list is available. Can be null.
*/
public void requestPeers(Channel c, PeerListListener listener) {
checkChannel(c);
Bundle callingPackage = new Bundle();
callingPackage.putString(CALLING_PACKAGE, c.mContext.getOpPackageName());
c.mAsyncChannel.sendMessage(REQUEST_PEERS, 0, c.putListener(listener),
callingPackage);
}
WifiP2pServiceImpl:
DefaultState会处理该消息,并回复给WifiP2pManager
case WifiP2pManager.REQUEST_PEERS:
replyToMessage(message, WifiP2pManager.RESPONSE_PEERS,
getPeers((Bundle) message.obj, message.sendingUid));
break;
WifiManager:
case RESPONSE_PEERS:
WifiP2pDeviceList peers = (WifiP2pDeviceList) message.obj;
if (listener != null) {
((PeerListListener) listener).onPeersAvailable(peers);
}
break;
WifiP2pSettings:
@Override
public void onPeersAvailable(WifiP2pDeviceList peers) {
if (DBG) Log.d(TAG, "Requested peers are available");
mPeers = peers;
handlePeersChanged();
}
private void handlePeersChanged() {
mPeerCategoryController.removeAllChildren();
mConnectedDevices = 0;
if (DBG) Log.d(TAG, "List of available peers");
for (WifiP2pDevice peer: mPeers.getDeviceList()) {
if (DBG) Log.d(TAG, "-> " + peer);
mPeerCategoryController.addChild(new WifiP2pPeer(getPrefContext(), peer));
if (peer.status == WifiP2pDevice.CONNECTED) mConnectedDevices++;
}
if (DBG) Log.d(TAG, " mConnectedDevices " + mConnectedDevices);
}
简单来看调用framework和回调获取扫描结果流程已经借宿了,回过头来看下WifiP2pServiceImpl的getPeers方法:
WifiP2pServiceImpl
case WifiP2pManager.REQUEST_PEERS:
replyToMessage(message, WifiP2pManager.RESPONSE_PEERS,
getPeers((Bundle) message.obj, message.sendingUid));
break;
/**
* Enforces permissions on the caller who is requesting for P2p Peers
* @param pkg Bundle containing the calling package string
* @param uid of the caller
* @return WifiP2pDeviceList the peer list
*/
private WifiP2pDeviceList getPeers(Bundle pkg, int uid) {
String pkgName = pkg.getString(WifiP2pManager.CALLING_PACKAGE);
boolean scanPermission = false;
WifiPermissionsUtil wifiPermissionsUtil;
// getPeers() is guaranteed to be invoked after Wifi Service is up
// This ensures getInstance() will return a non-null object now
if (mWifiInjector == null) {
mWifiInjector = WifiInjector.getInstance();
}
wifiPermissionsUtil = mWifiInjector.getWifiPermissionsUtil();
// Minimum Version to enforce location permission is O or later
try {
scanPermission = wifiPermissionsUtil.canAccessScanResults(pkgName, uid,
Build.VERSION_CODES.O);
} catch (SecurityException e) {
Log.e(TAG, "Security Exception, cannot access peer list");
}
if (scanPermission) {
return new WifiP2pDeviceList(mPeers);
} else {
return new WifiP2pDeviceList();
}
}
}
这个方法只是校验了下权限,然后将mPeers封装出来了,mPeers应该是之前扫描结果封装起来的。
而mPeers的加载成员只有调用如下方法:
WifiP2pDeviceList:
/** Only updates details fetched from the supplicant @hide */
public void updateSupplicantDetails(WifiP2pDevice device) {
validateDevice(device);
WifiP2pDevice d = mDevices.get(device.deviceAddress);
if (d != null) {
d.deviceName = device.deviceName;
d.primaryDeviceType = device.primaryDeviceType;
d.secondaryDeviceType = device.secondaryDeviceType;
d.wpsConfigMethodsSupported = device.wpsConfigMethodsSupported;
d.deviceCapability = device.deviceCapability;
d.groupCapability = device.groupCapability;
d.wfdInfo = device.wfdInfo;
return;
}
//Not found, add a new one
mDevices.put(device.deviceAddress, device);
}
只有在WifiP2pServiceImpl$P2pEnabledState状态处理P2P_DEVICE_FOUND_EVENT的时候加载
case WifiP2pMonitor.P2P_DEVICE_FOUND_EVENT:
if (message.obj == null) {
Log.e(TAG, "Illegal argument(s)");
break;
}
WifiP2pDevice device = (WifiP2pDevice) message.obj;
if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break;
mPeers.updateSupplicantDetails(device);
sendPeersChangedBroadcast();
break;
这个消息应该是WifiMonitor监听到supplicant返回来告知WifiP2pServiceImpl$P2pEnabledState处理的。
mWifiMonitor.registerHandler(interfaceName,
WifiP2pMonitor.P2P_DEVICE_FOUND_EVENT, getHandler());
看下wifi p2p connect流程
WifiP2pSettings:
@Override
public boolean onPreferenceTreeClick(Preference preference) {
if (preference instanceof WifiP2pPeer) {
mSelectedWifiPeer = (WifiP2pPeer) preference;
if (mSelectedWifiPeer.device.status == WifiP2pDevice.CONNECTED) {
showDialog(DIALOG_DISCONNECT);
} else if (mSelectedWifiPeer.device.status == WifiP2pDevice.INVITED) {
showDialog(DIALOG_CANCEL_CONNECT);
} else {
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = mSelectedWifiPeer.device.deviceAddress;
int forceWps = SystemProperties.getInt("wifidirect.wps", -1);
if (forceWps != -1) {
config.wps.setup = forceWps;
} else {
if (mSelectedWifiPeer.device.wpsPbcSupported()) {
config.wps.setup = WpsInfo.PBC;
} else if (mSelectedWifiPeer.device.wpsKeypadSupported()) {
config.wps.setup = WpsInfo.KEYPAD;
} else {
config.wps.setup = WpsInfo.DISPLAY;
}
}
mWifiP2pManager.connect(mChannel, config,
new WifiP2pManager.ActionListener() {
public void onSuccess() {
if (DBG) Log.d(TAG, " connect success");
}
public void onFailure(int reason) {
Log.e(TAG, " connect fail " + reason);
Toast.makeText(getActivity(),
R.string.wifi_p2p_failed_connect_message,
Toast.LENGTH_SHORT).show();
}
});
}
} else if (preference instanceof WifiP2pPersistentGroup) {
mSelectedGroup = (WifiP2pPersistentGroup) preference;
showDialog(DIALOG_DELETE_GROUP);
}
return super.onPreferenceTreeClick(preference);
}
WifiP2pManager:
/**
* Start a p2p connection to a device with the specified configuration.
*
* The function call immediately returns after sending a connection request
* to the framework. The application is notified of a success or failure to initiate
* connect through listener callbacks {@link ActionListener#onSuccess} or
* {@link ActionListener#onFailure}.
*
*
Register for {@link #WIFI_P2P_CONNECTION_CHANGED_ACTION} intent to
* determine when the framework notifies of a change in connectivity.
*
*
If the current device is not part of a p2p group, a connect request initiates
* a group negotiation with the peer.
*
*
If the current device is part of an existing p2p group or has created
* a p2p group with {@link #createGroup}, an invitation to join the group is sent to
* the peer device.
*
* @param c is the channel created at {@link #initialize}
* @param config options as described in {@link WifiP2pConfig} class
* @param listener for callbacks on success or failure. Can be null.
*/
public void connect(Channel c, WifiP2pConfig config, ActionListener listener) {
checkChannel(c);
checkP2pConfig(config);
c.mAsyncChannel.sendMessage(CONNECT, 0, c.putListener(listener), config);
}
WifiP2pServiceImpl$GroupCreatedState(看InactiveState也会处理)
case WifiP2pManager.CONNECT:
WifiP2pConfig config = (WifiP2pConfig) message.obj;
if (isConfigInvalid(config)) {
loge("Dropping connect request " + config);
replyToMessage(message, WifiP2pManager.CONNECT_FAILED);
break;
}
logd("Inviting device : " + config.deviceAddress);
mSavedPeerConfig = config;
if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) {
mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED);
sendPeersChangedBroadcast();
replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
WifiP2pManager.ERROR);
}
// TODO: figure out updating the status to declined
// when invitation is rejected
break;
WifiNative
/**
* Invite a device to a persistent group.
* If the peer device is the group owner of the persistent group, the peer
* parameter is not needed. Otherwise it is used to specify which
* device to invite. |goDeviceAddress| parameter may be used to override
* the group owner device address for Invitation Request should it not be
* known for some reason (this should not be needed in most cases).
*
* @param group Group object to use.
* @param deviceAddress MAC address of the device to invite.
*
* @return boolean value indicating whether operation was successful.
*/
public boolean p2pInvite(WifiP2pGroup group, String deviceAddress) {
return mSupplicantP2pIfaceHal.invite(group, deviceAddress);
}
SupplicantP2pIfaceHal
/**
* Invite a device to a persistent group.
* If the peer device is the group owner of the persistent group, the peer
* parameter is not needed. Otherwise it is used to specify which
* device to invite. |goDeviceAddress| parameter may be used to override
* the group owner device address for Invitation Request should it not be
* known for some reason (this should not be needed in most cases).
*
* @param group Group object to use.
* @param peerAddress MAC address of the device to invite.
*
* @return boolean value indicating whether operation was successful.
*/
public boolean invite(WifiP2pGroup group, String peerAddress) {
if (TextUtils.isEmpty(peerAddress)) return false;
synchronized (mLock) {
if (!checkSupplicantP2pIfaceAndLogFailure("invite")) return false;
if (group == null) {
Log.e(TAG, "Cannot invite to null group.");
return false;
}
if (group.getOwner() == null) {
Log.e(TAG, "Cannot invite to group with null owner.");
return false;
}
if (group.getOwner().deviceAddress == null) {
Log.e(TAG, "Group owner has no mac address.");
return false;
}
byte[] ownerMacAddress = null;
try {
ownerMacAddress = NativeUtil.macAddressToByteArray(group.getOwner().deviceAddress);
} catch (Exception e) {
Log.e(TAG, "Group owner mac address parse error.", e);
return false;
}
if (peerAddress == null) {
Log.e(TAG, "Cannot parse peer mac address.");
return false;
}
byte[] peerMacAddress;
try {
peerMacAddress = NativeUtil.macAddressToByteArray(peerAddress);
} catch (Exception e) {
Log.e(TAG, "Peer mac address parse error.", e);
return false;
}
SupplicantResult result = new SupplicantResult(
"invite(" + group.getInterface() + ", " + group.getOwner().deviceAddress
+ ", " + peerAddress + ")");
try {
result.setResult(mISupplicantP2pIface.invite(
group.getInterface(), ownerMacAddress, peerMacAddress));
} catch (RemoteException e) {
Log.e(TAG, "ISupplicantP2pIface exception: " + e);
supplicantServiceDiedHandler();
}
return result.isSuccess();
}
}
先梳理到这。。。