1cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown/* 2cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Copyright (C) 2012 The Android Open Source Project 3cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * 4cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License"); 5cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * you may not use this file except in compliance with the License. 6cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * You may obtain a copy of the License at 7cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * 8cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * http://www.apache.org/licenses/LICENSE-2.0 9cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * 10cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Unless required by applicable law or agreed to in writing, software 11cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS, 12cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * See the License for the specific language governing permissions and 14cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * limitations under the License. 15cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown */ 16cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 17cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownpackage com.android.server.display; 18cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 19cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport com.android.internal.util.DumpUtils; 20cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 21cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.content.BroadcastReceiver; 2289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport android.content.ContentResolver; 23cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.content.Context; 24cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.content.Intent; 25cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.content.IntentFilter; 2689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport android.database.ContentObserver; 27e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport android.hardware.display.WifiDisplay; 281f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhangimport android.hardware.display.WifiDisplaySessionInfo; 2989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport android.hardware.display.WifiDisplayStatus; 3088469e56c8294a928e65398352e8444d66bdb75aJeff Brownimport android.media.AudioManager; 31f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brownimport android.media.RemoteDisplay; 32cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.NetworkInfo; 3389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport android.net.Uri; 346681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriffimport android.net.wifi.WpsInfo; 35cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pConfig; 36cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pDevice; 37cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pDeviceList; 38cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pGroup; 39cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pManager; 40cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pWfdInfo; 41cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pManager.ActionListener; 42cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pManager.Channel; 43cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pManager.GroupInfoListener; 44cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pManager.PeerListListener; 45cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.os.Handler; 4689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport android.provider.Settings; 47cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.util.Slog; 48f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brownimport android.view.Surface; 49cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 50cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.io.PrintWriter; 51cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.net.Inet4Address; 52cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.net.InetAddress; 53cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.net.NetworkInterface; 54cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.net.SocketException; 55cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.util.ArrayList; 56cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.util.Enumeration; 57cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 58c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brownimport libcore.util.Objects; 59c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown 60cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown/** 61cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Manages all of the various asynchronous interactions with the {@link WifiP2pManager} 62cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * on behalf of {@link WifiDisplayAdapter}. 63cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * <p> 64cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * This code is isolated from {@link WifiDisplayAdapter} so that we can avoid 65cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * accidentally introducing any deadlocks due to the display manager calling 66cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * outside of itself while holding its lock. It's also way easier to write this 67cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * asynchronous code if we can assume that it is single-threaded. 68cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p><p> 69cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * The controller must be instantiated on the handler thread. 70cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p> 71cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown */ 72cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownfinal class WifiDisplayController implements DumpUtils.Dump { 73cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private static final String TAG = "WifiDisplayController"; 74c5df37c285221d0fb113f55b9e78b35632241d3fJeff Brown private static final boolean DEBUG = false; 75cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 76cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private static final int DEFAULT_CONTROL_PORT = 7236; 77cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private static final int MAX_THROUGHPUT = 50; 782c2ca5cb7c083cd53dee00e71af99d1abf931976Irfan Sheriff private static final int CONNECTION_TIMEOUT_SECONDS = 60; 79f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown private static final int RTSP_TIMEOUT_SECONDS = 15; 801f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang private static final int RTSP_TIMEOUT_SECONDS_CERT_MODE = 120; 81cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 820cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown private static final int DISCOVER_PEERS_MAX_RETRIES = 10; 830cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown private static final int DISCOVER_PEERS_RETRY_DELAY_MILLIS = 500; 840cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown 850cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown private static final int CONNECT_MAX_RETRIES = 3; 860cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown private static final int CONNECT_RETRY_DELAY_MILLIS = 500; 870cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown 88cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private final Context mContext; 89cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private final Handler mHandler; 90cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private final Listener mListener; 9188469e56c8294a928e65398352e8444d66bdb75aJeff Brown 92cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private final WifiP2pManager mWifiP2pManager; 93cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private final Channel mWifiP2pChannel; 94cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 95cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private boolean mWifiP2pEnabled; 96cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private boolean mWfdEnabled; 97cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private boolean mWfdEnabling; 98cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private NetworkInfo mNetworkInfo; 99cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 10089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown private final ArrayList<WifiP2pDevice> mAvailableWifiDisplayPeers = 101cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown new ArrayList<WifiP2pDevice>(); 102cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 10389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown // True if Wifi display is enabled by the user. 10489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown private boolean mWifiDisplayOnSetting; 10589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown 1060cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown // True if there is a call to discoverPeers in progress. 1070cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown private boolean mDiscoverPeersInProgress; 1080cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown 1090cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown // Number of discover peers retries remaining. 1100cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown private int mDiscoverPeersRetriesLeft; 1110cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown 112cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown // The device to which we want to connect, or null if we want to be disconnected. 113cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private WifiP2pDevice mDesiredDevice; 114cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 115cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown // The device to which we are currently connecting, or null if we have already connected 116cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown // or are not trying to connect. 117cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private WifiP2pDevice mConnectingDevice; 118cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 11974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown // The device from which we are currently disconnecting. 12074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown private WifiP2pDevice mDisconnectingDevice; 12174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown 12274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown // The device to which we were previously trying to connect and are now canceling. 12374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown private WifiP2pDevice mCancelingDevice; 12474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown 125cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown // The device to which we are currently connected, which means we have an active P2P group. 126cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private WifiP2pDevice mConnectedDevice; 127cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 128cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown // The group info obtained after connecting. 129cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private WifiP2pGroup mConnectedDeviceGroupInfo; 130cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 1310cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown // Number of connection retries remaining. 1320cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown private int mConnectionRetriesLeft; 1330cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown 134f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown // The remote display that is listening on the connection. 135f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown // Created after the Wifi P2P network is connected. 136f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown private RemoteDisplay mRemoteDisplay; 137f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown 138f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown // The remote display interface. 139f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown private String mRemoteDisplayInterface; 140f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown 141f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown // True if RTSP has connected. 142f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown private boolean mRemoteDisplayConnected; 143f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown 144c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown // The information we have most recently told WifiDisplayAdapter about. 145c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown private WifiDisplay mAdvertisedDisplay; 146c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown private Surface mAdvertisedDisplaySurface; 147c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown private int mAdvertisedDisplayWidth; 148c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown private int mAdvertisedDisplayHeight; 149c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown private int mAdvertisedDisplayFlags; 150c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown 1511f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang // Certification 1521f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang private boolean mWifiDisplayCertMode; 153e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang private int mWifiDisplayWpsConfig = WpsInfo.INVALID; 154e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang 1551f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang private WifiP2pDevice mThisDevice; 1561f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang 157cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown public WifiDisplayController(Context context, Handler handler, Listener listener) { 158cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mContext = context; 159cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mHandler = handler; 160cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mListener = listener; 161cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 162cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mWifiP2pManager = (WifiP2pManager)context.getSystemService(Context.WIFI_P2P_SERVICE); 163cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mWifiP2pChannel = mWifiP2pManager.initialize(context, handler.getLooper(), null); 164cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 165cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown IntentFilter intentFilter = new IntentFilter(); 166cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); 167cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); 168cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); 1691f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); 17089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown context.registerReceiver(mWifiP2pReceiver, intentFilter, null, mHandler); 17189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown 17289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown ContentObserver settingsObserver = new ContentObserver(mHandler) { 17389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown @Override 17489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown public void onChange(boolean selfChange, Uri uri) { 17589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown updateSettings(); 17689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown } 17789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown }; 17889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown 17989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown final ContentResolver resolver = mContext.getContentResolver(); 18089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown resolver.registerContentObserver(Settings.Global.getUriFor( 18189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown Settings.Global.WIFI_DISPLAY_ON), false, settingsObserver); 1821f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang resolver.registerContentObserver(Settings.Global.getUriFor( 1831f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON), false, settingsObserver); 184e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang resolver.registerContentObserver(Settings.Global.getUriFor( 185e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang Settings.Global.WIFI_DISPLAY_WPS_CONFIG), false, settingsObserver); 18689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown updateSettings(); 18789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown } 18889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown 18989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown private void updateSettings() { 19089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown final ContentResolver resolver = mContext.getContentResolver(); 19189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown mWifiDisplayOnSetting = Settings.Global.getInt(resolver, 19289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown Settings.Global.WIFI_DISPLAY_ON, 0) != 0; 1931f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang mWifiDisplayCertMode = Settings.Global.getInt(resolver, 1941f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON, 0) != 0; 19589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown 196e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang mWifiDisplayWpsConfig = WpsInfo.INVALID; 197e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang if (mWifiDisplayCertMode) { 198e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang mWifiDisplayWpsConfig = Settings.Global.getInt(resolver, 199e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang Settings.Global.WIFI_DISPLAY_WPS_CONFIG, WpsInfo.INVALID); 200e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang } 201e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang 20289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown updateWfdEnableState(); 203cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 204cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 20574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown @Override 206cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown public void dump(PrintWriter pw) { 20789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown pw.println("mWifiDisplayOnSetting=" + mWifiDisplayOnSetting); 208cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled); 209cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown pw.println("mWfdEnabled=" + mWfdEnabled); 210cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown pw.println("mWfdEnabling=" + mWfdEnabling); 211cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown pw.println("mNetworkInfo=" + mNetworkInfo); 2120cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown pw.println("mDiscoverPeersInProgress=" + mDiscoverPeersInProgress); 2130cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown pw.println("mDiscoverPeersRetriesLeft=" + mDiscoverPeersRetriesLeft); 214cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice)); 215cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice)); 21674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown pw.println("mDisconnectingDisplay=" + describeWifiP2pDevice(mDisconnectingDevice)); 21774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown pw.println("mCancelingDisplay=" + describeWifiP2pDevice(mCancelingDevice)); 218cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown pw.println("mConnectedDevice=" + describeWifiP2pDevice(mConnectedDevice)); 2190cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown pw.println("mConnectionRetriesLeft=" + mConnectionRetriesLeft); 220f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown pw.println("mRemoteDisplay=" + mRemoteDisplay); 221f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown pw.println("mRemoteDisplayInterface=" + mRemoteDisplayInterface); 222f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown pw.println("mRemoteDisplayConnected=" + mRemoteDisplayConnected); 223c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown pw.println("mAdvertisedDisplay=" + mAdvertisedDisplay); 224c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown pw.println("mAdvertisedDisplaySurface=" + mAdvertisedDisplaySurface); 225c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown pw.println("mAdvertisedDisplayWidth=" + mAdvertisedDisplayWidth); 226c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown pw.println("mAdvertisedDisplayHeight=" + mAdvertisedDisplayHeight); 227c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown pw.println("mAdvertisedDisplayFlags=" + mAdvertisedDisplayFlags); 228cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 22989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown pw.println("mAvailableWifiDisplayPeers: size=" + mAvailableWifiDisplayPeers.size()); 23089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown for (WifiP2pDevice device : mAvailableWifiDisplayPeers) { 231cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown pw.println(" " + describeWifiP2pDevice(device)); 232cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 233cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 234cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 235e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown public void requestScan() { 236e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown discoverPeers(); 237e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown } 238e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown 239e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown public void requestConnect(String address) { 24089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown for (WifiP2pDevice device : mAvailableWifiDisplayPeers) { 241e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown if (device.deviceAddress.equals(address)) { 242e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown connect(device); 243e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown } 244e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown } 245e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown } 246e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown 2471f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang public void requestPause() { 2481f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang if (mRemoteDisplay != null) { 2491f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang mRemoteDisplay.pause(); 2501f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang } 2511f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang } 2521f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang 2531f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang public void requestResume() { 2541f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang if (mRemoteDisplay != null) { 2551f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang mRemoteDisplay.resume(); 2561f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang } 2571f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang } 2581f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang 259e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown public void requestDisconnect() { 260e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown disconnect(); 261e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown } 262e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown 26389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown private void updateWfdEnableState() { 26489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown if (mWifiDisplayOnSetting && mWifiP2pEnabled) { 26589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown // WFD should be enabled. 26689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown if (!mWfdEnabled && !mWfdEnabling) { 26789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown mWfdEnabling = true; 26889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown 26989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo(); 27089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown wfdInfo.setWfdEnabled(true); 27189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown wfdInfo.setDeviceType(WifiP2pWfdInfo.WFD_SOURCE); 27289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown wfdInfo.setSessionAvailable(true); 27389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown wfdInfo.setControlPort(DEFAULT_CONTROL_PORT); 27489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown wfdInfo.setMaxThroughput(MAX_THROUGHPUT); 27589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() { 27689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown @Override 27789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown public void onSuccess() { 27889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown if (DEBUG) { 27989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown Slog.d(TAG, "Successfully set WFD info."); 28089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown } 28189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown if (mWfdEnabling) { 28289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown mWfdEnabling = false; 28389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown mWfdEnabled = true; 28489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown reportFeatureState(); 28589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown } 286cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 287cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 28889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown @Override 28989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown public void onFailure(int reason) { 29089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown if (DEBUG) { 29189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown Slog.d(TAG, "Failed to set WFD info with reason " + reason + "."); 29289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown } 29389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown mWfdEnabling = false; 294cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 29589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown }); 29689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown } 29789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown } else { 29889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown // WFD should be disabled. 29972193e1f329ec91bfd86f977035caecb00914444Chong Zhang if (mWfdEnabled || mWfdEnabling) { 30072193e1f329ec91bfd86f977035caecb00914444Chong Zhang WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo(); 30172193e1f329ec91bfd86f977035caecb00914444Chong Zhang wfdInfo.setWfdEnabled(false); 30272193e1f329ec91bfd86f977035caecb00914444Chong Zhang mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() { 30372193e1f329ec91bfd86f977035caecb00914444Chong Zhang @Override 30472193e1f329ec91bfd86f977035caecb00914444Chong Zhang public void onSuccess() { 30572193e1f329ec91bfd86f977035caecb00914444Chong Zhang if (DEBUG) { 30672193e1f329ec91bfd86f977035caecb00914444Chong Zhang Slog.d(TAG, "Successfully set WFD info."); 30772193e1f329ec91bfd86f977035caecb00914444Chong Zhang } 30872193e1f329ec91bfd86f977035caecb00914444Chong Zhang } 30972193e1f329ec91bfd86f977035caecb00914444Chong Zhang 31072193e1f329ec91bfd86f977035caecb00914444Chong Zhang @Override 31172193e1f329ec91bfd86f977035caecb00914444Chong Zhang public void onFailure(int reason) { 31272193e1f329ec91bfd86f977035caecb00914444Chong Zhang if (DEBUG) { 31372193e1f329ec91bfd86f977035caecb00914444Chong Zhang Slog.d(TAG, "Failed to set WFD info with reason " + reason + "."); 31472193e1f329ec91bfd86f977035caecb00914444Chong Zhang } 31572193e1f329ec91bfd86f977035caecb00914444Chong Zhang } 31672193e1f329ec91bfd86f977035caecb00914444Chong Zhang }); 31772193e1f329ec91bfd86f977035caecb00914444Chong Zhang } 31889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown mWfdEnabling = false; 31989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown mWfdEnabled = false; 32089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown reportFeatureState(); 32189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown disconnect(); 322cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 323cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 324cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 32589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown private void reportFeatureState() { 32689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown final int featureState = computeFeatureState(); 32789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown mHandler.post(new Runnable() { 32889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown @Override 32989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown public void run() { 33089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown mListener.onFeatureStateChanged(featureState); 33189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown } 33289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown }); 33389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown } 33489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown 33589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown private int computeFeatureState() { 33689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown if (!mWifiP2pEnabled) { 33789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown return WifiDisplayStatus.FEATURE_STATE_DISABLED; 338e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown } 33989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown return mWifiDisplayOnSetting ? WifiDisplayStatus.FEATURE_STATE_ON : 34089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown WifiDisplayStatus.FEATURE_STATE_OFF; 341e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown } 342e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown 343cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private void discoverPeers() { 3440cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown if (!mDiscoverPeersInProgress) { 3450cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown mDiscoverPeersInProgress = true; 3460cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown mDiscoverPeersRetriesLeft = DISCOVER_PEERS_MAX_RETRIES; 347e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown handleScanStarted(); 3480cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown tryDiscoverPeers(); 3490cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown } 3500cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown } 3510cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown 3520cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown private void tryDiscoverPeers() { 353cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mWifiP2pManager.discoverPeers(mWifiP2pChannel, new ActionListener() { 354cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown @Override 355cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown public void onSuccess() { 356cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (DEBUG) { 357cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.d(TAG, "Discover peers succeeded. Requesting peers now."); 358cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 359cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 3600cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown mDiscoverPeersInProgress = false; 361cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown requestPeers(); 362cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 363cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 364cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown @Override 365cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown public void onFailure(int reason) { 366cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (DEBUG) { 367cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.d(TAG, "Discover peers failed with reason " + reason + "."); 368cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 3690cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown 3700cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown if (mDiscoverPeersInProgress) { 3710cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown if (reason == 0 && mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) { 3720cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown mHandler.postDelayed(new Runnable() { 3730cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown @Override 3740cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown public void run() { 3750cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown if (mDiscoverPeersInProgress) { 3760cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown if (mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) { 3770cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown mDiscoverPeersRetriesLeft -= 1; 3780cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown if (DEBUG) { 3790cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown Slog.d(TAG, "Retrying discovery. Retries left: " 3800cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown + mDiscoverPeersRetriesLeft); 3810cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown } 3820cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown tryDiscoverPeers(); 3830cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown } else { 384e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown handleScanFinished(); 3850cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown mDiscoverPeersInProgress = false; 3860cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown } 3870cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown } 3880cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown } 3890cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown }, DISCOVER_PEERS_RETRY_DELAY_MILLIS); 3900cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown } else { 391e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown handleScanFinished(); 3920cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown mDiscoverPeersInProgress = false; 3930cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown } 3940cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown } 395cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 396cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown }); 397cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 398cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 399cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private void requestPeers() { 400cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mWifiP2pManager.requestPeers(mWifiP2pChannel, new PeerListListener() { 401cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown @Override 402cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown public void onPeersAvailable(WifiP2pDeviceList peers) { 403cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (DEBUG) { 404cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.d(TAG, "Received list of peers."); 405cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 406cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 40789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown mAvailableWifiDisplayPeers.clear(); 408cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown for (WifiP2pDevice device : peers.getDeviceList()) { 409cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (DEBUG) { 410cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.d(TAG, " " + describeWifiP2pDevice(device)); 411cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 412cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 413cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (isWifiDisplay(device)) { 41489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown mAvailableWifiDisplayPeers.add(device); 415cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 416cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 417cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 418e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown handleScanFinished(); 419e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown } 420e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown }); 421e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown } 422cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 423e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown private void handleScanStarted() { 424e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown mHandler.post(new Runnable() { 425e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown @Override 426e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown public void run() { 427e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown mListener.onScanStarted(); 428e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown } 429e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown }); 430e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown } 431cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 432e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown private void handleScanFinished() { 43389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown final int count = mAvailableWifiDisplayPeers.size(); 434e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count); 435e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown for (int i = 0; i < count; i++) { 43674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown WifiP2pDevice device = mAvailableWifiDisplayPeers.get(i); 43774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown displays[i] = createWifiDisplay(device); 43874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown updateDesiredDevice(device); 439e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown } 440e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown 441e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown mHandler.post(new Runnable() { 442e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown @Override 443e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown public void run() { 444e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown mListener.onScanFinished(displays); 445cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 446cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown }); 447cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 448cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 44974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown private void updateDesiredDevice(WifiP2pDevice device) { 45074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown // Handle the case where the device to which we are connecting or connected 45174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown // may have been renamed or reported different properties in the latest scan. 45274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown final String address = device.deviceAddress; 45374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown if (mDesiredDevice != null && mDesiredDevice.deviceAddress.equals(address)) { 45474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown if (DEBUG) { 45574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown Slog.d(TAG, "updateDesiredDevice: new information " 45674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown + describeWifiP2pDevice(device)); 45774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown } 45874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown mDesiredDevice.update(device); 45974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown if (mAdvertisedDisplay != null 46074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown && mAdvertisedDisplay.getDeviceAddress().equals(address)) { 46174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown readvertiseDisplay(createWifiDisplay(mDesiredDevice)); 46274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown } 46374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown } 46474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown } 46574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown 466cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private void connect(final WifiP2pDevice device) { 467cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (mDesiredDevice != null 468cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown && !mDesiredDevice.deviceAddress.equals(device.deviceAddress)) { 469cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (DEBUG) { 470cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.d(TAG, "connect: nothing to do, already connecting to " 471cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown + describeWifiP2pDevice(device)); 472cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 473cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown return; 474cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 475cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 476cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (mConnectedDevice != null 477cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown && !mConnectedDevice.deviceAddress.equals(device.deviceAddress) 478cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown && mDesiredDevice == null) { 479cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (DEBUG) { 480cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.d(TAG, "connect: nothing to do, already connected to " 481cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown + describeWifiP2pDevice(device) + " and not part way through " 482cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown + "connecting to a different device."); 483cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 4840cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown return; 485cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 486cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 487cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mDesiredDevice = device; 4880cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown mConnectionRetriesLeft = CONNECT_MAX_RETRIES; 489cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown updateConnection(); 490cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 491cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 492cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private void disconnect() { 493cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mDesiredDevice = null; 494cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown updateConnection(); 495cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 496cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 4970cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown private void retryConnection() { 49889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown // Cheap hack. Make a new instance of the device object so that we 49989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown // can distinguish it from the previous connection attempt. 50089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown // This will cause us to tear everything down before we try again. 50189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown mDesiredDevice = new WifiP2pDevice(mDesiredDevice); 50289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown updateConnection(); 5030cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown } 5040cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown 505cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown /** 506cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * This function is called repeatedly after each asynchronous operation 507cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * until all preconditions for the connection have been satisfied and the 508cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * connection is established (or not). 509cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown */ 510cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private void updateConnection() { 511cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown // Step 1. Before we try to connect to a new device, tell the system we 512cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown // have disconnected from the old one. 513f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown if (mRemoteDisplay != null && mConnectedDevice != mDesiredDevice) { 514f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown Slog.i(TAG, "Stopped listening for RTSP connection on " + mRemoteDisplayInterface 515f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown + " from Wifi display: " + mConnectedDevice.deviceName); 516f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown 517f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown mRemoteDisplay.dispose(); 518f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown mRemoteDisplay = null; 519f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown mRemoteDisplayInterface = null; 520f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown mRemoteDisplayConnected = false; 521f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown mHandler.removeCallbacks(mRtspTimeout); 522f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown 523f110a3701b8d7ac435c5bb65df4dd9d758be1762Jeff Brown mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_DISABLED); 524c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown unadvertiseDisplay(); 525cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 526cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown // continue to next step 527cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 528cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 529cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown // Step 2. Before we try to connect to a new device, disconnect from the old one. 53074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown if (mDisconnectingDevice != null) { 53174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown return; // wait for asynchronous callback 53274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown } 533cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) { 534cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName); 53574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown mDisconnectingDevice = mConnectedDevice; 53674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown mConnectedDevice = null; 5371f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang mConnectedDeviceGroupInfo = null; 538cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 539c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown unadvertiseDisplay(); 540c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown 54174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown final WifiP2pDevice oldDevice = mDisconnectingDevice; 542cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() { 543cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown @Override 544cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown public void onSuccess() { 545cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.i(TAG, "Disconnected from Wifi display: " + oldDevice.deviceName); 546cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown next(); 547cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 548cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 549cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown @Override 550cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown public void onFailure(int reason) { 551cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.i(TAG, "Failed to disconnect from Wifi display: " 552cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown + oldDevice.deviceName + ", reason=" + reason); 553cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown next(); 554cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 555cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 556cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private void next() { 55774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown if (mDisconnectingDevice == oldDevice) { 55874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown mDisconnectingDevice = null; 559cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown updateConnection(); 560cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 561cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 562cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown }); 563cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown return; // wait for asynchronous callback 564cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 565cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 566cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown // Step 3. Before we try to connect to a new device, stop trying to connect 567cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown // to the old one. 56874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown if (mCancelingDevice != null) { 56974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown return; // wait for asynchronous callback 57074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown } 571cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (mConnectingDevice != null && mConnectingDevice != mDesiredDevice) { 572cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.i(TAG, "Canceling connection to Wifi display: " + mConnectingDevice.deviceName); 57374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown mCancelingDevice = mConnectingDevice; 57474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown mConnectingDevice = null; 575cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 576c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown unadvertiseDisplay(); 577cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mHandler.removeCallbacks(mConnectionTimeout); 578cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 57974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown final WifiP2pDevice oldDevice = mCancelingDevice; 580cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mWifiP2pManager.cancelConnect(mWifiP2pChannel, new ActionListener() { 581cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown @Override 582cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown public void onSuccess() { 583cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.i(TAG, "Canceled connection to Wifi display: " + oldDevice.deviceName); 584cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown next(); 585cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 586cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 587cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown @Override 588cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown public void onFailure(int reason) { 589cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.i(TAG, "Failed to cancel connection to Wifi display: " 590cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown + oldDevice.deviceName + ", reason=" + reason); 591cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown next(); 592cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 593cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 594cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private void next() { 59574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown if (mCancelingDevice == oldDevice) { 59674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown mCancelingDevice = null; 597cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown updateConnection(); 598cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 599cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 600cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown }); 601cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown return; // wait for asynchronous callback 602cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 603cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 6041f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang // Step 4. If we wanted to disconnect, or we're updating after starting an 6051f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang // autonomous GO, then mission accomplished. 606cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (mDesiredDevice == null) { 6071f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang if (mWifiDisplayCertMode) { 6081f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang mListener.onDisplaySessionInfo(getSessionInfo(mConnectedDeviceGroupInfo, 0)); 6091f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang } 610c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown unadvertiseDisplay(); 611cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown return; // done 612cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 613cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 614cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown // Step 5. Try to connect. 615cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (mConnectedDevice == null && mConnectingDevice == null) { 616cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.i(TAG, "Connecting to Wifi display: " + mDesiredDevice.deviceName); 617cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 618cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mConnectingDevice = mDesiredDevice; 619cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown WifiP2pConfig config = new WifiP2pConfig(); 6206681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff WpsInfo wps = new WpsInfo(); 621e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang if (mWifiDisplayWpsConfig != WpsInfo.INVALID) { 622e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang wps.setup = mWifiDisplayWpsConfig; 623e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang } else if (mConnectingDevice.wpsPbcSupported()) { 6246681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff wps.setup = WpsInfo.PBC; 6256681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff } else if (mConnectingDevice.wpsDisplaySupported()) { 6266681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff // We do keypad if peer does display 6276681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff wps.setup = WpsInfo.KEYPAD; 6286681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff } else { 6296681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff wps.setup = WpsInfo.DISPLAY; 6306681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff } 6316681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff config.wps = wps; 632cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown config.deviceAddress = mConnectingDevice.deviceAddress; 633e0c28d5f1358fc2d4c464f910bd04fed4b283fefIrfan Sheriff // Helps with STA & P2P concurrency 63499766cf40ed706aad36032f2107fb0c1e54fc398Irfan Sheriff config.groupOwnerIntent = WifiP2pConfig.MIN_GROUP_OWNER_INTENT; 635cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 636c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown WifiDisplay display = createWifiDisplay(mConnectingDevice); 637c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown advertiseDisplay(display, null, 0, 0, 0); 638e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown 639cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown final WifiP2pDevice newDevice = mDesiredDevice; 640cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mWifiP2pManager.connect(mWifiP2pChannel, config, new ActionListener() { 641cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown @Override 642cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown public void onSuccess() { 643cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown // The connection may not yet be established. We still need to wait 644cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown // for WIFI_P2P_CONNECTION_CHANGED_ACTION. However, we might never 645cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown // get that broadcast, so we register a timeout. 646cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.i(TAG, "Initiated connection to Wifi display: " + newDevice.deviceName); 647cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 648cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mHandler.postDelayed(mConnectionTimeout, CONNECTION_TIMEOUT_SECONDS * 1000); 649cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 650cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 651cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown @Override 652cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown public void onFailure(int reason) { 653cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (mConnectingDevice == newDevice) { 654f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown Slog.i(TAG, "Failed to initiate connection to Wifi display: " 655f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown + newDevice.deviceName + ", reason=" + reason); 656cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mConnectingDevice = null; 6570cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown handleConnectionFailure(false); 658cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 659cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 660cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown }); 661cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown return; // wait for asynchronous callback 662cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 663cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 664f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown // Step 6. Listen for incoming connections. 665f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown if (mConnectedDevice != null && mRemoteDisplay == null) { 666cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Inet4Address addr = getInterfaceAddress(mConnectedDeviceGroupInfo); 667cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (addr == null) { 668cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.i(TAG, "Failed to get local interface address for communicating " 669cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown + "with Wifi display: " + mConnectedDevice.deviceName); 6700cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown handleConnectionFailure(false); 671cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown return; // done 672cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 673cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 674f110a3701b8d7ac435c5bb65df4dd9d758be1762Jeff Brown mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_SOURCE); 675c9bd4ca005768cb30aaaa44c1171e113c13cd107Jeff Brown 676f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown final WifiP2pDevice oldDevice = mConnectedDevice; 6770f68d166e6ca45fe27410ea520967275e0733757Jeff Brown final int port = getPortNumber(mConnectedDevice); 678cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown final String iface = addr.getHostAddress() + ":" + port; 679f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown mRemoteDisplayInterface = iface; 680cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 681f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown Slog.i(TAG, "Listening for RTSP connection on " + iface 682f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown + " from Wifi display: " + mConnectedDevice.deviceName); 683f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown 684f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown mRemoteDisplay = RemoteDisplay.listen(iface, new RemoteDisplay.Listener() { 685cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown @Override 686c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown public void onDisplayConnected(Surface surface, 6871f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang int width, int height, int flags, int session) { 688f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown if (mConnectedDevice == oldDevice && !mRemoteDisplayConnected) { 689f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown Slog.i(TAG, "Opened RTSP connection with Wifi display: " 690f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown + mConnectedDevice.deviceName); 691f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown mRemoteDisplayConnected = true; 692f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown mHandler.removeCallbacks(mRtspTimeout); 693f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown 6941f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang if (mWifiDisplayCertMode) { 6951f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang mListener.onDisplaySessionInfo( 6961f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang getSessionInfo(mConnectedDeviceGroupInfo, session)); 6971f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang } 6981f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang 699f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown final WifiDisplay display = createWifiDisplay(mConnectedDevice); 700c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown advertiseDisplay(display, surface, width, height, flags); 701f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown } 702cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 703f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown 704f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown @Override 705f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown public void onDisplayDisconnected() { 706f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown if (mConnectedDevice == oldDevice) { 707f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown Slog.i(TAG, "Closed RTSP connection with Wifi display: " 708f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown + mConnectedDevice.deviceName); 709f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown mHandler.removeCallbacks(mRtspTimeout); 710f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown disconnect(); 711f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown } 712f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown } 713f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown 714f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown @Override 715f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown public void onDisplayError(int error) { 716f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown if (mConnectedDevice == oldDevice) { 717f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown Slog.i(TAG, "Lost RTSP connection with Wifi display due to error " 718f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown + error + ": " + mConnectedDevice.deviceName); 719f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown mHandler.removeCallbacks(mRtspTimeout); 720f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown handleConnectionFailure(false); 721f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown } 722f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown } 723f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown }, mHandler); 724f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown 7251f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang // Use extended timeout value for certification, as some tests require user inputs 7261f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang int rtspTimeout = mWifiDisplayCertMode ? 7271f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang RTSP_TIMEOUT_SECONDS_CERT_MODE : RTSP_TIMEOUT_SECONDS; 7281f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang 7291f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang mHandler.postDelayed(mRtspTimeout, rtspTimeout * 1000); 7301f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang } 7311f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang } 7321f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang 7331f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang private WifiDisplaySessionInfo getSessionInfo(WifiP2pGroup info, int session) { 7341f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang if (info == null) { 7351f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang return null; 7361f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang } 7371f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang Inet4Address addr = getInterfaceAddress(info); 7381f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang WifiDisplaySessionInfo sessionInfo = new WifiDisplaySessionInfo( 7391f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang !info.getOwner().deviceAddress.equals(mThisDevice.deviceAddress), 7401f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang session, 7411f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang info.getOwner().deviceAddress + " " + info.getNetworkName(), 7421f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang info.getPassphrase(), 7431f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang (addr != null) ? addr.getHostAddress() : ""); 7441f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang if (DEBUG) { 7451f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang Slog.d(TAG, sessionInfo.toString()); 746cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 7471f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang return sessionInfo; 748cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 749cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 750cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private void handleStateChanged(boolean enabled) { 75189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown mWifiP2pEnabled = enabled; 75289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown updateWfdEnableState(); 753cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 754cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 755cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private void handlePeersChanged() { 75656925d65fde7f1ac8676ada6f91d0e604645c0a5Irfan Sheriff // Even if wfd is disabled, it is best to get the latest set of peers to 75756925d65fde7f1ac8676ada6f91d0e604645c0a5Irfan Sheriff // keep in sync with the p2p framework 75856925d65fde7f1ac8676ada6f91d0e604645c0a5Irfan Sheriff requestPeers(); 759cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 760cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 761cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private void handleConnectionChanged(NetworkInfo networkInfo) { 762cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mNetworkInfo = networkInfo; 763180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown if (mWfdEnabled && networkInfo.isConnected()) { 7641f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang if (mDesiredDevice != null || mWifiDisplayCertMode) { 765cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mWifiP2pManager.requestGroupInfo(mWifiP2pChannel, new GroupInfoListener() { 766cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown @Override 767cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown public void onGroupInfoAvailable(WifiP2pGroup info) { 768cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (DEBUG) { 769cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.d(TAG, "Received group info: " + describeWifiP2pGroup(info)); 770cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 771cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 772cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (mConnectingDevice != null && !info.contains(mConnectingDevice)) { 773cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.i(TAG, "Aborting connection to Wifi display because " 774cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown + "the current P2P group does not contain the device " 77589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown + "we expected to find: " + mConnectingDevice.deviceName 77689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown + ", group info was: " + describeWifiP2pGroup(info)); 7770cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown handleConnectionFailure(false); 778cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown return; 779cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 780cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 781cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (mDesiredDevice != null && !info.contains(mDesiredDevice)) { 782cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown disconnect(); 783cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown return; 784cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 785cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 7861f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang if (mWifiDisplayCertMode) { 7871f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang boolean owner = info.getOwner().deviceAddress 7881f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang .equals(mThisDevice.deviceAddress); 7891f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang if (owner && info.getClientList().isEmpty()) { 7901f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang // this is the case when we started Autonomous GO, 7911f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang // and no client has connected, save group info 7921f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang // and updateConnection() 7931f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang mConnectingDevice = mDesiredDevice = null; 7941f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang mConnectedDeviceGroupInfo = info; 7951f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang updateConnection(); 7961f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang } else if (mConnectingDevice == null && mDesiredDevice == null) { 7971f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang // this is the case when we received an incoming connection 7981f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang // from the sink, update both mConnectingDevice and mDesiredDevice 7991f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang // then proceed to updateConnection() below 8001f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang mConnectingDevice = mDesiredDevice = owner ? 8011f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang info.getClientList().iterator().next() : info.getOwner(); 8021f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang } 8031f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang } 8041f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang 805cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) { 8060cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown Slog.i(TAG, "Connected to Wifi display: " 8070cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown + mConnectingDevice.deviceName); 808cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 809cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mHandler.removeCallbacks(mConnectionTimeout); 810cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mConnectedDeviceGroupInfo = info; 811cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mConnectedDevice = mConnectingDevice; 812cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown mConnectingDevice = null; 813cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown updateConnection(); 814cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 815cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 816cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown }); 817cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 818cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } else { 8191f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang mConnectedDeviceGroupInfo = null; 820cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown disconnect(); 821180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown 822180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown // After disconnection for a group, for some reason we have a tendency 823180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown // to get a peer change notification with an empty list of peers. 824180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown // Perform a fresh scan. 825180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown if (mWfdEnabled) { 826180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown requestPeers(); 827180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown } 828cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 829cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 830cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 831cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private final Runnable mConnectionTimeout = new Runnable() { 832cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown @Override 833cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown public void run() { 834cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) { 835cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.i(TAG, "Timed out waiting for Wifi display connection after " 836cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown + CONNECTION_TIMEOUT_SECONDS + " seconds: " 837cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown + mConnectingDevice.deviceName); 8380cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown handleConnectionFailure(true); 839cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 840cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 841cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown }; 842cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 843f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown private final Runnable mRtspTimeout = new Runnable() { 844f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown @Override 845f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown public void run() { 846f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown if (mConnectedDevice != null 847f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown && mRemoteDisplay != null && !mRemoteDisplayConnected) { 848f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown Slog.i(TAG, "Timed out waiting for Wifi display RTSP connection after " 849f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown + RTSP_TIMEOUT_SECONDS + " seconds: " 850f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown + mConnectedDevice.deviceName); 851f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown handleConnectionFailure(true); 852f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown } 853f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown } 854f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown }; 855f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown 8560cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown private void handleConnectionFailure(boolean timeoutOccurred) { 857f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown Slog.i(TAG, "Wifi display connection failed!"); 8580cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown 859f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown if (mDesiredDevice != null) { 8600cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown if (mConnectionRetriesLeft > 0) { 86189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown final WifiP2pDevice oldDevice = mDesiredDevice; 8620cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown mHandler.postDelayed(new Runnable() { 8630cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown @Override 8640cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown public void run() { 86589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown if (mDesiredDevice == oldDevice && mConnectionRetriesLeft > 0) { 86689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown mConnectionRetriesLeft -= 1; 86789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown Slog.i(TAG, "Retrying Wifi display connection. Retries left: " 86889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown + mConnectionRetriesLeft); 86989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown retryConnection(); 87089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown } 8710cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown } 8720cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown }, timeoutOccurred ? 0 : CONNECT_RETRY_DELAY_MILLIS); 8730cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown } else { 8740cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown disconnect(); 8750cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown } 876cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 877cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 878cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 879c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown private void advertiseDisplay(final WifiDisplay display, 880c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown final Surface surface, final int width, final int height, final int flags) { 881c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown if (!Objects.equal(mAdvertisedDisplay, display) 882c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown || mAdvertisedDisplaySurface != surface 883c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown || mAdvertisedDisplayWidth != width 884c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown || mAdvertisedDisplayHeight != height 885c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown || mAdvertisedDisplayFlags != flags) { 886c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown final WifiDisplay oldDisplay = mAdvertisedDisplay; 887c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown final Surface oldSurface = mAdvertisedDisplaySurface; 888c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown 889c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown mAdvertisedDisplay = display; 890c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown mAdvertisedDisplaySurface = surface; 891c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown mAdvertisedDisplayWidth = width; 892c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown mAdvertisedDisplayHeight = height; 893c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown mAdvertisedDisplayFlags = flags; 894c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown 895c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown mHandler.post(new Runnable() { 896c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown @Override 897c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown public void run() { 898c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown if (oldSurface != null && surface != oldSurface) { 899c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown mListener.onDisplayDisconnected(); 90074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown } else if (oldDisplay != null && !oldDisplay.hasSameAddress(display)) { 901c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown mListener.onDisplayConnectionFailed(); 902c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown } 903c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown 904c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown if (display != null) { 90574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown if (!display.hasSameAddress(oldDisplay)) { 906c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown mListener.onDisplayConnecting(display); 90774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown } else if (!display.equals(oldDisplay)) { 90874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown // The address is the same but some other property such as the 90974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown // name must have changed. 91074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown mListener.onDisplayChanged(display); 911c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown } 912c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown if (surface != null && surface != oldSurface) { 913c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown mListener.onDisplayConnected(display, surface, width, height, flags); 914c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown } 915c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown } 916c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown } 917c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown }); 918c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown } 919c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown } 920c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown 921c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown private void unadvertiseDisplay() { 922c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown advertiseDisplay(null, null, 0, 0, 0); 923c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown } 924c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown 92574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown private void readvertiseDisplay(WifiDisplay display) { 92674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown advertiseDisplay(display, mAdvertisedDisplaySurface, 92774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown mAdvertisedDisplayWidth, mAdvertisedDisplayHeight, 92874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown mAdvertisedDisplayFlags); 92974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown } 93074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown 931cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private static Inet4Address getInterfaceAddress(WifiP2pGroup info) { 932cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown NetworkInterface iface; 933cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown try { 934cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown iface = NetworkInterface.getByName(info.getInterface()); 935cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } catch (SocketException ex) { 936cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.w(TAG, "Could not obtain address of network interface " 937cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown + info.getInterface(), ex); 938cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown return null; 939cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 940cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 941cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Enumeration<InetAddress> addrs = iface.getInetAddresses(); 942cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown while (addrs.hasMoreElements()) { 943cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown InetAddress addr = addrs.nextElement(); 944cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (addr instanceof Inet4Address) { 945cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown return (Inet4Address)addr; 946cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 947cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 948cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 949cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.w(TAG, "Could not obtain address of network interface " 950cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown + info.getInterface() + " because it had no IPv4 addresses."); 951cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown return null; 952cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 953cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 9540f68d166e6ca45fe27410ea520967275e0733757Jeff Brown private static int getPortNumber(WifiP2pDevice device) { 9550f68d166e6ca45fe27410ea520967275e0733757Jeff Brown if (device.deviceName.startsWith("DIRECT-") 9560f68d166e6ca45fe27410ea520967275e0733757Jeff Brown && device.deviceName.endsWith("Broadcom")) { 9570f68d166e6ca45fe27410ea520967275e0733757Jeff Brown // These dongles ignore the port we broadcast in our WFD IE. 9580f68d166e6ca45fe27410ea520967275e0733757Jeff Brown return 8554; 9590f68d166e6ca45fe27410ea520967275e0733757Jeff Brown } 9600f68d166e6ca45fe27410ea520967275e0733757Jeff Brown return DEFAULT_CONTROL_PORT; 9610f68d166e6ca45fe27410ea520967275e0733757Jeff Brown } 9620f68d166e6ca45fe27410ea520967275e0733757Jeff Brown 963cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private static boolean isWifiDisplay(WifiP2pDevice device) { 9640f68d166e6ca45fe27410ea520967275e0733757Jeff Brown return device.wfdInfo != null 9650f68d166e6ca45fe27410ea520967275e0733757Jeff Brown && device.wfdInfo.isWfdEnabled() 9660f68d166e6ca45fe27410ea520967275e0733757Jeff Brown && isPrimarySinkDeviceType(device.wfdInfo.getDeviceType()); 9670f68d166e6ca45fe27410ea520967275e0733757Jeff Brown } 9680f68d166e6ca45fe27410ea520967275e0733757Jeff Brown 9690f68d166e6ca45fe27410ea520967275e0733757Jeff Brown private static boolean isPrimarySinkDeviceType(int deviceType) { 9700f68d166e6ca45fe27410ea520967275e0733757Jeff Brown return deviceType == WifiP2pWfdInfo.PRIMARY_SINK 9710f68d166e6ca45fe27410ea520967275e0733757Jeff Brown || deviceType == WifiP2pWfdInfo.SOURCE_OR_PRIMARY_SINK; 972cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 973cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 974cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private static String describeWifiP2pDevice(WifiP2pDevice device) { 975cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown return device != null ? device.toString().replace('\n', ',') : "null"; 976cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 977cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 978cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private static String describeWifiP2pGroup(WifiP2pGroup group) { 979cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown return group != null ? group.toString().replace('\n', ',') : "null"; 980cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 981cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 982e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown private static WifiDisplay createWifiDisplay(WifiP2pDevice device) { 98321f603996ed83c7a9a6c430582e8a5af5ac13c6cChong Zhang return new WifiDisplay(device.deviceAddress, device.deviceName, null, 984ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang true, device.wfdInfo.isSessionAvailable(), false); 985e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown } 986e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown 987cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown private final BroadcastReceiver mWifiP2pReceiver = new BroadcastReceiver() { 988cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown @Override 989cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown public void onReceive(Context context, Intent intent) { 990cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown final String action = intent.getAction(); 991cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) { 99289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown // This broadcast is sticky so we'll always get the initial Wifi P2P state 99389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown // on startup. 994cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown boolean enabled = (intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, 995cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown WifiP2pManager.WIFI_P2P_STATE_DISABLED)) == 996cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown WifiP2pManager.WIFI_P2P_STATE_ENABLED; 997cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (DEBUG) { 998cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.d(TAG, "Received WIFI_P2P_STATE_CHANGED_ACTION: enabled=" 999cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown + enabled); 1000cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 1001cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 1002cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown handleStateChanged(enabled); 1003cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } else if (action.equals(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)) { 1004cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (DEBUG) { 1005cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.d(TAG, "Received WIFI_P2P_PEERS_CHANGED_ACTION."); 1006cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 1007cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 1008cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown handlePeersChanged(); 1009cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) { 1010cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra( 1011cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown WifiP2pManager.EXTRA_NETWORK_INFO); 1012cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown if (DEBUG) { 1013cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown Slog.d(TAG, "Received WIFI_P2P_CONNECTION_CHANGED_ACTION: networkInfo=" 1014cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown + networkInfo); 1015cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 1016cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 1017cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown handleConnectionChanged(networkInfo); 10181f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang } else if (action.equals(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)) { 10191f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang mThisDevice = (WifiP2pDevice) intent.getParcelableExtra( 10201f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang WifiP2pManager.EXTRA_WIFI_P2P_DEVICE); 10211f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang if (DEBUG) { 10221f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang Slog.d(TAG, "Received WIFI_P2P_THIS_DEVICE_CHANGED_ACTION: mThisDevice= " 10231f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang + mThisDevice); 10241f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang } 1025cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 1026cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 1027cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown }; 1028cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown 1029cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown /** 1030cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Called on the handler thread when displays are connected or disconnected. 1031cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown */ 1032cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown public interface Listener { 103389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown void onFeatureStateChanged(int featureState); 1034e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown 1035e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown void onScanStarted(); 103689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown void onScanFinished(WifiDisplay[] availableDisplays); 1037e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown 1038e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown void onDisplayConnecting(WifiDisplay display); 1039e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown void onDisplayConnectionFailed(); 104074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown void onDisplayChanged(WifiDisplay display); 1041f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown void onDisplayConnected(WifiDisplay display, 1042f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown Surface surface, int width, int height, int flags); 10431f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang void onDisplaySessionInfo(WifiDisplaySessionInfo sessionInfo); 1044cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown void onDisplayDisconnected(); 1045cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown } 1046cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown} 1047