WifiDisplayControllerpublic final class WifiDisplayController extends Object implements DumpUtils.DumpManages all of the various asynchronous interactions with the {@link WifiP2pManager}
on behalf of {@link WifiDisplayAdapter}.
This code is isolated from {@link WifiDisplayAdapter} so that we can avoid
accidentally introducing any deadlocks due to the display manager calling
outside of itself while holding its lock. It's also way easier to write this
asynchronous code if we can assume that it is single-threaded.
The controller must be instantiated on the handler thread.
|
Fields Summary |
---|
private static final String | TAG | private static final boolean | DEBUG | private static final int | DEFAULT_CONTROL_PORT | private static final int | MAX_THROUGHPUT | private static final int | CONNECTION_TIMEOUT_SECONDS | private static final int | RTSP_TIMEOUT_SECONDS | private static final int | RTSP_TIMEOUT_SECONDS_CERT_MODE | private static final int | DISCOVER_PEERS_INTERVAL_MILLIS | private static final int | CONNECT_MAX_RETRIES | private static final int | CONNECT_RETRY_DELAY_MILLIS | private final android.content.Context | mContext | private final android.os.Handler | mHandler | private final Listener | mListener | private final android.net.wifi.p2p.WifiP2pManager | mWifiP2pManager | private final android.net.wifi.p2p.WifiP2pManager.Channel | mWifiP2pChannel | private boolean | mWifiP2pEnabled | private boolean | mWfdEnabled | private boolean | mWfdEnabling | private android.net.NetworkInfo | mNetworkInfo | private final ArrayList | mAvailableWifiDisplayPeers | private boolean | mWifiDisplayOnSetting | private boolean | mScanRequested | private boolean | mDiscoverPeersInProgress | private android.net.wifi.p2p.WifiP2pDevice | mDesiredDevice | private android.net.wifi.p2p.WifiP2pDevice | mConnectingDevice | private android.net.wifi.p2p.WifiP2pDevice | mDisconnectingDevice | private android.net.wifi.p2p.WifiP2pDevice | mCancelingDevice | private android.net.wifi.p2p.WifiP2pDevice | mConnectedDevice | private android.net.wifi.p2p.WifiP2pGroup | mConnectedDeviceGroupInfo | private int | mConnectionRetriesLeft | private android.media.RemoteDisplay | mRemoteDisplay | private String | mRemoteDisplayInterface | private boolean | mRemoteDisplayConnected | private android.hardware.display.WifiDisplay | mAdvertisedDisplay | private android.view.Surface | mAdvertisedDisplaySurface | private int | mAdvertisedDisplayWidth | private int | mAdvertisedDisplayHeight | private int | mAdvertisedDisplayFlags | private boolean | mWifiDisplayCertMode | private int | mWifiDisplayWpsConfig | private android.net.wifi.p2p.WifiP2pDevice | mThisDevice | private final Runnable | mDiscoverPeers | private final Runnable | mConnectionTimeout | private final Runnable | mRtspTimeout | private final android.content.BroadcastReceiver | mWifiP2pReceiver |
Constructors Summary |
---|
public WifiDisplayController(android.content.Context context, android.os.Handler handler, Listener listener)
mContext = context;
mHandler = handler;
mListener = listener;
mWifiP2pManager = (WifiP2pManager)context.getSystemService(Context.WIFI_P2P_SERVICE);
mWifiP2pChannel = mWifiP2pManager.initialize(context, handler.getLooper(), null);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
context.registerReceiver(mWifiP2pReceiver, intentFilter, null, mHandler);
ContentObserver settingsObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange, Uri uri) {
updateSettings();
}
};
final ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.WIFI_DISPLAY_ON), false, settingsObserver);
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON), false, settingsObserver);
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.WIFI_DISPLAY_WPS_CONFIG), false, settingsObserver);
updateSettings();
|
Methods Summary |
---|
private void | advertiseDisplay(android.hardware.display.WifiDisplay display, android.view.Surface surface, int width, int height, int flags)
if (!Objects.equal(mAdvertisedDisplay, display)
|| mAdvertisedDisplaySurface != surface
|| mAdvertisedDisplayWidth != width
|| mAdvertisedDisplayHeight != height
|| mAdvertisedDisplayFlags != flags) {
final WifiDisplay oldDisplay = mAdvertisedDisplay;
final Surface oldSurface = mAdvertisedDisplaySurface;
mAdvertisedDisplay = display;
mAdvertisedDisplaySurface = surface;
mAdvertisedDisplayWidth = width;
mAdvertisedDisplayHeight = height;
mAdvertisedDisplayFlags = flags;
mHandler.post(new Runnable() {
@Override
public void run() {
if (oldSurface != null && surface != oldSurface) {
mListener.onDisplayDisconnected();
} else if (oldDisplay != null && !oldDisplay.hasSameAddress(display)) {
mListener.onDisplayConnectionFailed();
}
if (display != null) {
if (!display.hasSameAddress(oldDisplay)) {
mListener.onDisplayConnecting(display);
} else if (!display.equals(oldDisplay)) {
// The address is the same but some other property such as the
// name must have changed.
mListener.onDisplayChanged(display);
}
if (surface != null && surface != oldSurface) {
mListener.onDisplayConnected(display, surface, width, height, flags);
}
}
}
});
}
| private int | computeFeatureState()
if (!mWifiP2pEnabled) {
return WifiDisplayStatus.FEATURE_STATE_DISABLED;
}
return mWifiDisplayOnSetting ? WifiDisplayStatus.FEATURE_STATE_ON :
WifiDisplayStatus.FEATURE_STATE_OFF;
| private void | connect(android.net.wifi.p2p.WifiP2pDevice device)
if (mDesiredDevice != null
&& !mDesiredDevice.deviceAddress.equals(device.deviceAddress)) {
if (DEBUG) {
Slog.d(TAG, "connect: nothing to do, already connecting to "
+ describeWifiP2pDevice(device));
}
return;
}
if (mConnectedDevice != null
&& !mConnectedDevice.deviceAddress.equals(device.deviceAddress)
&& mDesiredDevice == null) {
if (DEBUG) {
Slog.d(TAG, "connect: nothing to do, already connected to "
+ describeWifiP2pDevice(device) + " and not part way through "
+ "connecting to a different device.");
}
return;
}
if (!mWfdEnabled) {
Slog.i(TAG, "Ignoring request to connect to Wifi display because the "
+" feature is currently disabled: " + device.deviceName);
return;
}
mDesiredDevice = device;
mConnectionRetriesLeft = CONNECT_MAX_RETRIES;
updateConnection();
| private static android.hardware.display.WifiDisplay | createWifiDisplay(android.net.wifi.p2p.WifiP2pDevice device)
return new WifiDisplay(device.deviceAddress, device.deviceName, null,
true, device.wfdInfo.isSessionAvailable(), false);
| private static java.lang.String | describeWifiP2pDevice(android.net.wifi.p2p.WifiP2pDevice device)
return device != null ? device.toString().replace('\n", ',") : "null";
| private static java.lang.String | describeWifiP2pGroup(android.net.wifi.p2p.WifiP2pGroup group)
return group != null ? group.toString().replace('\n", ',") : "null";
| private void | disconnect()
mDesiredDevice = null;
updateConnection();
| public void | dump(java.io.PrintWriter pw)
pw.println("mWifiDisplayOnSetting=" + mWifiDisplayOnSetting);
pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled);
pw.println("mWfdEnabled=" + mWfdEnabled);
pw.println("mWfdEnabling=" + mWfdEnabling);
pw.println("mNetworkInfo=" + mNetworkInfo);
pw.println("mScanRequested=" + mScanRequested);
pw.println("mDiscoverPeersInProgress=" + mDiscoverPeersInProgress);
pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice));
pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice));
pw.println("mDisconnectingDisplay=" + describeWifiP2pDevice(mDisconnectingDevice));
pw.println("mCancelingDisplay=" + describeWifiP2pDevice(mCancelingDevice));
pw.println("mConnectedDevice=" + describeWifiP2pDevice(mConnectedDevice));
pw.println("mConnectionRetriesLeft=" + mConnectionRetriesLeft);
pw.println("mRemoteDisplay=" + mRemoteDisplay);
pw.println("mRemoteDisplayInterface=" + mRemoteDisplayInterface);
pw.println("mRemoteDisplayConnected=" + mRemoteDisplayConnected);
pw.println("mAdvertisedDisplay=" + mAdvertisedDisplay);
pw.println("mAdvertisedDisplaySurface=" + mAdvertisedDisplaySurface);
pw.println("mAdvertisedDisplayWidth=" + mAdvertisedDisplayWidth);
pw.println("mAdvertisedDisplayHeight=" + mAdvertisedDisplayHeight);
pw.println("mAdvertisedDisplayFlags=" + mAdvertisedDisplayFlags);
pw.println("mAvailableWifiDisplayPeers: size=" + mAvailableWifiDisplayPeers.size());
for (WifiP2pDevice device : mAvailableWifiDisplayPeers) {
pw.println(" " + describeWifiP2pDevice(device));
}
| private static java.net.Inet4Address | getInterfaceAddress(android.net.wifi.p2p.WifiP2pGroup info)
NetworkInterface iface;
try {
iface = NetworkInterface.getByName(info.getInterface());
} catch (SocketException ex) {
Slog.w(TAG, "Could not obtain address of network interface "
+ info.getInterface(), ex);
return null;
}
Enumeration<InetAddress> addrs = iface.getInetAddresses();
while (addrs.hasMoreElements()) {
InetAddress addr = addrs.nextElement();
if (addr instanceof Inet4Address) {
return (Inet4Address)addr;
}
}
Slog.w(TAG, "Could not obtain address of network interface "
+ info.getInterface() + " because it had no IPv4 addresses.");
return null;
| private static int | getPortNumber(android.net.wifi.p2p.WifiP2pDevice device)
if (device.deviceName.startsWith("DIRECT-")
&& device.deviceName.endsWith("Broadcom")) {
// These dongles ignore the port we broadcast in our WFD IE.
return 8554;
}
return DEFAULT_CONTROL_PORT;
| private android.hardware.display.WifiDisplaySessionInfo | getSessionInfo(android.net.wifi.p2p.WifiP2pGroup info, int session)
if (info == null) {
return null;
}
Inet4Address addr = getInterfaceAddress(info);
WifiDisplaySessionInfo sessionInfo = new WifiDisplaySessionInfo(
!info.getOwner().deviceAddress.equals(mThisDevice.deviceAddress),
session,
info.getOwner().deviceAddress + " " + info.getNetworkName(),
info.getPassphrase(),
(addr != null) ? addr.getHostAddress() : "");
if (DEBUG) {
Slog.d(TAG, sessionInfo.toString());
}
return sessionInfo;
| private void | handleConnectionChanged(android.net.NetworkInfo networkInfo)
mNetworkInfo = networkInfo;
if (mWfdEnabled && networkInfo.isConnected()) {
if (mDesiredDevice != null || mWifiDisplayCertMode) {
mWifiP2pManager.requestGroupInfo(mWifiP2pChannel, new GroupInfoListener() {
@Override
public void onGroupInfoAvailable(WifiP2pGroup info) {
if (DEBUG) {
Slog.d(TAG, "Received group info: " + describeWifiP2pGroup(info));
}
if (mConnectingDevice != null && !info.contains(mConnectingDevice)) {
Slog.i(TAG, "Aborting connection to Wifi display because "
+ "the current P2P group does not contain the device "
+ "we expected to find: " + mConnectingDevice.deviceName
+ ", group info was: " + describeWifiP2pGroup(info));
handleConnectionFailure(false);
return;
}
if (mDesiredDevice != null && !info.contains(mDesiredDevice)) {
disconnect();
return;
}
if (mWifiDisplayCertMode) {
boolean owner = info.getOwner().deviceAddress
.equals(mThisDevice.deviceAddress);
if (owner && info.getClientList().isEmpty()) {
// this is the case when we started Autonomous GO,
// and no client has connected, save group info
// and updateConnection()
mConnectingDevice = mDesiredDevice = null;
mConnectedDeviceGroupInfo = info;
updateConnection();
} else if (mConnectingDevice == null && mDesiredDevice == null) {
// this is the case when we received an incoming connection
// from the sink, update both mConnectingDevice and mDesiredDevice
// then proceed to updateConnection() below
mConnectingDevice = mDesiredDevice = owner ?
info.getClientList().iterator().next() : info.getOwner();
}
}
if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) {
Slog.i(TAG, "Connected to Wifi display: "
+ mConnectingDevice.deviceName);
mHandler.removeCallbacks(mConnectionTimeout);
mConnectedDeviceGroupInfo = info;
mConnectedDevice = mConnectingDevice;
mConnectingDevice = null;
updateConnection();
}
}
});
}
} else {
mConnectedDeviceGroupInfo = null;
// Disconnect if we lost the network while connecting or connected to a display.
if (mConnectingDevice != null || mConnectedDevice != null) {
disconnect();
}
// After disconnection for a group, for some reason we have a tendency
// to get a peer change notification with an empty list of peers.
// Perform a fresh scan.
if (mWfdEnabled) {
requestPeers();
}
}
| private void | handleConnectionFailure(boolean timeoutOccurred)
Slog.i(TAG, "Wifi display connection failed!");
if (mDesiredDevice != null) {
if (mConnectionRetriesLeft > 0) {
final WifiP2pDevice oldDevice = mDesiredDevice;
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (mDesiredDevice == oldDevice && mConnectionRetriesLeft > 0) {
mConnectionRetriesLeft -= 1;
Slog.i(TAG, "Retrying Wifi display connection. Retries left: "
+ mConnectionRetriesLeft);
retryConnection();
}
}
}, timeoutOccurred ? 0 : CONNECT_RETRY_DELAY_MILLIS);
} else {
disconnect();
}
}
| private void | handlePeersChanged()
// Even if wfd is disabled, it is best to get the latest set of peers to
// keep in sync with the p2p framework
requestPeers();
| private void | handleScanFinished()
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onScanFinished();
}
});
| private void | handleScanResults()
final int count = mAvailableWifiDisplayPeers.size();
final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count);
for (int i = 0; i < count; i++) {
WifiP2pDevice device = mAvailableWifiDisplayPeers.get(i);
displays[i] = createWifiDisplay(device);
updateDesiredDevice(device);
}
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onScanResults(displays);
}
});
| private void | handleScanStarted()
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onScanStarted();
}
});
| private void | handleStateChanged(boolean enabled)
mWifiP2pEnabled = enabled;
updateWfdEnableState();
| private static boolean | isPrimarySinkDeviceType(int deviceType)
return deviceType == WifiP2pWfdInfo.PRIMARY_SINK
|| deviceType == WifiP2pWfdInfo.SOURCE_OR_PRIMARY_SINK;
| private static boolean | isWifiDisplay(android.net.wifi.p2p.WifiP2pDevice device)
return device.wfdInfo != null
&& device.wfdInfo.isWfdEnabled()
&& isPrimarySinkDeviceType(device.wfdInfo.getDeviceType());
| private void | readvertiseDisplay(android.hardware.display.WifiDisplay display)
advertiseDisplay(display, mAdvertisedDisplaySurface,
mAdvertisedDisplayWidth, mAdvertisedDisplayHeight,
mAdvertisedDisplayFlags);
| private void | reportFeatureState()
final int featureState = computeFeatureState();
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onFeatureStateChanged(featureState);
}
});
| public void | requestConnect(java.lang.String address)
for (WifiP2pDevice device : mAvailableWifiDisplayPeers) {
if (device.deviceAddress.equals(address)) {
connect(device);
}
}
| public void | requestDisconnect()
disconnect();
| public void | requestPause()
if (mRemoteDisplay != null) {
mRemoteDisplay.pause();
}
| private void | requestPeers()
mWifiP2pManager.requestPeers(mWifiP2pChannel, new PeerListListener() {
@Override
public void onPeersAvailable(WifiP2pDeviceList peers) {
if (DEBUG) {
Slog.d(TAG, "Received list of peers.");
}
mAvailableWifiDisplayPeers.clear();
for (WifiP2pDevice device : peers.getDeviceList()) {
if (DEBUG) {
Slog.d(TAG, " " + describeWifiP2pDevice(device));
}
if (isWifiDisplay(device)) {
mAvailableWifiDisplayPeers.add(device);
}
}
if (mDiscoverPeersInProgress) {
handleScanResults();
}
}
});
| public void | requestResume()
if (mRemoteDisplay != null) {
mRemoteDisplay.resume();
}
| public void | requestStartScan()
if (!mScanRequested) {
mScanRequested = true;
updateScanState();
}
| public void | requestStopScan()
if (mScanRequested) {
mScanRequested = false;
updateScanState();
}
| private void | retryConnection()
// Cheap hack. Make a new instance of the device object so that we
// can distinguish it from the previous connection attempt.
// This will cause us to tear everything down before we try again.
mDesiredDevice = new WifiP2pDevice(mDesiredDevice);
updateConnection();
| private void | stopPeerDiscovery()
mWifiP2pManager.stopPeerDiscovery(mWifiP2pChannel, new ActionListener() {
@Override
public void onSuccess() {
if (DEBUG) {
Slog.d(TAG, "Stop peer discovery succeeded.");
}
}
@Override
public void onFailure(int reason) {
if (DEBUG) {
Slog.d(TAG, "Stop peer discovery failed with reason " + reason + ".");
}
}
});
| private void | tryDiscoverPeers()
mWifiP2pManager.discoverPeers(mWifiP2pChannel, new ActionListener() {
@Override
public void onSuccess() {
if (DEBUG) {
Slog.d(TAG, "Discover peers succeeded. Requesting peers now.");
}
if (mDiscoverPeersInProgress) {
requestPeers();
}
}
@Override
public void onFailure(int reason) {
if (DEBUG) {
Slog.d(TAG, "Discover peers failed with reason " + reason + ".");
}
// Ignore the error.
// We will retry automatically in a little bit.
}
});
// Retry discover peers periodically until stopped.
mHandler.postDelayed(mDiscoverPeers, DISCOVER_PEERS_INTERVAL_MILLIS);
| private void | unadvertiseDisplay()
advertiseDisplay(null, null, 0, 0, 0);
| private void | updateConnection()This function is called repeatedly after each asynchronous operation
until all preconditions for the connection have been satisfied and the
connection is established (or not).
// Step 0. Stop scans if necessary to prevent interference while connected.
// Resume scans later when no longer attempting to connect.
updateScanState();
// Step 1. Before we try to connect to a new device, tell the system we
// have disconnected from the old one.
if (mRemoteDisplay != null && mConnectedDevice != mDesiredDevice) {
Slog.i(TAG, "Stopped listening for RTSP connection on " + mRemoteDisplayInterface
+ " from Wifi display: " + mConnectedDevice.deviceName);
mRemoteDisplay.dispose();
mRemoteDisplay = null;
mRemoteDisplayInterface = null;
mRemoteDisplayConnected = false;
mHandler.removeCallbacks(mRtspTimeout);
mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_DISABLED);
unadvertiseDisplay();
// continue to next step
}
// Step 2. Before we try to connect to a new device, disconnect from the old one.
if (mDisconnectingDevice != null) {
return; // wait for asynchronous callback
}
if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) {
Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName);
mDisconnectingDevice = mConnectedDevice;
mConnectedDevice = null;
mConnectedDeviceGroupInfo = null;
unadvertiseDisplay();
final WifiP2pDevice oldDevice = mDisconnectingDevice;
mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() {
@Override
public void onSuccess() {
Slog.i(TAG, "Disconnected from Wifi display: " + oldDevice.deviceName);
next();
}
@Override
public void onFailure(int reason) {
Slog.i(TAG, "Failed to disconnect from Wifi display: "
+ oldDevice.deviceName + ", reason=" + reason);
next();
}
private void next() {
if (mDisconnectingDevice == oldDevice) {
mDisconnectingDevice = null;
updateConnection();
}
}
});
return; // wait for asynchronous callback
}
// Step 3. Before we try to connect to a new device, stop trying to connect
// to the old one.
if (mCancelingDevice != null) {
return; // wait for asynchronous callback
}
if (mConnectingDevice != null && mConnectingDevice != mDesiredDevice) {
Slog.i(TAG, "Canceling connection to Wifi display: " + mConnectingDevice.deviceName);
mCancelingDevice = mConnectingDevice;
mConnectingDevice = null;
unadvertiseDisplay();
mHandler.removeCallbacks(mConnectionTimeout);
final WifiP2pDevice oldDevice = mCancelingDevice;
mWifiP2pManager.cancelConnect(mWifiP2pChannel, new ActionListener() {
@Override
public void onSuccess() {
Slog.i(TAG, "Canceled connection to Wifi display: " + oldDevice.deviceName);
next();
}
@Override
public void onFailure(int reason) {
Slog.i(TAG, "Failed to cancel connection to Wifi display: "
+ oldDevice.deviceName + ", reason=" + reason);
next();
}
private void next() {
if (mCancelingDevice == oldDevice) {
mCancelingDevice = null;
updateConnection();
}
}
});
return; // wait for asynchronous callback
}
// Step 4. If we wanted to disconnect, or we're updating after starting an
// autonomous GO, then mission accomplished.
if (mDesiredDevice == null) {
if (mWifiDisplayCertMode) {
mListener.onDisplaySessionInfo(getSessionInfo(mConnectedDeviceGroupInfo, 0));
}
unadvertiseDisplay();
return; // done
}
// Step 5. Try to connect.
if (mConnectedDevice == null && mConnectingDevice == null) {
Slog.i(TAG, "Connecting to Wifi display: " + mDesiredDevice.deviceName);
mConnectingDevice = mDesiredDevice;
WifiP2pConfig config = new WifiP2pConfig();
WpsInfo wps = new WpsInfo();
if (mWifiDisplayWpsConfig != WpsInfo.INVALID) {
wps.setup = mWifiDisplayWpsConfig;
} else if (mConnectingDevice.wpsPbcSupported()) {
wps.setup = WpsInfo.PBC;
} else if (mConnectingDevice.wpsDisplaySupported()) {
// We do keypad if peer does display
wps.setup = WpsInfo.KEYPAD;
} else {
wps.setup = WpsInfo.DISPLAY;
}
config.wps = wps;
config.deviceAddress = mConnectingDevice.deviceAddress;
// Helps with STA & P2P concurrency
config.groupOwnerIntent = WifiP2pConfig.MIN_GROUP_OWNER_INTENT;
WifiDisplay display = createWifiDisplay(mConnectingDevice);
advertiseDisplay(display, null, 0, 0, 0);
final WifiP2pDevice newDevice = mDesiredDevice;
mWifiP2pManager.connect(mWifiP2pChannel, config, new ActionListener() {
@Override
public void onSuccess() {
// The connection may not yet be established. We still need to wait
// for WIFI_P2P_CONNECTION_CHANGED_ACTION. However, we might never
// get that broadcast, so we register a timeout.
Slog.i(TAG, "Initiated connection to Wifi display: " + newDevice.deviceName);
mHandler.postDelayed(mConnectionTimeout, CONNECTION_TIMEOUT_SECONDS * 1000);
}
@Override
public void onFailure(int reason) {
if (mConnectingDevice == newDevice) {
Slog.i(TAG, "Failed to initiate connection to Wifi display: "
+ newDevice.deviceName + ", reason=" + reason);
mConnectingDevice = null;
handleConnectionFailure(false);
}
}
});
return; // wait for asynchronous callback
}
// Step 6. Listen for incoming RTSP connection.
if (mConnectedDevice != null && mRemoteDisplay == null) {
Inet4Address addr = getInterfaceAddress(mConnectedDeviceGroupInfo);
if (addr == null) {
Slog.i(TAG, "Failed to get local interface address for communicating "
+ "with Wifi display: " + mConnectedDevice.deviceName);
handleConnectionFailure(false);
return; // done
}
mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_SOURCE);
final WifiP2pDevice oldDevice = mConnectedDevice;
final int port = getPortNumber(mConnectedDevice);
final String iface = addr.getHostAddress() + ":" + port;
mRemoteDisplayInterface = iface;
Slog.i(TAG, "Listening for RTSP connection on " + iface
+ " from Wifi display: " + mConnectedDevice.deviceName);
mRemoteDisplay = RemoteDisplay.listen(iface, new RemoteDisplay.Listener() {
@Override
public void onDisplayConnected(Surface surface,
int width, int height, int flags, int session) {
if (mConnectedDevice == oldDevice && !mRemoteDisplayConnected) {
Slog.i(TAG, "Opened RTSP connection with Wifi display: "
+ mConnectedDevice.deviceName);
mRemoteDisplayConnected = true;
mHandler.removeCallbacks(mRtspTimeout);
if (mWifiDisplayCertMode) {
mListener.onDisplaySessionInfo(
getSessionInfo(mConnectedDeviceGroupInfo, session));
}
final WifiDisplay display = createWifiDisplay(mConnectedDevice);
advertiseDisplay(display, surface, width, height, flags);
}
}
@Override
public void onDisplayDisconnected() {
if (mConnectedDevice == oldDevice) {
Slog.i(TAG, "Closed RTSP connection with Wifi display: "
+ mConnectedDevice.deviceName);
mHandler.removeCallbacks(mRtspTimeout);
disconnect();
}
}
@Override
public void onDisplayError(int error) {
if (mConnectedDevice == oldDevice) {
Slog.i(TAG, "Lost RTSP connection with Wifi display due to error "
+ error + ": " + mConnectedDevice.deviceName);
mHandler.removeCallbacks(mRtspTimeout);
handleConnectionFailure(false);
}
}
}, mHandler);
// Use extended timeout value for certification, as some tests require user inputs
int rtspTimeout = mWifiDisplayCertMode ?
RTSP_TIMEOUT_SECONDS_CERT_MODE : RTSP_TIMEOUT_SECONDS;
mHandler.postDelayed(mRtspTimeout, rtspTimeout * 1000);
}
| private void | updateDesiredDevice(android.net.wifi.p2p.WifiP2pDevice device)
// Handle the case where the device to which we are connecting or connected
// may have been renamed or reported different properties in the latest scan.
final String address = device.deviceAddress;
if (mDesiredDevice != null && mDesiredDevice.deviceAddress.equals(address)) {
if (DEBUG) {
Slog.d(TAG, "updateDesiredDevice: new information "
+ describeWifiP2pDevice(device));
}
mDesiredDevice.update(device);
if (mAdvertisedDisplay != null
&& mAdvertisedDisplay.getDeviceAddress().equals(address)) {
readvertiseDisplay(createWifiDisplay(mDesiredDevice));
}
}
| 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();
}
}
}
| private void | updateSettings()
final ContentResolver resolver = mContext.getContentResolver();
mWifiDisplayOnSetting = Settings.Global.getInt(resolver,
Settings.Global.WIFI_DISPLAY_ON, 0) != 0;
mWifiDisplayCertMode = Settings.Global.getInt(resolver,
Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON, 0) != 0;
mWifiDisplayWpsConfig = WpsInfo.INVALID;
if (mWifiDisplayCertMode) {
mWifiDisplayWpsConfig = Settings.Global.getInt(resolver,
Settings.Global.WIFI_DISPLAY_WPS_CONFIG, WpsInfo.INVALID);
}
updateWfdEnableState();
| 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();
}
}
@Override
public void onFailure(int reason) {
if (DEBUG) {
Slog.d(TAG, "Failed to set WFD info with reason " + reason + ".");
}
mWfdEnabling = false;
}
});
}
} else {
// WFD should be disabled.
if (mWfdEnabled || mWfdEnabling) {
WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo();
wfdInfo.setWfdEnabled(false);
mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() {
@Override
public void onSuccess() {
if (DEBUG) {
Slog.d(TAG, "Successfully set WFD info.");
}
}
@Override
public void onFailure(int reason) {
if (DEBUG) {
Slog.d(TAG, "Failed to set WFD info with reason " + reason + ".");
}
}
});
}
mWfdEnabling = false;
mWfdEnabled = false;
reportFeatureState();
updateScanState();
disconnect();
}
|
|