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;
30f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brownimport android.media.RemoteDisplay;
31cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.NetworkInfo;
3289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport android.net.Uri;
336681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriffimport android.net.wifi.WpsInfo;
34cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pConfig;
35cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pDevice;
36cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pDeviceList;
37cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pGroup;
38cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pManager;
39cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pWfdInfo;
40cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pManager.ActionListener;
41cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pManager.Channel;
42cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pManager.GroupInfoListener;
43cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pManager.PeerListListener;
44cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.os.Handler;
4589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport android.provider.Settings;
46cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.util.Slog;
47f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brownimport android.view.Surface;
48cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
49cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.io.PrintWriter;
50cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.net.Inet4Address;
51cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.net.InetAddress;
52cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.net.NetworkInterface;
53cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.net.SocketException;
54cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.util.ArrayList;
55cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.util.Enumeration;
56607223f3b7a1c4dc3ac995f742f8d2da50d85ffcNarayan Kamathimport java.util.Objects;
57c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
58cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown/**
59cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Manages all of the various asynchronous interactions with the {@link WifiP2pManager}
60cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * on behalf of {@link WifiDisplayAdapter}.
61cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * <p>
62cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * This code is isolated from {@link WifiDisplayAdapter} so that we can avoid
63cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * accidentally introducing any deadlocks due to the display manager calling
64cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * outside of itself while holding its lock.  It's also way easier to write this
65cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * asynchronous code if we can assume that it is single-threaded.
66cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p><p>
67cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * The controller must be instantiated on the handler thread.
68cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p>
69cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown */
70cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownfinal class WifiDisplayController implements DumpUtils.Dump {
71cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static final String TAG = "WifiDisplayController";
72c5df37c285221d0fb113f55b9e78b35632241d3fJeff Brown    private static final boolean DEBUG = false;
73cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
74cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static final int DEFAULT_CONTROL_PORT = 7236;
75cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static final int MAX_THROUGHPUT = 50;
76ce468a35b388ca46578934706b38dbae94941643Jeff Brown    private static final int CONNECTION_TIMEOUT_SECONDS = 30;
77e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown    private static final int RTSP_TIMEOUT_SECONDS = 30;
781f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    private static final int RTSP_TIMEOUT_SECONDS_CERT_MODE = 120;
79cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
80ce468a35b388ca46578934706b38dbae94941643Jeff Brown    // We repeatedly issue calls to discover peers every so often for a few reasons.
81ce468a35b388ca46578934706b38dbae94941643Jeff Brown    // 1. The initial request may fail and need to retried.
82ce468a35b388ca46578934706b38dbae94941643Jeff Brown    // 2. Discovery will self-abort after any group is initiated, which may not necessarily
83ce468a35b388ca46578934706b38dbae94941643Jeff Brown    //    be what we want to have happen.
84ce468a35b388ca46578934706b38dbae94941643Jeff Brown    // 3. Discovery will self-timeout after 2 minutes, whereas we want discovery to
85ce468a35b388ca46578934706b38dbae94941643Jeff Brown    //    be occur for as long as a client is requesting it be.
86ce468a35b388ca46578934706b38dbae94941643Jeff Brown    // 4. We don't seem to get updated results for displays we've already found until
87ce468a35b388ca46578934706b38dbae94941643Jeff Brown    //    we ask to discover again, particularly for the isSessionAvailable() property.
88ce468a35b388ca46578934706b38dbae94941643Jeff Brown    private static final int DISCOVER_PEERS_INTERVAL_MILLIS = 10000;
890cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
900cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private static final int CONNECT_MAX_RETRIES = 3;
910cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private static final int CONNECT_RETRY_DELAY_MILLIS = 500;
920cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
93cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final Context mContext;
94cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final Handler mHandler;
95cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final Listener mListener;
9688469e56c8294a928e65398352e8444d66bdb75aJeff Brown
97cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final WifiP2pManager mWifiP2pManager;
98cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final Channel mWifiP2pChannel;
99cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
100cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private boolean mWifiP2pEnabled;
101cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private boolean mWfdEnabled;
102cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private boolean mWfdEnabling;
103cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private NetworkInfo mNetworkInfo;
104cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
10589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private final ArrayList<WifiP2pDevice> mAvailableWifiDisplayPeers =
106cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            new ArrayList<WifiP2pDevice>();
107cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
10889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    // True if Wifi display is enabled by the user.
10989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private boolean mWifiDisplayOnSetting;
11089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
111ce468a35b388ca46578934706b38dbae94941643Jeff Brown    // True if a scan was requested independent of whether one is actually in progress.
112ce468a35b388ca46578934706b38dbae94941643Jeff Brown    private boolean mScanRequested;
113ce468a35b388ca46578934706b38dbae94941643Jeff Brown
1140cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    // True if there is a call to discoverPeers in progress.
1150cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private boolean mDiscoverPeersInProgress;
1160cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
117cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // The device to which we want to connect, or null if we want to be disconnected.
118cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiP2pDevice mDesiredDevice;
119cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
120cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // The device to which we are currently connecting, or null if we have already connected
121cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // or are not trying to connect.
122cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiP2pDevice mConnectingDevice;
123cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
12474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    // The device from which we are currently disconnecting.
12574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private WifiP2pDevice mDisconnectingDevice;
12674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
12774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    // The device to which we were previously trying to connect and are now canceling.
12874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private WifiP2pDevice mCancelingDevice;
12974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
130cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // The device to which we are currently connected, which means we have an active P2P group.
131cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiP2pDevice mConnectedDevice;
132cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
133cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // The group info obtained after connecting.
134cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiP2pGroup mConnectedDeviceGroupInfo;
135cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1360cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    // Number of connection retries remaining.
1370cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private int mConnectionRetriesLeft;
1380cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
139f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    // The remote display that is listening on the connection.
140f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    // Created after the Wifi P2P network is connected.
141f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private RemoteDisplay mRemoteDisplay;
142f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
143f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    // The remote display interface.
144f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private String mRemoteDisplayInterface;
145f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
146f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    // True if RTSP has connected.
147f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private boolean mRemoteDisplayConnected;
148f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
149c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    // The information we have most recently told WifiDisplayAdapter about.
150c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private WifiDisplay mAdvertisedDisplay;
151c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private Surface mAdvertisedDisplaySurface;
152c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private int mAdvertisedDisplayWidth;
153c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private int mAdvertisedDisplayHeight;
154c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private int mAdvertisedDisplayFlags;
155c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
1561f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    // Certification
1571f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    private boolean mWifiDisplayCertMode;
158e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang    private int mWifiDisplayWpsConfig = WpsInfo.INVALID;
159e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang
1601f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    private WifiP2pDevice mThisDevice;
1611f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
162cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public WifiDisplayController(Context context, Handler handler, Listener listener) {
163cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mContext = context;
164cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mHandler = handler;
165cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mListener = listener;
166cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
167cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mWifiP2pManager = (WifiP2pManager)context.getSystemService(Context.WIFI_P2P_SERVICE);
168cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mWifiP2pChannel = mWifiP2pManager.initialize(context, handler.getLooper(), null);
169cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
170cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        IntentFilter intentFilter = new IntentFilter();
171cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
172cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
173cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
1741f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
17589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        context.registerReceiver(mWifiP2pReceiver, intentFilter, null, mHandler);
17689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
17789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        ContentObserver settingsObserver = new ContentObserver(mHandler) {
17889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            @Override
17989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            public void onChange(boolean selfChange, Uri uri) {
18089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                updateSettings();
18189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
18289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        };
18389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
18489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        final ContentResolver resolver = mContext.getContentResolver();
18589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        resolver.registerContentObserver(Settings.Global.getUriFor(
18689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                Settings.Global.WIFI_DISPLAY_ON), false, settingsObserver);
1871f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        resolver.registerContentObserver(Settings.Global.getUriFor(
1881f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON), false, settingsObserver);
189e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang        resolver.registerContentObserver(Settings.Global.getUriFor(
190e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang                Settings.Global.WIFI_DISPLAY_WPS_CONFIG), false, settingsObserver);
19189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        updateSettings();
19289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
19389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
19489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void updateSettings() {
19589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        final ContentResolver resolver = mContext.getContentResolver();
19689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mWifiDisplayOnSetting = Settings.Global.getInt(resolver,
19789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                Settings.Global.WIFI_DISPLAY_ON, 0) != 0;
1981f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        mWifiDisplayCertMode = Settings.Global.getInt(resolver,
1991f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON, 0) != 0;
20089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
201e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang        mWifiDisplayWpsConfig = WpsInfo.INVALID;
202e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang        if (mWifiDisplayCertMode) {
203e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang            mWifiDisplayWpsConfig = Settings.Global.getInt(resolver,
204e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang                  Settings.Global.WIFI_DISPLAY_WPS_CONFIG, WpsInfo.INVALID);
205e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang        }
206e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang
20789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        updateWfdEnableState();
208cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
209cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
21074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    @Override
211ae6688b09649447e57468b3e7935691bc09ec9b9Dianne Hackborn    public void dump(PrintWriter pw, String prefix) {
21289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mWifiDisplayOnSetting=" + mWifiDisplayOnSetting);
213cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled);
214cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mWfdEnabled=" + mWfdEnabled);
215cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mWfdEnabling=" + mWfdEnabling);
216cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mNetworkInfo=" + mNetworkInfo);
217ce468a35b388ca46578934706b38dbae94941643Jeff Brown        pw.println("mScanRequested=" + mScanRequested);
2180cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown        pw.println("mDiscoverPeersInProgress=" + mDiscoverPeersInProgress);
219cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice));
220cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice));
22174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        pw.println("mDisconnectingDisplay=" + describeWifiP2pDevice(mDisconnectingDevice));
22274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        pw.println("mCancelingDisplay=" + describeWifiP2pDevice(mCancelingDevice));
223cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mConnectedDevice=" + describeWifiP2pDevice(mConnectedDevice));
2240cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown        pw.println("mConnectionRetriesLeft=" + mConnectionRetriesLeft);
225f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        pw.println("mRemoteDisplay=" + mRemoteDisplay);
226f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        pw.println("mRemoteDisplayInterface=" + mRemoteDisplayInterface);
227f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        pw.println("mRemoteDisplayConnected=" + mRemoteDisplayConnected);
228c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        pw.println("mAdvertisedDisplay=" + mAdvertisedDisplay);
229c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        pw.println("mAdvertisedDisplaySurface=" + mAdvertisedDisplaySurface);
230c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        pw.println("mAdvertisedDisplayWidth=" + mAdvertisedDisplayWidth);
231c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        pw.println("mAdvertisedDisplayHeight=" + mAdvertisedDisplayHeight);
232c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        pw.println("mAdvertisedDisplayFlags=" + mAdvertisedDisplayFlags);
233cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
23489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mAvailableWifiDisplayPeers: size=" + mAvailableWifiDisplayPeers.size());
23589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        for (WifiP2pDevice device : mAvailableWifiDisplayPeers) {
236cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("  " + describeWifiP2pDevice(device));
237cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
238cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
239cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
240ce468a35b388ca46578934706b38dbae94941643Jeff Brown    public void requestStartScan() {
241ce468a35b388ca46578934706b38dbae94941643Jeff Brown        if (!mScanRequested) {
242ce468a35b388ca46578934706b38dbae94941643Jeff Brown            mScanRequested = true;
243ce468a35b388ca46578934706b38dbae94941643Jeff Brown            updateScanState();
244ce468a35b388ca46578934706b38dbae94941643Jeff Brown        }
245ce468a35b388ca46578934706b38dbae94941643Jeff Brown    }
246ce468a35b388ca46578934706b38dbae94941643Jeff Brown
247ce468a35b388ca46578934706b38dbae94941643Jeff Brown    public void requestStopScan() {
248ce468a35b388ca46578934706b38dbae94941643Jeff Brown        if (mScanRequested) {
249ce468a35b388ca46578934706b38dbae94941643Jeff Brown            mScanRequested = false;
250ce468a35b388ca46578934706b38dbae94941643Jeff Brown            updateScanState();
251ce468a35b388ca46578934706b38dbae94941643Jeff Brown        }
252e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
253e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
254e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestConnect(String address) {
25589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        for (WifiP2pDevice device : mAvailableWifiDisplayPeers) {
256e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            if (device.deviceAddress.equals(address)) {
257e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                connect(device);
258e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
259e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
260e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
261e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
2621f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    public void requestPause() {
2631f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        if (mRemoteDisplay != null) {
2641f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            mRemoteDisplay.pause();
2651f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        }
2661f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    }
2671f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
2681f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    public void requestResume() {
2691f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        if (mRemoteDisplay != null) {
2701f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            mRemoteDisplay.resume();
2711f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        }
2721f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    }
2731f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
274e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestDisconnect() {
275e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        disconnect();
276e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
277e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
27889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void updateWfdEnableState() {
27989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mWifiDisplayOnSetting && mWifiP2pEnabled) {
28089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            // WFD should be enabled.
28189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            if (!mWfdEnabled && !mWfdEnabling) {
28289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                mWfdEnabling = true;
28389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
28489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo();
28589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                wfdInfo.setWfdEnabled(true);
28689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                wfdInfo.setDeviceType(WifiP2pWfdInfo.WFD_SOURCE);
28789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                wfdInfo.setSessionAvailable(true);
28889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                wfdInfo.setControlPort(DEFAULT_CONTROL_PORT);
28989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                wfdInfo.setMaxThroughput(MAX_THROUGHPUT);
29089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() {
29189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    @Override
29289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    public void onSuccess() {
29389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        if (DEBUG) {
29489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            Slog.d(TAG, "Successfully set WFD info.");
29589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        }
29689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        if (mWfdEnabling) {
29789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            mWfdEnabling = false;
29889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            mWfdEnabled = true;
29989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            reportFeatureState();
300ce468a35b388ca46578934706b38dbae94941643Jeff Brown                            updateScanState();
30189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        }
302cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
303cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
30489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    @Override
30589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    public void onFailure(int reason) {
30689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        if (DEBUG) {
30789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            Slog.d(TAG, "Failed to set WFD info with reason " + reason + ".");
30889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        }
30989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        mWfdEnabling = false;
310cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
31189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                });
31289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
31389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        } else {
31489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            // WFD should be disabled.
31572193e1f329ec91bfd86f977035caecb00914444Chong Zhang            if (mWfdEnabled || mWfdEnabling) {
31672193e1f329ec91bfd86f977035caecb00914444Chong Zhang                WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo();
31772193e1f329ec91bfd86f977035caecb00914444Chong Zhang                wfdInfo.setWfdEnabled(false);
31872193e1f329ec91bfd86f977035caecb00914444Chong Zhang                mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() {
31972193e1f329ec91bfd86f977035caecb00914444Chong Zhang                    @Override
32072193e1f329ec91bfd86f977035caecb00914444Chong Zhang                    public void onSuccess() {
32172193e1f329ec91bfd86f977035caecb00914444Chong Zhang                        if (DEBUG) {
32272193e1f329ec91bfd86f977035caecb00914444Chong Zhang                            Slog.d(TAG, "Successfully set WFD info.");
32372193e1f329ec91bfd86f977035caecb00914444Chong Zhang                        }
32472193e1f329ec91bfd86f977035caecb00914444Chong Zhang                    }
32572193e1f329ec91bfd86f977035caecb00914444Chong Zhang
32672193e1f329ec91bfd86f977035caecb00914444Chong Zhang                    @Override
32772193e1f329ec91bfd86f977035caecb00914444Chong Zhang                    public void onFailure(int reason) {
32872193e1f329ec91bfd86f977035caecb00914444Chong Zhang                        if (DEBUG) {
32972193e1f329ec91bfd86f977035caecb00914444Chong Zhang                            Slog.d(TAG, "Failed to set WFD info with reason " + reason + ".");
33072193e1f329ec91bfd86f977035caecb00914444Chong Zhang                        }
33172193e1f329ec91bfd86f977035caecb00914444Chong Zhang                    }
33272193e1f329ec91bfd86f977035caecb00914444Chong Zhang                });
33372193e1f329ec91bfd86f977035caecb00914444Chong Zhang            }
33489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mWfdEnabling = false;
33589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mWfdEnabled = false;
33689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            reportFeatureState();
337ce468a35b388ca46578934706b38dbae94941643Jeff Brown            updateScanState();
33889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            disconnect();
339cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
340cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
341cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
34289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void reportFeatureState() {
34389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        final int featureState = computeFeatureState();
34489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mHandler.post(new Runnable() {
34589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            @Override
34689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            public void run() {
34789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                mListener.onFeatureStateChanged(featureState);
34889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
34989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        });
35089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
35189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
35289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private int computeFeatureState() {
35389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (!mWifiP2pEnabled) {
35489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            return WifiDisplayStatus.FEATURE_STATE_DISABLED;
355e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
35689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        return mWifiDisplayOnSetting ? WifiDisplayStatus.FEATURE_STATE_ON :
35789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                WifiDisplayStatus.FEATURE_STATE_OFF;
358e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
359e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
360ce468a35b388ca46578934706b38dbae94941643Jeff Brown    private void updateScanState() {
361ce468a35b388ca46578934706b38dbae94941643Jeff Brown        if (mScanRequested && mWfdEnabled && mDesiredDevice == null) {
362ce468a35b388ca46578934706b38dbae94941643Jeff Brown            if (!mDiscoverPeersInProgress) {
363ce468a35b388ca46578934706b38dbae94941643Jeff Brown                Slog.i(TAG, "Starting Wifi display scan.");
364ce468a35b388ca46578934706b38dbae94941643Jeff Brown                mDiscoverPeersInProgress = true;
365ce468a35b388ca46578934706b38dbae94941643Jeff Brown                handleScanStarted();
366ce468a35b388ca46578934706b38dbae94941643Jeff Brown                tryDiscoverPeers();
367ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
368ce468a35b388ca46578934706b38dbae94941643Jeff Brown        } else {
369ce468a35b388ca46578934706b38dbae94941643Jeff Brown            if (mDiscoverPeersInProgress) {
370ce468a35b388ca46578934706b38dbae94941643Jeff Brown                // Cancel automatic retry right away.
371ce468a35b388ca46578934706b38dbae94941643Jeff Brown                mHandler.removeCallbacks(mDiscoverPeers);
372ce468a35b388ca46578934706b38dbae94941643Jeff Brown
373ce468a35b388ca46578934706b38dbae94941643Jeff Brown                // Defer actually stopping discovery if we have a connection attempt in progress.
374ce468a35b388ca46578934706b38dbae94941643Jeff Brown                // The wifi display connection attempt often fails if we are not in discovery
375ce468a35b388ca46578934706b38dbae94941643Jeff Brown                // mode.  So we allow discovery to continue until we give up trying to connect.
376ce468a35b388ca46578934706b38dbae94941643Jeff Brown                if (mDesiredDevice == null || mDesiredDevice == mConnectedDevice) {
377ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    Slog.i(TAG, "Stopping Wifi display scan.");
378ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    mDiscoverPeersInProgress = false;
379ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    stopPeerDiscovery();
380ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    handleScanFinished();
381ce468a35b388ca46578934706b38dbae94941643Jeff Brown                }
382ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
3830cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown        }
3840cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    }
3850cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
3860cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private void tryDiscoverPeers() {
387cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mWifiP2pManager.discoverPeers(mWifiP2pChannel, new ActionListener() {
388cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
389cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void onSuccess() {
390cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
391cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Discover peers succeeded.  Requesting peers now.");
392cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
393cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
394ce468a35b388ca46578934706b38dbae94941643Jeff Brown                if (mDiscoverPeersInProgress) {
395ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    requestPeers();
396ce468a35b388ca46578934706b38dbae94941643Jeff Brown                }
397cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
398cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
399cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
400cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void onFailure(int reason) {
401cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
402cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Discover peers failed with reason " + reason + ".");
403cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
4040cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
405ce468a35b388ca46578934706b38dbae94941643Jeff Brown                // Ignore the error.
406ce468a35b388ca46578934706b38dbae94941643Jeff Brown                // We will retry automatically in a little bit.
407ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
408ce468a35b388ca46578934706b38dbae94941643Jeff Brown        });
409ce468a35b388ca46578934706b38dbae94941643Jeff Brown
410ce468a35b388ca46578934706b38dbae94941643Jeff Brown        // Retry discover peers periodically until stopped.
411ce468a35b388ca46578934706b38dbae94941643Jeff Brown        mHandler.postDelayed(mDiscoverPeers, DISCOVER_PEERS_INTERVAL_MILLIS);
412ce468a35b388ca46578934706b38dbae94941643Jeff Brown    }
413ce468a35b388ca46578934706b38dbae94941643Jeff Brown
414ce468a35b388ca46578934706b38dbae94941643Jeff Brown    private void stopPeerDiscovery() {
415ce468a35b388ca46578934706b38dbae94941643Jeff Brown        mWifiP2pManager.stopPeerDiscovery(mWifiP2pChannel, new ActionListener() {
416ce468a35b388ca46578934706b38dbae94941643Jeff Brown            @Override
417ce468a35b388ca46578934706b38dbae94941643Jeff Brown            public void onSuccess() {
418ce468a35b388ca46578934706b38dbae94941643Jeff Brown                if (DEBUG) {
419ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    Slog.d(TAG, "Stop peer discovery succeeded.");
420ce468a35b388ca46578934706b38dbae94941643Jeff Brown                }
421ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
422ce468a35b388ca46578934706b38dbae94941643Jeff Brown
423ce468a35b388ca46578934706b38dbae94941643Jeff Brown            @Override
424ce468a35b388ca46578934706b38dbae94941643Jeff Brown            public void onFailure(int reason) {
425ce468a35b388ca46578934706b38dbae94941643Jeff Brown                if (DEBUG) {
426ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    Slog.d(TAG, "Stop peer discovery failed with reason " + reason + ".");
4270cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                }
428cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
429cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        });
430cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
431cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
432cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void requestPeers() {
433cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mWifiP2pManager.requestPeers(mWifiP2pChannel, new PeerListListener() {
434cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
435cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void onPeersAvailable(WifiP2pDeviceList peers) {
436cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
437cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Received list of peers.");
438cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
439cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
44089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                mAvailableWifiDisplayPeers.clear();
441cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                for (WifiP2pDevice device : peers.getDeviceList()) {
442cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    if (DEBUG) {
443cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        Slog.d(TAG, "  " + describeWifiP2pDevice(device));
444cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
445cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
446cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    if (isWifiDisplay(device)) {
44789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        mAvailableWifiDisplayPeers.add(device);
448cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
449cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
450cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
451ce468a35b388ca46578934706b38dbae94941643Jeff Brown                if (mDiscoverPeersInProgress) {
452ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    handleScanResults();
453ce468a35b388ca46578934706b38dbae94941643Jeff Brown                }
454e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
455e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
456e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
457cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
458e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private void handleScanStarted() {
459e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        mHandler.post(new Runnable() {
460e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
461e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
462e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                mListener.onScanStarted();
463e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
464e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
465e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
466cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
467ce468a35b388ca46578934706b38dbae94941643Jeff Brown    private void handleScanResults() {
46889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        final int count = mAvailableWifiDisplayPeers.size();
469e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count);
470e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        for (int i = 0; i < count; i++) {
47174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            WifiP2pDevice device = mAvailableWifiDisplayPeers.get(i);
47274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            displays[i] = createWifiDisplay(device);
47374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            updateDesiredDevice(device);
474e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
475e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
476e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        mHandler.post(new Runnable() {
477e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
478e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
479ce468a35b388ca46578934706b38dbae94941643Jeff Brown                mListener.onScanResults(displays);
480ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
481ce468a35b388ca46578934706b38dbae94941643Jeff Brown        });
482ce468a35b388ca46578934706b38dbae94941643Jeff Brown    }
483ce468a35b388ca46578934706b38dbae94941643Jeff Brown
484ce468a35b388ca46578934706b38dbae94941643Jeff Brown    private void handleScanFinished() {
485ce468a35b388ca46578934706b38dbae94941643Jeff Brown        mHandler.post(new Runnable() {
486ce468a35b388ca46578934706b38dbae94941643Jeff Brown            @Override
487ce468a35b388ca46578934706b38dbae94941643Jeff Brown            public void run() {
488ce468a35b388ca46578934706b38dbae94941643Jeff Brown                mListener.onScanFinished();
489cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
490cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        });
491cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
492cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
49374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private void updateDesiredDevice(WifiP2pDevice device) {
49474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        // Handle the case where the device to which we are connecting or connected
49574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        // may have been renamed or reported different properties in the latest scan.
49674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        final String address = device.deviceAddress;
49774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        if (mDesiredDevice != null && mDesiredDevice.deviceAddress.equals(address)) {
49874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            if (DEBUG) {
49974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                Slog.d(TAG, "updateDesiredDevice: new information "
50074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                        + describeWifiP2pDevice(device));
50174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            }
50274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            mDesiredDevice.update(device);
50374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            if (mAdvertisedDisplay != null
50474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    && mAdvertisedDisplay.getDeviceAddress().equals(address)) {
50574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                readvertiseDisplay(createWifiDisplay(mDesiredDevice));
50674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            }
50774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        }
50874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    }
50974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
510cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void connect(final WifiP2pDevice device) {
511cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mDesiredDevice != null
512cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                && !mDesiredDevice.deviceAddress.equals(device.deviceAddress)) {
513cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (DEBUG) {
514cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Slog.d(TAG, "connect: nothing to do, already connecting to "
515cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + describeWifiP2pDevice(device));
516cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
517cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return;
518cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
519cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
520cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mConnectedDevice != null
521cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                && !mConnectedDevice.deviceAddress.equals(device.deviceAddress)
522cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                && mDesiredDevice == null) {
523cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (DEBUG) {
524cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Slog.d(TAG, "connect: nothing to do, already connected to "
525cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + describeWifiP2pDevice(device) + " and not part way through "
526cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + "connecting to a different device.");
527cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
5280cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown            return;
529cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
530cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
531ce468a35b388ca46578934706b38dbae94941643Jeff Brown        if (!mWfdEnabled) {
532ce468a35b388ca46578934706b38dbae94941643Jeff Brown            Slog.i(TAG, "Ignoring request to connect to Wifi display because the "
533ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    +" feature is currently disabled: " + device.deviceName);
534ce468a35b388ca46578934706b38dbae94941643Jeff Brown            return;
535ce468a35b388ca46578934706b38dbae94941643Jeff Brown        }
536ce468a35b388ca46578934706b38dbae94941643Jeff Brown
537cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mDesiredDevice = device;
5380cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown        mConnectionRetriesLeft = CONNECT_MAX_RETRIES;
539cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        updateConnection();
540cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
541cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
542cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void disconnect() {
543cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mDesiredDevice = null;
544cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        updateConnection();
545cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
546cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
5470cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private void retryConnection() {
54889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        // Cheap hack.  Make a new instance of the device object so that we
54989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        // can distinguish it from the previous connection attempt.
55089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        // This will cause us to tear everything down before we try again.
55189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mDesiredDevice = new WifiP2pDevice(mDesiredDevice);
55289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        updateConnection();
5530cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    }
5540cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
555cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    /**
556cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * This function is called repeatedly after each asynchronous operation
557cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * until all preconditions for the connection have been satisfied and the
558cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * connection is established (or not).
559cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     */
560cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void updateConnection() {
561ce468a35b388ca46578934706b38dbae94941643Jeff Brown        // Step 0. Stop scans if necessary to prevent interference while connected.
562ce468a35b388ca46578934706b38dbae94941643Jeff Brown        // Resume scans later when no longer attempting to connect.
563ce468a35b388ca46578934706b38dbae94941643Jeff Brown        updateScanState();
564ce468a35b388ca46578934706b38dbae94941643Jeff Brown
565cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Step 1. Before we try to connect to a new device, tell the system we
566cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // have disconnected from the old one.
567f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        if (mRemoteDisplay != null && mConnectedDevice != mDesiredDevice) {
568f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            Slog.i(TAG, "Stopped listening for RTSP connection on " + mRemoteDisplayInterface
569f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    + " from Wifi display: " + mConnectedDevice.deviceName);
570f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
571f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplay.dispose();
572f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplay = null;
573f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplayInterface = null;
574f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplayConnected = false;
575f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mHandler.removeCallbacks(mRtspTimeout);
576f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
577f110a3701b8d7ac435c5bb65df4dd9d758be1762Jeff Brown            mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_DISABLED);
578c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            unadvertiseDisplay();
579cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
580cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            // continue to next step
581cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
582cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
583cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Step 2. Before we try to connect to a new device, disconnect from the old one.
58474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        if (mDisconnectingDevice != null) {
58574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            return; // wait for asynchronous callback
58674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        }
587cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) {
588cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName);
58974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            mDisconnectingDevice = mConnectedDevice;
59074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            mConnectedDevice = null;
5911f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            mConnectedDeviceGroupInfo = null;
592cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
593c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            unadvertiseDisplay();
594c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
59574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            final WifiP2pDevice oldDevice = mDisconnectingDevice;
596cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() {
597cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
598cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onSuccess() {
599cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.i(TAG, "Disconnected from Wifi display: " + oldDevice.deviceName);
600cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    next();
601cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
602cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
603cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
604cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onFailure(int reason) {
605cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.i(TAG, "Failed to disconnect from Wifi display: "
606cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            + oldDevice.deviceName + ", reason=" + reason);
607cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    next();
608cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
609cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
610cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                private void next() {
61174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    if (mDisconnectingDevice == oldDevice) {
61274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                        mDisconnectingDevice = null;
613cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        updateConnection();
614cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
615cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
616cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            });
617cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return; // wait for asynchronous callback
618cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
619cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
620cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Step 3. Before we try to connect to a new device, stop trying to connect
621cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // to the old one.
62274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        if (mCancelingDevice != null) {
62374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            return; // wait for asynchronous callback
62474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        }
625cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mConnectingDevice != null && mConnectingDevice != mDesiredDevice) {
626cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Slog.i(TAG, "Canceling connection to Wifi display: " + mConnectingDevice.deviceName);
62774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            mCancelingDevice = mConnectingDevice;
62874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            mConnectingDevice = null;
629cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
630c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            unadvertiseDisplay();
631cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mHandler.removeCallbacks(mConnectionTimeout);
632cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
63374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            final WifiP2pDevice oldDevice = mCancelingDevice;
634cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mWifiP2pManager.cancelConnect(mWifiP2pChannel, new ActionListener() {
635cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
636cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onSuccess() {
637cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.i(TAG, "Canceled connection to Wifi display: " + oldDevice.deviceName);
638cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    next();
639cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
640cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
641cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
642cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onFailure(int reason) {
643cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.i(TAG, "Failed to cancel connection to Wifi display: "
644cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            + oldDevice.deviceName + ", reason=" + reason);
645cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    next();
646cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
647cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
648cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                private void next() {
64974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    if (mCancelingDevice == oldDevice) {
65074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                        mCancelingDevice = null;
651cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        updateConnection();
652cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
653cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
654cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            });
655cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return; // wait for asynchronous callback
656cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
657cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
6581f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        // Step 4. If we wanted to disconnect, or we're updating after starting an
6591f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        // autonomous GO, then mission accomplished.
660cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mDesiredDevice == null) {
6611f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            if (mWifiDisplayCertMode) {
6621f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                mListener.onDisplaySessionInfo(getSessionInfo(mConnectedDeviceGroupInfo, 0));
6631f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            }
664c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            unadvertiseDisplay();
665cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return; // done
666cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
667cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
668cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Step 5. Try to connect.
669cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mConnectedDevice == null && mConnectingDevice == null) {
670cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Slog.i(TAG, "Connecting to Wifi display: " + mDesiredDevice.deviceName);
671cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
672cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mConnectingDevice = mDesiredDevice;
673cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            WifiP2pConfig config = new WifiP2pConfig();
6746681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff            WpsInfo wps = new WpsInfo();
675e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang            if (mWifiDisplayWpsConfig != WpsInfo.INVALID) {
676e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang                wps.setup = mWifiDisplayWpsConfig;
677e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang            } else if (mConnectingDevice.wpsPbcSupported()) {
6786681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff                wps.setup = WpsInfo.PBC;
6796681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff            } else if (mConnectingDevice.wpsDisplaySupported()) {
6806681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff                // We do keypad if peer does display
6816681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff                wps.setup = WpsInfo.KEYPAD;
6826681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff            } else {
6836681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff                wps.setup = WpsInfo.DISPLAY;
6846681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff            }
6856681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff            config.wps = wps;
686cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            config.deviceAddress = mConnectingDevice.deviceAddress;
687e0c28d5f1358fc2d4c464f910bd04fed4b283fefIrfan Sheriff            // Helps with STA & P2P concurrency
68899766cf40ed706aad36032f2107fb0c1e54fc398Irfan Sheriff            config.groupOwnerIntent = WifiP2pConfig.MIN_GROUP_OWNER_INTENT;
689cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
690c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            WifiDisplay display = createWifiDisplay(mConnectingDevice);
691c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            advertiseDisplay(display, null, 0, 0, 0);
692e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
693cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            final WifiP2pDevice newDevice = mDesiredDevice;
694cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mWifiP2pManager.connect(mWifiP2pChannel, config, new ActionListener() {
695cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
696cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onSuccess() {
697cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    // The connection may not yet be established.  We still need to wait
698cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    // for WIFI_P2P_CONNECTION_CHANGED_ACTION.  However, we might never
699cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    // get that broadcast, so we register a timeout.
700cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.i(TAG, "Initiated connection to Wifi display: " + newDevice.deviceName);
701cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
702cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    mHandler.postDelayed(mConnectionTimeout, CONNECTION_TIMEOUT_SECONDS * 1000);
703cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
704cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
705cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
706cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onFailure(int reason) {
707cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    if (mConnectingDevice == newDevice) {
708f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        Slog.i(TAG, "Failed to initiate connection to Wifi display: "
709f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                                + newDevice.deviceName + ", reason=" + reason);
710cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        mConnectingDevice = null;
7110cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                        handleConnectionFailure(false);
712cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
713cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
714cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            });
715cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return; // wait for asynchronous callback
716cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
717cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
718ce468a35b388ca46578934706b38dbae94941643Jeff Brown        // Step 6. Listen for incoming RTSP connection.
719f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        if (mConnectedDevice != null && mRemoteDisplay == null) {
720cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Inet4Address addr = getInterfaceAddress(mConnectedDeviceGroupInfo);
721cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (addr == null) {
722cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Slog.i(TAG, "Failed to get local interface address for communicating "
723cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + "with Wifi display: " + mConnectedDevice.deviceName);
7240cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                handleConnectionFailure(false);
725cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                return; // done
726cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
727cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
728f110a3701b8d7ac435c5bb65df4dd9d758be1762Jeff Brown            mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_SOURCE);
729c9bd4ca005768cb30aaaa44c1171e113c13cd107Jeff Brown
730f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            final WifiP2pDevice oldDevice = mConnectedDevice;
7310f68d166e6ca45fe27410ea520967275e0733757Jeff Brown            final int port = getPortNumber(mConnectedDevice);
732cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            final String iface = addr.getHostAddress() + ":" + port;
733f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplayInterface = iface;
734cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
735f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            Slog.i(TAG, "Listening for RTSP connection on " + iface
736f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    + " from Wifi display: " + mConnectedDevice.deviceName);
737f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
738f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplay = RemoteDisplay.listen(iface, new RemoteDisplay.Listener() {
739cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
740c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                public void onDisplayConnected(Surface surface,
7411f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                        int width, int height, int flags, int session) {
742f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    if (mConnectedDevice == oldDevice && !mRemoteDisplayConnected) {
743f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        Slog.i(TAG, "Opened RTSP connection with Wifi display: "
744f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                                + mConnectedDevice.deviceName);
745f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        mRemoteDisplayConnected = true;
746f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        mHandler.removeCallbacks(mRtspTimeout);
747f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
7481f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                        if (mWifiDisplayCertMode) {
7491f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                            mListener.onDisplaySessionInfo(
7501f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                    getSessionInfo(mConnectedDeviceGroupInfo, session));
7511f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                        }
7521f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
753f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        final WifiDisplay display = createWifiDisplay(mConnectedDevice);
754c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        advertiseDisplay(display, surface, width, height, flags);
755f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    }
756cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
757f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
758f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                @Override
759f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                public void onDisplayDisconnected() {
760f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    if (mConnectedDevice == oldDevice) {
761f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        Slog.i(TAG, "Closed RTSP connection with Wifi display: "
762f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                                + mConnectedDevice.deviceName);
763f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        mHandler.removeCallbacks(mRtspTimeout);
764f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        disconnect();
765f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    }
766f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                }
767f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
768f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                @Override
769f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                public void onDisplayError(int error) {
770f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    if (mConnectedDevice == oldDevice) {
771f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        Slog.i(TAG, "Lost RTSP connection with Wifi display due to error "
772f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                                + error + ": " + mConnectedDevice.deviceName);
773f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        mHandler.removeCallbacks(mRtspTimeout);
774f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        handleConnectionFailure(false);
775f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    }
776f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                }
777fa5ecdc4ac6d7a8db2bb9e4a6a60a3189025df30Svet Ganov            }, mHandler, mContext.getOpPackageName());
778f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
7791f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            // Use extended timeout value for certification, as some tests require user inputs
7801f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            int rtspTimeout = mWifiDisplayCertMode ?
7811f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                    RTSP_TIMEOUT_SECONDS_CERT_MODE : RTSP_TIMEOUT_SECONDS;
7821f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
7831f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            mHandler.postDelayed(mRtspTimeout, rtspTimeout * 1000);
7841f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        }
7851f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    }
7861f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
7871f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    private WifiDisplaySessionInfo getSessionInfo(WifiP2pGroup info, int session) {
7881f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        if (info == null) {
7891f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            return null;
7901f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        }
7911f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        Inet4Address addr = getInterfaceAddress(info);
7921f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        WifiDisplaySessionInfo sessionInfo = new WifiDisplaySessionInfo(
7931f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                !info.getOwner().deviceAddress.equals(mThisDevice.deviceAddress),
7941f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                session,
7951f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                info.getOwner().deviceAddress + " " + info.getNetworkName(),
7961f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                info.getPassphrase(),
7971f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                (addr != null) ? addr.getHostAddress() : "");
7981f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        if (DEBUG) {
7991f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            Slog.d(TAG, sessionInfo.toString());
800cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
8011f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        return sessionInfo;
802cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
803cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
804cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void handleStateChanged(boolean enabled) {
80589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mWifiP2pEnabled = enabled;
80689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        updateWfdEnableState();
807cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
808cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
809cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void handlePeersChanged() {
81056925d65fde7f1ac8676ada6f91d0e604645c0a5Irfan Sheriff        // Even if wfd is disabled, it is best to get the latest set of peers to
81156925d65fde7f1ac8676ada6f91d0e604645c0a5Irfan Sheriff        // keep in sync with the p2p framework
81256925d65fde7f1ac8676ada6f91d0e604645c0a5Irfan Sheriff        requestPeers();
813cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
814cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
815cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void handleConnectionChanged(NetworkInfo networkInfo) {
816cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mNetworkInfo = networkInfo;
817180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        if (mWfdEnabled && networkInfo.isConnected()) {
8181f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            if (mDesiredDevice != null || mWifiDisplayCertMode) {
819cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mWifiP2pManager.requestGroupInfo(mWifiP2pChannel, new GroupInfoListener() {
820cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    @Override
821cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    public void onGroupInfoAvailable(WifiP2pGroup info) {
822cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        if (DEBUG) {
823cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            Slog.d(TAG, "Received group info: " + describeWifiP2pGroup(info));
824cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        }
825cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
826cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        if (mConnectingDevice != null && !info.contains(mConnectingDevice)) {
827cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            Slog.i(TAG, "Aborting connection to Wifi display because "
828cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                                    + "the current P2P group does not contain the device "
82989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                                    + "we expected to find: " + mConnectingDevice.deviceName
83089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                                    + ", group info was: " + describeWifiP2pGroup(info));
8310cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                            handleConnectionFailure(false);
832cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            return;
833cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        }
834cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
835cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        if (mDesiredDevice != null && !info.contains(mDesiredDevice)) {
836cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            disconnect();
837cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            return;
838cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        }
839cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
8401f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                        if (mWifiDisplayCertMode) {
8411f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                            boolean owner = info.getOwner().deviceAddress
8421f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                    .equals(mThisDevice.deviceAddress);
8431f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                            if (owner && info.getClientList().isEmpty()) {
8441f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                // this is the case when we started Autonomous GO,
8451f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                // and no client has connected, save group info
8461f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                // and updateConnection()
8471f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                mConnectingDevice = mDesiredDevice = null;
8481f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                mConnectedDeviceGroupInfo = info;
8491f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                updateConnection();
8501f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                            } else if (mConnectingDevice == null && mDesiredDevice == null) {
8511f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                // this is the case when we received an incoming connection
8521f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                // from the sink, update both mConnectingDevice and mDesiredDevice
8531f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                // then proceed to updateConnection() below
8541f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                mConnectingDevice = mDesiredDevice = owner ?
8551f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                        info.getClientList().iterator().next() : info.getOwner();
8561f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                            }
8571f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                        }
8581f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
859cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) {
8600cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                            Slog.i(TAG, "Connected to Wifi display: "
8610cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                                    + mConnectingDevice.deviceName);
862cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
863cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            mHandler.removeCallbacks(mConnectionTimeout);
864cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            mConnectedDeviceGroupInfo = info;
865cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            mConnectedDevice = mConnectingDevice;
866cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            mConnectingDevice = null;
867cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            updateConnection();
868cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        }
869cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
870cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                });
871cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
872cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        } else {
8731f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            mConnectedDeviceGroupInfo = null;
874ce468a35b388ca46578934706b38dbae94941643Jeff Brown
875ce468a35b388ca46578934706b38dbae94941643Jeff Brown            // Disconnect if we lost the network while connecting or connected to a display.
876ce468a35b388ca46578934706b38dbae94941643Jeff Brown            if (mConnectingDevice != null || mConnectedDevice != null) {
877ce468a35b388ca46578934706b38dbae94941643Jeff Brown                disconnect();
878ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
879180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown
880180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown            // After disconnection for a group, for some reason we have a tendency
881180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown            // to get a peer change notification with an empty list of peers.
882180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown            // Perform a fresh scan.
883180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown            if (mWfdEnabled) {
884180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                requestPeers();
885180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown            }
886cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
887cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
888cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
889ce468a35b388ca46578934706b38dbae94941643Jeff Brown    private final Runnable mDiscoverPeers = new Runnable() {
890ce468a35b388ca46578934706b38dbae94941643Jeff Brown        @Override
891ce468a35b388ca46578934706b38dbae94941643Jeff Brown        public void run() {
892ce468a35b388ca46578934706b38dbae94941643Jeff Brown            tryDiscoverPeers();
893ce468a35b388ca46578934706b38dbae94941643Jeff Brown        }
894ce468a35b388ca46578934706b38dbae94941643Jeff Brown    };
895ce468a35b388ca46578934706b38dbae94941643Jeff Brown
896cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final Runnable mConnectionTimeout = new Runnable() {
897cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
898cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void run() {
899cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) {
900cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Slog.i(TAG, "Timed out waiting for Wifi display connection after "
901cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + CONNECTION_TIMEOUT_SECONDS + " seconds: "
902cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + mConnectingDevice.deviceName);
9030cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                handleConnectionFailure(true);
904cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
905cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
906cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    };
907cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
908f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private final Runnable mRtspTimeout = new Runnable() {
909f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        @Override
910f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        public void run() {
911f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            if (mConnectedDevice != null
912f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    && mRemoteDisplay != null && !mRemoteDisplayConnected) {
913f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                Slog.i(TAG, "Timed out waiting for Wifi display RTSP connection after "
914f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        + RTSP_TIMEOUT_SECONDS + " seconds: "
915f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        + mConnectedDevice.deviceName);
916f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                handleConnectionFailure(true);
917f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            }
918f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        }
919f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    };
920f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
9210cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private void handleConnectionFailure(boolean timeoutOccurred) {
922f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        Slog.i(TAG, "Wifi display connection failed!");
9230cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
924f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        if (mDesiredDevice != null) {
9250cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown            if (mConnectionRetriesLeft > 0) {
92689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                final WifiP2pDevice oldDevice = mDesiredDevice;
9270cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                mHandler.postDelayed(new Runnable() {
9280cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                    @Override
9290cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                    public void run() {
93089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        if (mDesiredDevice == oldDevice && mConnectionRetriesLeft > 0) {
93189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            mConnectionRetriesLeft -= 1;
93289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            Slog.i(TAG, "Retrying Wifi display connection.  Retries left: "
93389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                                    + mConnectionRetriesLeft);
93489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            retryConnection();
93589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        }
9360cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                    }
9370cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                }, timeoutOccurred ? 0 : CONNECT_RETRY_DELAY_MILLIS);
9380cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown            } else {
9390cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                disconnect();
9400cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown            }
941cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
942cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
943cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
944c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private void advertiseDisplay(final WifiDisplay display,
945c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            final Surface surface, final int width, final int height, final int flags) {
946607223f3b7a1c4dc3ac995f742f8d2da50d85ffcNarayan Kamath        if (!Objects.equals(mAdvertisedDisplay, display)
947c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                || mAdvertisedDisplaySurface != surface
948c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                || mAdvertisedDisplayWidth != width
949c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                || mAdvertisedDisplayHeight != height
950c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                || mAdvertisedDisplayFlags != flags) {
951c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            final WifiDisplay oldDisplay = mAdvertisedDisplay;
952c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            final Surface oldSurface = mAdvertisedDisplaySurface;
953c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
954c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mAdvertisedDisplay = display;
955c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mAdvertisedDisplaySurface = surface;
956c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mAdvertisedDisplayWidth = width;
957c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mAdvertisedDisplayHeight = height;
958c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mAdvertisedDisplayFlags = flags;
959c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
960c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mHandler.post(new Runnable() {
961c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                @Override
962c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                public void run() {
963c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                    if (oldSurface != null && surface != oldSurface) {
964c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        mListener.onDisplayDisconnected();
96574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    } else if (oldDisplay != null && !oldDisplay.hasSameAddress(display)) {
966c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        mListener.onDisplayConnectionFailed();
967c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                    }
968c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
969c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                    if (display != null) {
97074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                        if (!display.hasSameAddress(oldDisplay)) {
971c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                            mListener.onDisplayConnecting(display);
97274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                        } else if (!display.equals(oldDisplay)) {
97374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                            // The address is the same but some other property such as the
97474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                            // name must have changed.
97574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                            mListener.onDisplayChanged(display);
976c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        }
977c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        if (surface != null && surface != oldSurface) {
978c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                            mListener.onDisplayConnected(display, surface, width, height, flags);
979c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        }
980c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                    }
981c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                }
982c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            });
983c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        }
984c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    }
985c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
986c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private void unadvertiseDisplay() {
987c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        advertiseDisplay(null, null, 0, 0, 0);
988c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    }
989c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
99074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private void readvertiseDisplay(WifiDisplay display) {
99174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        advertiseDisplay(display, mAdvertisedDisplaySurface,
99274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                mAdvertisedDisplayWidth, mAdvertisedDisplayHeight,
99374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                mAdvertisedDisplayFlags);
99474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    }
99574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
996cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static Inet4Address getInterfaceAddress(WifiP2pGroup info) {
997cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        NetworkInterface iface;
998cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        try {
999cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            iface = NetworkInterface.getByName(info.getInterface());
1000cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        } catch (SocketException ex) {
1001cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Slog.w(TAG, "Could not obtain address of network interface "
1002cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    + info.getInterface(), ex);
1003cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return null;
1004cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
1005cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1006cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        Enumeration<InetAddress> addrs = iface.getInetAddresses();
1007cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        while (addrs.hasMoreElements()) {
1008cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            InetAddress addr = addrs.nextElement();
1009cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (addr instanceof Inet4Address) {
1010cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                return (Inet4Address)addr;
1011cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
1012cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
1013cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1014cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        Slog.w(TAG, "Could not obtain address of network interface "
1015cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                + info.getInterface() + " because it had no IPv4 addresses.");
1016cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        return null;
1017cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
1018cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
10190f68d166e6ca45fe27410ea520967275e0733757Jeff Brown    private static int getPortNumber(WifiP2pDevice device) {
10200f68d166e6ca45fe27410ea520967275e0733757Jeff Brown        if (device.deviceName.startsWith("DIRECT-")
10210f68d166e6ca45fe27410ea520967275e0733757Jeff Brown                && device.deviceName.endsWith("Broadcom")) {
10220f68d166e6ca45fe27410ea520967275e0733757Jeff Brown            // These dongles ignore the port we broadcast in our WFD IE.
10230f68d166e6ca45fe27410ea520967275e0733757Jeff Brown            return 8554;
10240f68d166e6ca45fe27410ea520967275e0733757Jeff Brown        }
10250f68d166e6ca45fe27410ea520967275e0733757Jeff Brown        return DEFAULT_CONTROL_PORT;
10260f68d166e6ca45fe27410ea520967275e0733757Jeff Brown    }
10270f68d166e6ca45fe27410ea520967275e0733757Jeff Brown
1028cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static boolean isWifiDisplay(WifiP2pDevice device) {
10290f68d166e6ca45fe27410ea520967275e0733757Jeff Brown        return device.wfdInfo != null
10300f68d166e6ca45fe27410ea520967275e0733757Jeff Brown                && device.wfdInfo.isWfdEnabled()
10310f68d166e6ca45fe27410ea520967275e0733757Jeff Brown                && isPrimarySinkDeviceType(device.wfdInfo.getDeviceType());
10320f68d166e6ca45fe27410ea520967275e0733757Jeff Brown    }
10330f68d166e6ca45fe27410ea520967275e0733757Jeff Brown
10340f68d166e6ca45fe27410ea520967275e0733757Jeff Brown    private static boolean isPrimarySinkDeviceType(int deviceType) {
10350f68d166e6ca45fe27410ea520967275e0733757Jeff Brown        return deviceType == WifiP2pWfdInfo.PRIMARY_SINK
10360f68d166e6ca45fe27410ea520967275e0733757Jeff Brown                || deviceType == WifiP2pWfdInfo.SOURCE_OR_PRIMARY_SINK;
1037cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
1038cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1039cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static String describeWifiP2pDevice(WifiP2pDevice device) {
1040cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        return device != null ? device.toString().replace('\n', ',') : "null";
1041cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
1042cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1043cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static String describeWifiP2pGroup(WifiP2pGroup group) {
1044cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        return group != null ? group.toString().replace('\n', ',') : "null";
1045cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
1046cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1047e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private static WifiDisplay createWifiDisplay(WifiP2pDevice device) {
104821f603996ed83c7a9a6c430582e8a5af5ac13c6cChong Zhang        return new WifiDisplay(device.deviceAddress, device.deviceName, null,
1049ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                true, device.wfdInfo.isSessionAvailable(), false);
1050e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
1051e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
1052cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final BroadcastReceiver mWifiP2pReceiver = new BroadcastReceiver() {
1053cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
1054cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void onReceive(Context context, Intent intent) {
1055cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            final String action = intent.getAction();
1056cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) {
105789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                // This broadcast is sticky so we'll always get the initial Wifi P2P state
105889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                // on startup.
1059cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                boolean enabled = (intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE,
1060cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        WifiP2pManager.WIFI_P2P_STATE_DISABLED)) ==
1061cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        WifiP2pManager.WIFI_P2P_STATE_ENABLED;
1062cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
1063cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Received WIFI_P2P_STATE_CHANGED_ACTION: enabled="
1064cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            + enabled);
1065cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
1066cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1067cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                handleStateChanged(enabled);
1068cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            } else if (action.equals(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)) {
1069cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
1070cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Received WIFI_P2P_PEERS_CHANGED_ACTION.");
1071cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
1072cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1073cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                handlePeersChanged();
1074cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) {
1075cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra(
1076cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        WifiP2pManager.EXTRA_NETWORK_INFO);
1077cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
1078cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Received WIFI_P2P_CONNECTION_CHANGED_ACTION: networkInfo="
1079cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            + networkInfo);
1080cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
1081cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1082cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                handleConnectionChanged(networkInfo);
10831f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            } else if (action.equals(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)) {
10841f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                mThisDevice = (WifiP2pDevice) intent.getParcelableExtra(
10851f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                        WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);
10861f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                if (DEBUG) {
10871f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                    Slog.d(TAG, "Received WIFI_P2P_THIS_DEVICE_CHANGED_ACTION: mThisDevice= "
10881f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                            + mThisDevice);
10891f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                }
1090cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
1091cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
1092cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    };
1093cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1094cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    /**
1095cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * Called on the handler thread when displays are connected or disconnected.
1096cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     */
1097cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public interface Listener {
109889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        void onFeatureStateChanged(int featureState);
1099e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
1100e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        void onScanStarted();
1101ce468a35b388ca46578934706b38dbae94941643Jeff Brown        void onScanResults(WifiDisplay[] availableDisplays);
1102ce468a35b388ca46578934706b38dbae94941643Jeff Brown        void onScanFinished();
1103e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
1104e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        void onDisplayConnecting(WifiDisplay display);
1105e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        void onDisplayConnectionFailed();
110674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        void onDisplayChanged(WifiDisplay display);
1107f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        void onDisplayConnected(WifiDisplay display,
1108f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                Surface surface, int width, int height, int flags);
11091f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        void onDisplaySessionInfo(WifiDisplaySessionInfo sessionInfo);
1110cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        void onDisplayDisconnected();
1111cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
1112cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown}
1113