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