1、注册P2P广播
通过监听广播的方式来了解系统中Wi-Fi P2P相关的信息及变化情况。下面这几个广播属于P2P特有的,其作用如下:
* WIFI_P2P_STATE_CHANGED_ACTION:用于通知系统中P2P功能的启用情况,如该功能是enable还是disable。
* WIFI_P2P_PEERS_CHANGED_ACTION:系统内部将保存搜索到的其他P2P设备信息,如果这些信息有变化,则系统将发送该广播。接收者需要通过WifiP2PManager的requestPeers函数重新获取这些P2P设备的信息。
* WIFI_P2P_CONNECTION_CHANGED_ACTION:用于通知P2P连接情况,该广播可携带WifiP2pInfo和NetworkInfo两个对象。相关信息可从这两个对象中获取。
* WIFI_P2P_THIS_DEVICE_CHANGED_ACTION:用于通知本机P2P设备信息发生了变化。
* WIFI_P2P_DISCOVERY_CHANGED_ACTION:用于通知P2P Device Discovery的工作状态,如启动或停止。
* WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION:用于通知persistent group信息发生了变化。
2、启动peersmWifiP2pManager.discoverPeers(mWifiP2pChannel, mP2pActionListenerAdapter);
这里会启用发现附近可用设备,如果发现可用连接,会收到广播WIFI_P2P_PEERS_CHANGED_ACTION,而我们代码里并没有在收到广播后去请求requestPeers,因为我们是sink端,这里discoverPeers的目的只是为了让手机能发现头盔。
3、请求连接
发现之后的选择连接对象,建立连接都在手机端
用户选择连接对象之后,头盔上收到底层发来的消息CONFIRMBTN_DIALOG_P2P_CREATE
显示链接对话框
4、允许连接
在头盔端点击允许之后,调用脚本方法:
public void onConfirmAllowClick(
{
//send sign
if(_ajoActivity != null)
{
int ret = _ajoActivity.Call<int>("onUnityToAndroid",
dialogManager.CONFIRMBTN_DIALOG_UTY_RESULT, 1, null);
}
mainMenuCtrl.onConfirmAllowClick();
}
调用android端code,CONFIRMBTN_DIALOG_UTY_RESULT
android再发消息mWifiP2pAsyncChannel.sendMessage(CONFIRMBTN_DIALOG_APP_RESULT,param1);
WifiP2pServiceImpl.java中/frameworks/opt/net/wifi/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
case CONFIRMBTN_DIALOG_APP_RESULT:
if (message.arg1 == 1) {
sendMessage(PEER_CONNECTION_USER_ACCEPT);
} else {
sendMessage(PEER_CONNECTION_USER_REJECT);
}
收到消息后发送PEER_CONNECTION_USER_ACCEPT
。
case PEER_CONNECTION_USER_ACCEPT:
mWifiNative.p2pStopFind();//停止find
if (!reinvokePersistentGroup(mSavedPeerConfig)) {
// Do negotiation when persistence fails
p2pConnectWithPinDisplay(mSavedPeerConfig);
}
mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);//更新状态
sendPeersChangedBroadcast();发送广播
transitionTo(mGroupNegotiationState);
break;
case PEER_CONNECTION_USER_REJECT:
if (DBG) logd("User rejected invitation " + mSavedPeerConfig);
transitionTo(mInactiveState);
break;
default:
return NOT_HANDLED;
收到WIFI_P2P_CONNECTION_CHANGED_ACTION
广播:
mMiracast.invokeSink()-->
Miracast.java-->
mWifiP2pManager.requestGroupInfo-->
public void onGroupInfoAvailable(-->
invokeSink2nd-->
mWifiP2pManager.requestConnectionInfo(-->
public void onConnectionInfoAvailable-->
delayedInvokeSinkThread-->
invokeSinkThread-->
new AvoidANRThread(-->
nativeMiracastSink3DUIBC(ip, port, layerstack, uibcSend3d)
连接成功。
layerstack
layerstack来自:MainActivity.onCreate-->mDisplayStackId = mSurfaceControl.initDisplay();
initDisplay中:
public int initDisplay()
{
// TODO : virtual display related section
mDisplayManager = (DisplayManager) mActivity.getSystemService(DISPLAY_SERVICE);
mDisplayManager.registerDisplayListener((MainActivity)mActivity, null);
mWindowManager = (WindowManager) mActivity.getSystemService(WINDOW_SERVICE);
mWindowManager.getDefaultDisplay().getRealSize(mRealDisplaySize);
mWindowManager.getDefaultDisplay().getMetrics(mDefaultDisplayMetrics);
mDensityDpi = mDefaultDisplayMetrics.densityDpi;
mWidth = Constants.INT_720P_WIDTH;
mHeight = Constants.INT_720P_HEIGHT;
Log.i(TAG, "mDensityDpi= "+mDensityDpi);
//创建VirtualDisplay
mVirtualDisplay = mDisplayManager.createVirtualDisplay(
DISPLAY_NAME,
mWidth,
mHeight,
mDensityDpi,
null, DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | 1 << 5,
null,
null);
// TODO : hard code set source to 720p.
// TODO : consider to use THREAD_PRIORITY_URGENT_DISPLAY to pull high the priority.
mImageThread = new HandlerThread(IMAGETHREAD_NAME);
mImageThread.start();
mImageHandler = new Handler(mImageThread.getLooper());
mImageListener.setBitmapListener(mBitmapListener);
mImageListener.rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
//创建ImageReader
mImageReader = ImageReader.newInstance(
Constants.INT_720P_WIDTH,
Constants.INT_720P_HEIGHT,
PixelFormat.RGBA_8888, 2);
//设置图像改变监听
mImageReader.setOnImageAvailableListener(mImageListener, mImageHandler);
//获得ImageSurface
mImageSurface = mImageReader.getSurface();
// TODO : assign mImageSurface to MiraCast renderer.
//把ImageSurface设置给VirtualDisplay
if (mVirtualDisplay != null) {
mVirtualDisplay.setSurface(mImageSurface);
}
return mVirtualDisplay.getDisplay().getDisplayId();
}
ImageReader,使应用能够以图片数据的形式读取绘制到Surface中的内容。
然后图像发生改变时,会回调mImageListener,把图形变化传递给unity端进行显示。也就是显示手机界面。
至于为什么头盔上创建的虚拟显示能拿到手机端的图形显示,猜测应该是连接成功的最后一步nativeMiracastSink3DUIBC(ip, port, layerstack, uibcSend3d)
native方法中进行的关联吧。