我们先来看一下WifiDisplay的代码,先从UI看起。 WifiDisplay是在Wifi P2P的基础上发展而来的,他的功能实现也离不开P2P。所以在WifiDisplaySettings的onCreate中,就先初始化了WifiP2P。 /packages/apps/Settings/src/com/android/settings/wfd/WifiDisplaySettings.java
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
final Context context = getActivity();
mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
mWifiP2pManager = (WifiP2pManager) context.getSystemService(Context.WIFI_P2P_SERVICE);
mWifiP2pChannel = mWifiP2pManager.initialize(context, Looper.getMainLooper(), null);
addPreferencesFromResource(R.xml.wifi_display_settings);
setHasOptionsMenu(true);
}
然后找到开启投屏的开关组件,check以后,修改数据库相关参数WIFI_DISPLAY_ON,从false置为true。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_ID_ENABLE_WIFI_DISPLAY:
mWifiDisplayOnSetting = !item.isChecked();
item.setChecked(mWifiDisplayOnSetting);
Settings.Global.putInt(getContentResolver(),
Settings.Global.WIFI_DISPLAY_ON, mWifiDisplayOnSetting ? 1 : 0);
return true;
}
return super.onOptionsItemSelected(item);
}
WifiDisplayController中从数据库查询WIFI_DISPLAY_ON参数,如果为true,表示开启WifiDisplay,然后开始一系列操作。 /frameworks/base/services/core/java/com/android/server/display/WifiDisplayController.java
private void updateSettings() {
final ContentResolver resolver = mContext.getContentResolver();
mWifiDisplayOnSetting = Settings.Global.getInt(resolver,
Settings.Global.WIFI_DISPLAY_ON, 0) != 0;
首先是修改状态,然后修改wfdinfo的相关配置信息。 WifiP2PManager也要进行相关配置,主要是setWFDInfo。
private void updateWfdEnableState() {
if (mWifiDisplayOnSetting && mWifiP2pEnabled) {
// WFD should be enabled.
if (!mWfdEnabled && !mWfdEnabling) {
mWfdEnabling = true;
WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo();
wfdInfo.setWfdEnabled(true);
wfdInfo.setDeviceType(WifiP2pWfdInfo.WFD_SOURCE);
wfdInfo.setSessionAvailable(true);
wfdInfo.setControlPort(DEFAULT_CONTROL_PORT);
wfdInfo.setMaxThroughput(MAX_THROUGHPUT);
mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() {
@Override
public void onSuccess() {
if (DEBUG) {
Slog.d(TAG, "Successfully set WFD info.");
}
if (mWfdEnabling) {
mWfdEnabling = false;
mWfdEnabled = true;
reportFeatureState();
updateScanState();
}
}
我们看setWFDInfo函数,主要是调用WifiP2pServiceImpl的checkConfigureWifiDisplayPermission方法。
public void setWFDInfo(
Channel c, WifiP2pWfdInfo wfdInfo,
ActionListener listener) {
checkChannel(c);
try {
mService.checkConfigureWifiDisplayPermission();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
c.mAsyncChannel.sendMessage(SET_WFD_INFO, 0, c.putListener(listener), wfdInfo);
}
这里是检测wfd有没有相关的权限。 /frameworks/opt/net/wifi/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
@Override
public void checkConfigureWifiDisplayPermission() {
if (!getWfdPermission(Binder.getCallingUid())) {
throw new SecurityException("Wifi Display Permission denied for uid = "
+ Binder.getCallingUid());
}
}
然后执行完以后就执行到updateScanState,就到扫描阶段了 /frameworks/base/services/core/java/com/android/server/display/WifiDisplayController.java
private void updateScanState() {
if (mScanRequested && mWfdEnabled && mDesiredDevice == null) {
if (!mDiscoverPeersInProgress) {
Slog.i(TAG, "Starting Wifi display scan.");
mDiscoverPeersInProgress = true;
handleScanStarted();
tryDiscoverPeers();
}
} else {
if (mDiscoverPeersInProgress) {
// Cancel automatic retry right away.
mHandler.removeCallbacks(mDiscoverPeers);
// Defer actually stopping discovery if we have a connection attempt in progress.
// The wifi display connection attempt often fails if we are not in discovery
// mode. So we allow discovery to continue until we give up trying to connect.
if (mDesiredDevice == null || mDesiredDevice == mConnectedDevice) {
Slog.i(TAG, "Stopping Wifi display scan.");
mDiscoverPeersInProgress = false;
stopPeerDiscovery();
handleScanFinished();
}
}
}
}