WifiDisplayController.java revision ae6688b09649447e57468b3e7935691bc09ec9b9
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;
56cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
57c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brownimport libcore.util.Objects;
58c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
59cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown/**
60cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Manages all of the various asynchronous interactions with the {@link WifiP2pManager}
61cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * on behalf of {@link WifiDisplayAdapter}.
62cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * <p>
63cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * This code is isolated from {@link WifiDisplayAdapter} so that we can avoid
64cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * accidentally introducing any deadlocks due to the display manager calling
65cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * outside of itself while holding its lock.  It's also way easier to write this
66cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * asynchronous code if we can assume that it is single-threaded.
67cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p><p>
68cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * The controller must be instantiated on the handler thread.
69cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p>
70cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown */
71cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownfinal class WifiDisplayController implements DumpUtils.Dump {
72cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static final String TAG = "WifiDisplayController";
73c5df37c285221d0fb113f55b9e78b35632241d3fJeff Brown    private static final boolean DEBUG = false;
74cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
75cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static final int DEFAULT_CONTROL_PORT = 7236;
76cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static final int MAX_THROUGHPUT = 50;
77ce468a35b388ca46578934706b38dbae94941643Jeff Brown    private static final int CONNECTION_TIMEOUT_SECONDS = 30;
78e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown    private static final int RTSP_TIMEOUT_SECONDS = 30;
791f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    private static final int RTSP_TIMEOUT_SECONDS_CERT_MODE = 120;
80cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
81ce468a35b388ca46578934706b38dbae94941643Jeff Brown    // We repeatedly issue calls to discover peers every so often for a few reasons.
82ce468a35b388ca46578934706b38dbae94941643Jeff Brown    // 1. The initial request may fail and need to retried.
83ce468a35b388ca46578934706b38dbae94941643Jeff Brown    // 2. Discovery will self-abort after any group is initiated, which may not necessarily
84ce468a35b388ca46578934706b38dbae94941643Jeff Brown    //    be what we want to have happen.
85ce468a35b388ca46578934706b38dbae94941643Jeff Brown    // 3. Discovery will self-timeout after 2 minutes, whereas we want discovery to
86ce468a35b388ca46578934706b38dbae94941643Jeff Brown    //    be occur for as long as a client is requesting it be.
87ce468a35b388ca46578934706b38dbae94941643Jeff Brown    // 4. We don't seem to get updated results for displays we've already found until
88ce468a35b388ca46578934706b38dbae94941643Jeff Brown    //    we ask to discover again, particularly for the isSessionAvailable() property.
89ce468a35b388ca46578934706b38dbae94941643Jeff Brown    private static final int DISCOVER_PEERS_INTERVAL_MILLIS = 10000;
900cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
910cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private static final int CONNECT_MAX_RETRIES = 3;
920cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private static final int CONNECT_RETRY_DELAY_MILLIS = 500;
930cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
94cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final Context mContext;
95cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final Handler mHandler;
96cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final Listener mListener;
9788469e56c8294a928e65398352e8444d66bdb75aJeff Brown
98cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final WifiP2pManager mWifiP2pManager;
99cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final Channel mWifiP2pChannel;
100cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
101cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private boolean mWifiP2pEnabled;
102cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private boolean mWfdEnabled;
103cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private boolean mWfdEnabling;
104cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private NetworkInfo mNetworkInfo;
105cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
10689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private final ArrayList<WifiP2pDevice> mAvailableWifiDisplayPeers =
107cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            new ArrayList<WifiP2pDevice>();
108cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
10989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    // True if Wifi display is enabled by the user.
11089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private boolean mWifiDisplayOnSetting;
11189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
112ce468a35b388ca46578934706b38dbae94941643Jeff Brown    // True if a scan was requested independent of whether one is actually in progress.
113ce468a35b388ca46578934706b38dbae94941643Jeff Brown    private boolean mScanRequested;
114ce468a35b388ca46578934706b38dbae94941643Jeff Brown
1150cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    // True if there is a call to discoverPeers in progress.
1160cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private boolean mDiscoverPeersInProgress;
1170cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
118cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // The device to which we want to connect, or null if we want to be disconnected.
119cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiP2pDevice mDesiredDevice;
120cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
121cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // The device to which we are currently connecting, or null if we have already connected
122cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // or are not trying to connect.
123cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiP2pDevice mConnectingDevice;
124cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
12574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    // The device from which we are currently disconnecting.
12674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private WifiP2pDevice mDisconnectingDevice;
12774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
12874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    // The device to which we were previously trying to connect and are now canceling.
12974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private WifiP2pDevice mCancelingDevice;
13074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
131cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // The device to which we are currently connected, which means we have an active P2P group.
132cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiP2pDevice mConnectedDevice;
133cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
134cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // The group info obtained after connecting.
135cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiP2pGroup mConnectedDeviceGroupInfo;
136cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1370cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    // Number of connection retries remaining.
1380cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private int mConnectionRetriesLeft;
1390cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
140f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    // The remote display that is listening on the connection.
141f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    // Created after the Wifi P2P network is connected.
142f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private RemoteDisplay mRemoteDisplay;
143f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
144f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    // The remote display interface.
145f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private String mRemoteDisplayInterface;
146f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
147f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    // True if RTSP has connected.
148f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private boolean mRemoteDisplayConnected;
149f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
150c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    // The information we have most recently told WifiDisplayAdapter about.
151c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private WifiDisplay mAdvertisedDisplay;
152c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private Surface mAdvertisedDisplaySurface;
153c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private int mAdvertisedDisplayWidth;
154c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private int mAdvertisedDisplayHeight;
155c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private int mAdvertisedDisplayFlags;
156c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
1571f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    // Certification
1581f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    private boolean mWifiDisplayCertMode;
159e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang    private int mWifiDisplayWpsConfig = WpsInfo.INVALID;
160e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang
1611f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    private WifiP2pDevice mThisDevice;
1621f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
163cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public WifiDisplayController(Context context, Handler handler, Listener listener) {
164cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mContext = context;
165cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mHandler = handler;
166cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mListener = listener;
167cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
168cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mWifiP2pManager = (WifiP2pManager)context.getSystemService(Context.WIFI_P2P_SERVICE);
169cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mWifiP2pChannel = mWifiP2pManager.initialize(context, handler.getLooper(), null);
170cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
171cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        IntentFilter intentFilter = new IntentFilter();
172cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
173cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
174cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
1751f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
17689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        context.registerReceiver(mWifiP2pReceiver, intentFilter, null, mHandler);
17789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
17889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        ContentObserver settingsObserver = new ContentObserver(mHandler) {
17989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            @Override
18089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            public void onChange(boolean selfChange, Uri uri) {
18189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                updateSettings();
18289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
18389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        };
18489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
18589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        final ContentResolver resolver = mContext.getContentResolver();
18689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        resolver.registerContentObserver(Settings.Global.getUriFor(
18789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                Settings.Global.WIFI_DISPLAY_ON), false, settingsObserver);
1881f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        resolver.registerContentObserver(Settings.Global.getUriFor(
1891f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON), false, settingsObserver);
190e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang        resolver.registerContentObserver(Settings.Global.getUriFor(
191e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang                Settings.Global.WIFI_DISPLAY_WPS_CONFIG), false, settingsObserver);
19289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        updateSettings();
19389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
19489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
19589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void updateSettings() {
19689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        final ContentResolver resolver = mContext.getContentResolver();
19789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mWifiDisplayOnSetting = Settings.Global.getInt(resolver,
19889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                Settings.Global.WIFI_DISPLAY_ON, 0) != 0;
1991f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        mWifiDisplayCertMode = Settings.Global.getInt(resolver,
2001f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON, 0) != 0;
20189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
202e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang        mWifiDisplayWpsConfig = WpsInfo.INVALID;
203e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang        if (mWifiDisplayCertMode) {
204e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang            mWifiDisplayWpsConfig = Settings.Global.getInt(resolver,
205e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang                  Settings.Global.WIFI_DISPLAY_WPS_CONFIG, WpsInfo.INVALID);
206e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang        }
207e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang
20889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        updateWfdEnableState();
209cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
210cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
21174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    @Override
212ae6688b09649447e57468b3e7935691bc09ec9b9Dianne Hackborn    public void dump(PrintWriter pw, String prefix) {
21389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mWifiDisplayOnSetting=" + mWifiDisplayOnSetting);
214cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled);
215cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mWfdEnabled=" + mWfdEnabled);
216cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mWfdEnabling=" + mWfdEnabling);
217cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mNetworkInfo=" + mNetworkInfo);
218ce468a35b388ca46578934706b38dbae94941643Jeff Brown        pw.println("mScanRequested=" + mScanRequested);
2190cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown        pw.println("mDiscoverPeersInProgress=" + mDiscoverPeersInProgress);
220cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice));
221cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice));
22274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        pw.println("mDisconnectingDisplay=" + describeWifiP2pDevice(mDisconnectingDevice));
22374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        pw.println("mCancelingDisplay=" + describeWifiP2pDevice(mCancelingDevice));
224cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mConnectedDevice=" + describeWifiP2pDevice(mConnectedDevice));
2250cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown        pw.println("mConnectionRetriesLeft=" + mConnectionRetriesLeft);
226f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        pw.println("mRemoteDisplay=" + mRemoteDisplay);
227f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        pw.println("mRemoteDisplayInterface=" + mRemoteDisplayInterface);
228f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        pw.println("mRemoteDisplayConnected=" + mRemoteDisplayConnected);
229c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        pw.println("mAdvertisedDisplay=" + mAdvertisedDisplay);
230c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        pw.println("mAdvertisedDisplaySurface=" + mAdvertisedDisplaySurface);
231c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        pw.println("mAdvertisedDisplayWidth=" + mAdvertisedDisplayWidth);
232c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        pw.println("mAdvertisedDisplayHeight=" + mAdvertisedDisplayHeight);
233c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        pw.println("mAdvertisedDisplayFlags=" + mAdvertisedDisplayFlags);
234cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
23589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mAvailableWifiDisplayPeers: size=" + mAvailableWifiDisplayPeers.size());
23689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        for (WifiP2pDevice device : mAvailableWifiDisplayPeers) {
237cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("  " + describeWifiP2pDevice(device));
238cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
239cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
240cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
241ce468a35b388ca46578934706b38dbae94941643Jeff Brown    public void requestStartScan() {
242ce468a35b388ca46578934706b38dbae94941643Jeff Brown        if (!mScanRequested) {
243ce468a35b388ca46578934706b38dbae94941643Jeff Brown            mScanRequested = true;
244ce468a35b388ca46578934706b38dbae94941643Jeff Brown            updateScanState();
245ce468a35b388ca46578934706b38dbae94941643Jeff Brown        }
246ce468a35b388ca46578934706b38dbae94941643Jeff Brown    }
247ce468a35b388ca46578934706b38dbae94941643Jeff Brown
248ce468a35b388ca46578934706b38dbae94941643Jeff Brown    public void requestStopScan() {
249ce468a35b388ca46578934706b38dbae94941643Jeff Brown        if (mScanRequested) {
250ce468a35b388ca46578934706b38dbae94941643Jeff Brown            mScanRequested = false;
251ce468a35b388ca46578934706b38dbae94941643Jeff Brown            updateScanState();
252ce468a35b388ca46578934706b38dbae94941643Jeff Brown        }
253e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
254e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
255e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestConnect(String address) {
25689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        for (WifiP2pDevice device : mAvailableWifiDisplayPeers) {
257e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            if (device.deviceAddress.equals(address)) {
258e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                connect(device);
259e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
260e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
261e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
262e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
2631f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    public void requestPause() {
2641f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        if (mRemoteDisplay != null) {
2651f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            mRemoteDisplay.pause();
2661f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        }
2671f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    }
2681f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
2691f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    public void requestResume() {
2701f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        if (mRemoteDisplay != null) {
2711f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            mRemoteDisplay.resume();
2721f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        }
2731f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    }
2741f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
275e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestDisconnect() {
276e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        disconnect();
277e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
278e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
27989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void updateWfdEnableState() {
28089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mWifiDisplayOnSetting && mWifiP2pEnabled) {
28189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            // WFD should be enabled.
28289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            if (!mWfdEnabled && !mWfdEnabling) {
28389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                mWfdEnabling = true;
28489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
28589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo();
28689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                wfdInfo.setWfdEnabled(true);
28789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                wfdInfo.setDeviceType(WifiP2pWfdInfo.WFD_SOURCE);
28889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                wfdInfo.setSessionAvailable(true);
28989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                wfdInfo.setControlPort(DEFAULT_CONTROL_PORT);
29089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                wfdInfo.setMaxThroughput(MAX_THROUGHPUT);
29189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() {
29289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    @Override
29389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    public void onSuccess() {
29489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        if (DEBUG) {
29589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            Slog.d(TAG, "Successfully set WFD info.");
29689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        }
29789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        if (mWfdEnabling) {
29889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            mWfdEnabling = false;
29989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            mWfdEnabled = true;
30089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            reportFeatureState();
301ce468a35b388ca46578934706b38dbae94941643Jeff Brown                            updateScanState();
30289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        }
303cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
304cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
30589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    @Override
30689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    public void onFailure(int reason) {
30789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        if (DEBUG) {
30889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            Slog.d(TAG, "Failed to set WFD info with reason " + reason + ".");
30989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        }
31089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        mWfdEnabling = false;
311cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
31289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                });
31389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
31489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        } else {
31589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            // WFD should be disabled.
31672193e1f329ec91bfd86f977035caecb00914444Chong Zhang            if (mWfdEnabled || mWfdEnabling) {
31772193e1f329ec91bfd86f977035caecb00914444Chong Zhang                WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo();
31872193e1f329ec91bfd86f977035caecb00914444Chong Zhang                wfdInfo.setWfdEnabled(false);
31972193e1f329ec91bfd86f977035caecb00914444Chong Zhang                mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() {
32072193e1f329ec91bfd86f977035caecb00914444Chong Zhang                    @Override
32172193e1f329ec91bfd86f977035caecb00914444Chong Zhang                    public void onSuccess() {
32272193e1f329ec91bfd86f977035caecb00914444Chong Zhang                        if (DEBUG) {
32372193e1f329ec91bfd86f977035caecb00914444Chong Zhang                            Slog.d(TAG, "Successfully set WFD info.");
32472193e1f329ec91bfd86f977035caecb00914444Chong Zhang                        }
32572193e1f329ec91bfd86f977035caecb00914444Chong Zhang                    }
32672193e1f329ec91bfd86f977035caecb00914444Chong Zhang
32772193e1f329ec91bfd86f977035caecb00914444Chong Zhang                    @Override
32872193e1f329ec91bfd86f977035caecb00914444Chong Zhang                    public void onFailure(int reason) {
32972193e1f329ec91bfd86f977035caecb00914444Chong Zhang                        if (DEBUG) {
33072193e1f329ec91bfd86f977035caecb00914444Chong Zhang                            Slog.d(TAG, "Failed to set WFD info with reason " + reason + ".");
33172193e1f329ec91bfd86f977035caecb00914444Chong Zhang                        }
33272193e1f329ec91bfd86f977035caecb00914444Chong Zhang                    }
33372193e1f329ec91bfd86f977035caecb00914444Chong Zhang                });
33472193e1f329ec91bfd86f977035caecb00914444Chong Zhang            }
33589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mWfdEnabling = false;
33689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mWfdEnabled = false;
33789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            reportFeatureState();
338ce468a35b388ca46578934706b38dbae94941643Jeff Brown            updateScanState();
33989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            disconnect();
340cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
341cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
342cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
34389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void reportFeatureState() {
34489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        final int featureState = computeFeatureState();
34589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mHandler.post(new Runnable() {
34689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            @Override
34789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            public void run() {
34889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                mListener.onFeatureStateChanged(featureState);
34989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
35089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        });
35189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
35289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
35389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private int computeFeatureState() {
35489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (!mWifiP2pEnabled) {
35589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            return WifiDisplayStatus.FEATURE_STATE_DISABLED;
356e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
35789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        return mWifiDisplayOnSetting ? WifiDisplayStatus.FEATURE_STATE_ON :
35889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                WifiDisplayStatus.FEATURE_STATE_OFF;
359e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
360e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
361ce468a35b388ca46578934706b38dbae94941643Jeff Brown    private void updateScanState() {
362ce468a35b388ca46578934706b38dbae94941643Jeff Brown        if (mScanRequested && mWfdEnabled && mDesiredDevice == null) {
363ce468a35b388ca46578934706b38dbae94941643Jeff Brown            if (!mDiscoverPeersInProgress) {
364ce468a35b388ca46578934706b38dbae94941643Jeff Brown                Slog.i(TAG, "Starting Wifi display scan.");
365ce468a35b388ca46578934706b38dbae94941643Jeff Brown                mDiscoverPeersInProgress = true;
366ce468a35b388ca46578934706b38dbae94941643Jeff Brown                handleScanStarted();
367ce468a35b388ca46578934706b38dbae94941643Jeff Brown                tryDiscoverPeers();
368ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
369ce468a35b388ca46578934706b38dbae94941643Jeff Brown        } else {
370ce468a35b388ca46578934706b38dbae94941643Jeff Brown            if (mDiscoverPeersInProgress) {
371ce468a35b388ca46578934706b38dbae94941643Jeff Brown                // Cancel automatic retry right away.
372ce468a35b388ca46578934706b38dbae94941643Jeff Brown                mHandler.removeCallbacks(mDiscoverPeers);
373ce468a35b388ca46578934706b38dbae94941643Jeff Brown
374ce468a35b388ca46578934706b38dbae94941643Jeff Brown                // Defer actually stopping discovery if we have a connection attempt in progress.
375ce468a35b388ca46578934706b38dbae94941643Jeff Brown                // The wifi display connection attempt often fails if we are not in discovery
376ce468a35b388ca46578934706b38dbae94941643Jeff Brown                // mode.  So we allow discovery to continue until we give up trying to connect.
377ce468a35b388ca46578934706b38dbae94941643Jeff Brown                if (mDesiredDevice == null || mDesiredDevice == mConnectedDevice) {
378ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    Slog.i(TAG, "Stopping Wifi display scan.");
379ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    mDiscoverPeersInProgress = false;
380ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    stopPeerDiscovery();
381ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    handleScanFinished();
382ce468a35b388ca46578934706b38dbae94941643Jeff Brown                }
383ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
3840cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown        }
3850cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    }
3860cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
3870cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private void tryDiscoverPeers() {
388cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mWifiP2pManager.discoverPeers(mWifiP2pChannel, new ActionListener() {
389cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
390cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void onSuccess() {
391cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
392cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Discover peers succeeded.  Requesting peers now.");
393cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
394cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
395ce468a35b388ca46578934706b38dbae94941643Jeff Brown                if (mDiscoverPeersInProgress) {
396ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    requestPeers();
397ce468a35b388ca46578934706b38dbae94941643Jeff Brown                }
398cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
399cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
400cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
401cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void onFailure(int reason) {
402cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
403cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Discover peers failed with reason " + reason + ".");
404cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
4050cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
406ce468a35b388ca46578934706b38dbae94941643Jeff Brown                // Ignore the error.
407ce468a35b388ca46578934706b38dbae94941643Jeff Brown                // We will retry automatically in a little bit.
408ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
409ce468a35b388ca46578934706b38dbae94941643Jeff Brown        });
410ce468a35b388ca46578934706b38dbae94941643Jeff Brown
411ce468a35b388ca46578934706b38dbae94941643Jeff Brown        // Retry discover peers periodically until stopped.
412ce468a35b388ca46578934706b38dbae94941643Jeff Brown        mHandler.postDelayed(mDiscoverPeers, DISCOVER_PEERS_INTERVAL_MILLIS);
413ce468a35b388ca46578934706b38dbae94941643Jeff Brown    }
414ce468a35b388ca46578934706b38dbae94941643Jeff Brown
415ce468a35b388ca46578934706b38dbae94941643Jeff Brown    private void stopPeerDiscovery() {
416ce468a35b388ca46578934706b38dbae94941643Jeff Brown        mWifiP2pManager.stopPeerDiscovery(mWifiP2pChannel, new ActionListener() {
417ce468a35b388ca46578934706b38dbae94941643Jeff Brown            @Override
418ce468a35b388ca46578934706b38dbae94941643Jeff Brown            public void onSuccess() {
419ce468a35b388ca46578934706b38dbae94941643Jeff Brown                if (DEBUG) {
420ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    Slog.d(TAG, "Stop peer discovery succeeded.");
421ce468a35b388ca46578934706b38dbae94941643Jeff Brown                }
422ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
423ce468a35b388ca46578934706b38dbae94941643Jeff Brown
424ce468a35b388ca46578934706b38dbae94941643Jeff Brown            @Override
425ce468a35b388ca46578934706b38dbae94941643Jeff Brown            public void onFailure(int reason) {
426ce468a35b388ca46578934706b38dbae94941643Jeff Brown                if (DEBUG) {
427ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    Slog.d(TAG, "Stop peer discovery failed with reason " + reason + ".");
4280cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                }
429cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
430cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        });
431cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
432cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
433cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void requestPeers() {
434cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mWifiP2pManager.requestPeers(mWifiP2pChannel, new PeerListListener() {
435cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
436cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void onPeersAvailable(WifiP2pDeviceList peers) {
437cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
438cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Received list of peers.");
439cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
440cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
44189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                mAvailableWifiDisplayPeers.clear();
442cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                for (WifiP2pDevice device : peers.getDeviceList()) {
443cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    if (DEBUG) {
444cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        Slog.d(TAG, "  " + describeWifiP2pDevice(device));
445cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
446cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
447cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    if (isWifiDisplay(device)) {
44889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        mAvailableWifiDisplayPeers.add(device);
449cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
450cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
451cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
452ce468a35b388ca46578934706b38dbae94941643Jeff Brown                if (mDiscoverPeersInProgress) {
453ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    handleScanResults();
454ce468a35b388ca46578934706b38dbae94941643Jeff Brown                }
455e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
456e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
457e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
458cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
459e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private void handleScanStarted() {
460e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        mHandler.post(new Runnable() {
461e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
462e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
463e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                mListener.onScanStarted();
464e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
465e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
466e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
467cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
468ce468a35b388ca46578934706b38dbae94941643Jeff Brown    private void handleScanResults() {
46989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        final int count = mAvailableWifiDisplayPeers.size();
470e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count);
471e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        for (int i = 0; i < count; i++) {
47274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            WifiP2pDevice device = mAvailableWifiDisplayPeers.get(i);
47374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            displays[i] = createWifiDisplay(device);
47474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            updateDesiredDevice(device);
475e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
476e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
477e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        mHandler.post(new Runnable() {
478e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
479e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
480ce468a35b388ca46578934706b38dbae94941643Jeff Brown                mListener.onScanResults(displays);
481ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
482ce468a35b388ca46578934706b38dbae94941643Jeff Brown        });
483ce468a35b388ca46578934706b38dbae94941643Jeff Brown    }
484ce468a35b388ca46578934706b38dbae94941643Jeff Brown
485ce468a35b388ca46578934706b38dbae94941643Jeff Brown    private void handleScanFinished() {
486ce468a35b388ca46578934706b38dbae94941643Jeff Brown        mHandler.post(new Runnable() {
487ce468a35b388ca46578934706b38dbae94941643Jeff Brown            @Override
488ce468a35b388ca46578934706b38dbae94941643Jeff Brown            public void run() {
489ce468a35b388ca46578934706b38dbae94941643Jeff Brown                mListener.onScanFinished();
490cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
491cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        });
492cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
493cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
49474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private void updateDesiredDevice(WifiP2pDevice device) {
49574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        // Handle the case where the device to which we are connecting or connected
49674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        // may have been renamed or reported different properties in the latest scan.
49774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        final String address = device.deviceAddress;
49874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        if (mDesiredDevice != null && mDesiredDevice.deviceAddress.equals(address)) {
49974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            if (DEBUG) {
50074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                Slog.d(TAG, "updateDesiredDevice: new information "
50174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                        + describeWifiP2pDevice(device));
50274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            }
50374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            mDesiredDevice.update(device);
50474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            if (mAdvertisedDisplay != null
50574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    && mAdvertisedDisplay.getDeviceAddress().equals(address)) {
50674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                readvertiseDisplay(createWifiDisplay(mDesiredDevice));
50774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            }
50874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        }
50974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    }
51074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
511cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void connect(final WifiP2pDevice device) {
512cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mDesiredDevice != null
513cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                && !mDesiredDevice.deviceAddress.equals(device.deviceAddress)) {
514cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (DEBUG) {
515cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Slog.d(TAG, "connect: nothing to do, already connecting to "
516cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + describeWifiP2pDevice(device));
517cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
518cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return;
519cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
520cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
521cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mConnectedDevice != null
522cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                && !mConnectedDevice.deviceAddress.equals(device.deviceAddress)
523cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                && mDesiredDevice == null) {
524cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (DEBUG) {
525cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Slog.d(TAG, "connect: nothing to do, already connected to "
526cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + describeWifiP2pDevice(device) + " and not part way through "
527cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + "connecting to a different device.");
528cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
5290cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown            return;
530cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
531cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
532ce468a35b388ca46578934706b38dbae94941643Jeff Brown        if (!mWfdEnabled) {
533ce468a35b388ca46578934706b38dbae94941643Jeff Brown            Slog.i(TAG, "Ignoring request to connect to Wifi display because the "
534ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    +" feature is currently disabled: " + device.deviceName);
535ce468a35b388ca46578934706b38dbae94941643Jeff Brown            return;
536ce468a35b388ca46578934706b38dbae94941643Jeff Brown        }
537ce468a35b388ca46578934706b38dbae94941643Jeff Brown
538cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mDesiredDevice = device;
5390cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown        mConnectionRetriesLeft = CONNECT_MAX_RETRIES;
540cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        updateConnection();
541cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
542cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
543cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void disconnect() {
544cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mDesiredDevice = null;
545cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        updateConnection();
546cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
547cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
5480cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private void retryConnection() {
54989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        // Cheap hack.  Make a new instance of the device object so that we
55089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        // can distinguish it from the previous connection attempt.
55189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        // This will cause us to tear everything down before we try again.
55289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mDesiredDevice = new WifiP2pDevice(mDesiredDevice);
55389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        updateConnection();
5540cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    }
5550cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
556cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    /**
557cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * This function is called repeatedly after each asynchronous operation
558cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * until all preconditions for the connection have been satisfied and the
559cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * connection is established (or not).
560cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     */
561cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void updateConnection() {
562ce468a35b388ca46578934706b38dbae94941643Jeff Brown        // Step 0. Stop scans if necessary to prevent interference while connected.
563ce468a35b388ca46578934706b38dbae94941643Jeff Brown        // Resume scans later when no longer attempting to connect.
564ce468a35b388ca46578934706b38dbae94941643Jeff Brown        updateScanState();
565ce468a35b388ca46578934706b38dbae94941643Jeff Brown
566cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Step 1. Before we try to connect to a new device, tell the system we
567cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // have disconnected from the old one.
568f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        if (mRemoteDisplay != null && mConnectedDevice != mDesiredDevice) {
569f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            Slog.i(TAG, "Stopped listening for RTSP connection on " + mRemoteDisplayInterface
570f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    + " from Wifi display: " + mConnectedDevice.deviceName);
571f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
572f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplay.dispose();
573f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplay = null;
574f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplayInterface = null;
575f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplayConnected = false;
576f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mHandler.removeCallbacks(mRtspTimeout);
577f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
578f110a3701b8d7ac435c5bb65df4dd9d758be1762Jeff Brown            mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_DISABLED);
579c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            unadvertiseDisplay();
580cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
581cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            // continue to next step
582cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
583cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
584cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Step 2. Before we try to connect to a new device, disconnect from the old one.
58574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        if (mDisconnectingDevice != null) {
58674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            return; // wait for asynchronous callback
58774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        }
588cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) {
589cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName);
59074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            mDisconnectingDevice = mConnectedDevice;
59174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            mConnectedDevice = null;
5921f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            mConnectedDeviceGroupInfo = null;
593cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
594c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            unadvertiseDisplay();
595c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
59674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            final WifiP2pDevice oldDevice = mDisconnectingDevice;
597cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() {
598cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
599cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onSuccess() {
600cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.i(TAG, "Disconnected from Wifi display: " + oldDevice.deviceName);
601cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    next();
602cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
603cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
604cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
605cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onFailure(int reason) {
606cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.i(TAG, "Failed to disconnect from Wifi display: "
607cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            + oldDevice.deviceName + ", reason=" + reason);
608cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    next();
609cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
610cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
611cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                private void next() {
61274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    if (mDisconnectingDevice == oldDevice) {
61374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                        mDisconnectingDevice = null;
614cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        updateConnection();
615cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
616cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
617cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            });
618cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return; // wait for asynchronous callback
619cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
620cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
621cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Step 3. Before we try to connect to a new device, stop trying to connect
622cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // to the old one.
62374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        if (mCancelingDevice != null) {
62474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            return; // wait for asynchronous callback
62574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        }
626cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mConnectingDevice != null && mConnectingDevice != mDesiredDevice) {
627cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Slog.i(TAG, "Canceling connection to Wifi display: " + mConnectingDevice.deviceName);
62874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            mCancelingDevice = mConnectingDevice;
62974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            mConnectingDevice = null;
630cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
631c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            unadvertiseDisplay();
632cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mHandler.removeCallbacks(mConnectionTimeout);
633cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
63474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            final WifiP2pDevice oldDevice = mCancelingDevice;
635cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mWifiP2pManager.cancelConnect(mWifiP2pChannel, new ActionListener() {
636cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
637cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onSuccess() {
638cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.i(TAG, "Canceled connection to Wifi display: " + oldDevice.deviceName);
639cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    next();
640cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
641cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
642cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
643cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onFailure(int reason) {
644cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.i(TAG, "Failed to cancel connection to Wifi display: "
645cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            + oldDevice.deviceName + ", reason=" + reason);
646cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    next();
647cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
648cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
649cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                private void next() {
65074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    if (mCancelingDevice == oldDevice) {
65174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                        mCancelingDevice = null;
652cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        updateConnection();
653cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
654cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
655cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            });
656cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return; // wait for asynchronous callback
657cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
658cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
6591f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        // Step 4. If we wanted to disconnect, or we're updating after starting an
6601f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        // autonomous GO, then mission accomplished.
661cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mDesiredDevice == null) {
6621f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            if (mWifiDisplayCertMode) {
6631f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                mListener.onDisplaySessionInfo(getSessionInfo(mConnectedDeviceGroupInfo, 0));
6641f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            }
665c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            unadvertiseDisplay();
666cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return; // done
667cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
668cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
669cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Step 5. Try to connect.
670cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mConnectedDevice == null && mConnectingDevice == null) {
671cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Slog.i(TAG, "Connecting to Wifi display: " + mDesiredDevice.deviceName);
672cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
673cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mConnectingDevice = mDesiredDevice;
674cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            WifiP2pConfig config = new WifiP2pConfig();
6756681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff            WpsInfo wps = new WpsInfo();
676e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang            if (mWifiDisplayWpsConfig != WpsInfo.INVALID) {
677e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang                wps.setup = mWifiDisplayWpsConfig;
678e38af818b10e1a4927cc3fd69d19c9125d579321Chong Zhang            } else if (mConnectingDevice.wpsPbcSupported()) {
6796681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff                wps.setup = WpsInfo.PBC;
6806681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff            } else if (mConnectingDevice.wpsDisplaySupported()) {
6816681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff                // We do keypad if peer does display
6826681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff                wps.setup = WpsInfo.KEYPAD;
6836681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff            } else {
6846681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff                wps.setup = WpsInfo.DISPLAY;
6856681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff            }
6866681be27875a50bd0c74826cb5d8defec72b8d58Irfan Sheriff            config.wps = wps;
687cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            config.deviceAddress = mConnectingDevice.deviceAddress;
688e0c28d5f1358fc2d4c464f910bd04fed4b283fefIrfan Sheriff            // Helps with STA & P2P concurrency
68999766cf40ed706aad36032f2107fb0c1e54fc398Irfan Sheriff            config.groupOwnerIntent = WifiP2pConfig.MIN_GROUP_OWNER_INTENT;
690cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
691c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            WifiDisplay display = createWifiDisplay(mConnectingDevice);
692c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            advertiseDisplay(display, null, 0, 0, 0);
693e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
694cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            final WifiP2pDevice newDevice = mDesiredDevice;
695cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mWifiP2pManager.connect(mWifiP2pChannel, config, new ActionListener() {
696cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
697cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onSuccess() {
698cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    // The connection may not yet be established.  We still need to wait
699cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    // for WIFI_P2P_CONNECTION_CHANGED_ACTION.  However, we might never
700cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    // get that broadcast, so we register a timeout.
701cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.i(TAG, "Initiated connection to Wifi display: " + newDevice.deviceName);
702cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
703cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    mHandler.postDelayed(mConnectionTimeout, CONNECTION_TIMEOUT_SECONDS * 1000);
704cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
705cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
706cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
707cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onFailure(int reason) {
708cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    if (mConnectingDevice == newDevice) {
709f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        Slog.i(TAG, "Failed to initiate connection to Wifi display: "
710f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                                + newDevice.deviceName + ", reason=" + reason);
711cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        mConnectingDevice = null;
7120cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                        handleConnectionFailure(false);
713cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
714cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
715cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            });
716cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return; // wait for asynchronous callback
717cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
718cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
719ce468a35b388ca46578934706b38dbae94941643Jeff Brown        // Step 6. Listen for incoming RTSP connection.
720f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        if (mConnectedDevice != null && mRemoteDisplay == null) {
721cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Inet4Address addr = getInterfaceAddress(mConnectedDeviceGroupInfo);
722cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (addr == null) {
723cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Slog.i(TAG, "Failed to get local interface address for communicating "
724cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + "with Wifi display: " + mConnectedDevice.deviceName);
7250cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                handleConnectionFailure(false);
726cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                return; // done
727cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
728cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
729f110a3701b8d7ac435c5bb65df4dd9d758be1762Jeff Brown            mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_SOURCE);
730c9bd4ca005768cb30aaaa44c1171e113c13cd107Jeff Brown
731f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            final WifiP2pDevice oldDevice = mConnectedDevice;
7320f68d166e6ca45fe27410ea520967275e0733757Jeff Brown            final int port = getPortNumber(mConnectedDevice);
733cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            final String iface = addr.getHostAddress() + ":" + port;
734f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplayInterface = iface;
735cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
736f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            Slog.i(TAG, "Listening for RTSP connection on " + iface
737f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    + " from Wifi display: " + mConnectedDevice.deviceName);
738f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
739f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplay = RemoteDisplay.listen(iface, new RemoteDisplay.Listener() {
740cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
741c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                public void onDisplayConnected(Surface surface,
7421f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                        int width, int height, int flags, int session) {
743f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    if (mConnectedDevice == oldDevice && !mRemoteDisplayConnected) {
744f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        Slog.i(TAG, "Opened RTSP connection with Wifi display: "
745f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                                + mConnectedDevice.deviceName);
746f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        mRemoteDisplayConnected = true;
747f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        mHandler.removeCallbacks(mRtspTimeout);
748f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
7491f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                        if (mWifiDisplayCertMode) {
7501f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                            mListener.onDisplaySessionInfo(
7511f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                    getSessionInfo(mConnectedDeviceGroupInfo, session));
7521f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                        }
7531f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
754f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        final WifiDisplay display = createWifiDisplay(mConnectedDevice);
755c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        advertiseDisplay(display, surface, width, height, flags);
756f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    }
757cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
758f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
759f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                @Override
760f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                public void onDisplayDisconnected() {
761f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    if (mConnectedDevice == oldDevice) {
762f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        Slog.i(TAG, "Closed RTSP connection with Wifi display: "
763f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                                + mConnectedDevice.deviceName);
764f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        mHandler.removeCallbacks(mRtspTimeout);
765f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        disconnect();
766f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    }
767f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                }
768f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
769f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                @Override
770f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                public void onDisplayError(int error) {
771f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    if (mConnectedDevice == oldDevice) {
772f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        Slog.i(TAG, "Lost RTSP connection with Wifi display due to error "
773f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                                + error + ": " + mConnectedDevice.deviceName);
774f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        mHandler.removeCallbacks(mRtspTimeout);
775f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        handleConnectionFailure(false);
776f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    }
777f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                }
778f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            }, mHandler);
779f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
7801f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            // Use extended timeout value for certification, as some tests require user inputs
7811f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            int rtspTimeout = mWifiDisplayCertMode ?
7821f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                    RTSP_TIMEOUT_SECONDS_CERT_MODE : RTSP_TIMEOUT_SECONDS;
7831f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
7841f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            mHandler.postDelayed(mRtspTimeout, rtspTimeout * 1000);
7851f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        }
7861f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    }
7871f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
7881f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    private WifiDisplaySessionInfo getSessionInfo(WifiP2pGroup info, int session) {
7891f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        if (info == null) {
7901f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            return null;
7911f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        }
7921f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        Inet4Address addr = getInterfaceAddress(info);
7931f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        WifiDisplaySessionInfo sessionInfo = new WifiDisplaySessionInfo(
7941f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                !info.getOwner().deviceAddress.equals(mThisDevice.deviceAddress),
7951f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                session,
7961f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                info.getOwner().deviceAddress + " " + info.getNetworkName(),
7971f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                info.getPassphrase(),
7981f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                (addr != null) ? addr.getHostAddress() : "");
7991f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        if (DEBUG) {
8001f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            Slog.d(TAG, sessionInfo.toString());
801cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
8021f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        return sessionInfo;
803cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
804cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
805cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void handleStateChanged(boolean enabled) {
80689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mWifiP2pEnabled = enabled;
80789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        updateWfdEnableState();
808cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
809cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
810cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void handlePeersChanged() {
81156925d65fde7f1ac8676ada6f91d0e604645c0a5Irfan Sheriff        // Even if wfd is disabled, it is best to get the latest set of peers to
81256925d65fde7f1ac8676ada6f91d0e604645c0a5Irfan Sheriff        // keep in sync with the p2p framework
81356925d65fde7f1ac8676ada6f91d0e604645c0a5Irfan Sheriff        requestPeers();
814cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
815cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
816cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void handleConnectionChanged(NetworkInfo networkInfo) {
817cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mNetworkInfo = networkInfo;
818180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        if (mWfdEnabled && networkInfo.isConnected()) {
8191f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            if (mDesiredDevice != null || mWifiDisplayCertMode) {
820cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mWifiP2pManager.requestGroupInfo(mWifiP2pChannel, new GroupInfoListener() {
821cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    @Override
822cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    public void onGroupInfoAvailable(WifiP2pGroup info) {
823cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        if (DEBUG) {
824cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            Slog.d(TAG, "Received group info: " + describeWifiP2pGroup(info));
825cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        }
826cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
827cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        if (mConnectingDevice != null && !info.contains(mConnectingDevice)) {
828cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            Slog.i(TAG, "Aborting connection to Wifi display because "
829cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                                    + "the current P2P group does not contain the device "
83089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                                    + "we expected to find: " + mConnectingDevice.deviceName
83189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                                    + ", group info was: " + describeWifiP2pGroup(info));
8320cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                            handleConnectionFailure(false);
833cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            return;
834cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        }
835cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
836cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        if (mDesiredDevice != null && !info.contains(mDesiredDevice)) {
837cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            disconnect();
838cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            return;
839cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        }
840cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
8411f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                        if (mWifiDisplayCertMode) {
8421f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                            boolean owner = info.getOwner().deviceAddress
8431f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                    .equals(mThisDevice.deviceAddress);
8441f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                            if (owner && info.getClientList().isEmpty()) {
8451f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                // this is the case when we started Autonomous GO,
8461f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                // and no client has connected, save group info
8471f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                // and updateConnection()
8481f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                mConnectingDevice = mDesiredDevice = null;
8491f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                mConnectedDeviceGroupInfo = info;
8501f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                updateConnection();
8511f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                            } else if (mConnectingDevice == null && mDesiredDevice == null) {
8521f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                // this is the case when we received an incoming connection
8531f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                // from the sink, update both mConnectingDevice and mDesiredDevice
8541f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                // then proceed to updateConnection() below
8551f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                mConnectingDevice = mDesiredDevice = owner ?
8561f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                                        info.getClientList().iterator().next() : info.getOwner();
8571f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                            }
8581f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                        }
8591f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
860cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) {
8610cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                            Slog.i(TAG, "Connected to Wifi display: "
8620cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                                    + mConnectingDevice.deviceName);
863cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
864cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            mHandler.removeCallbacks(mConnectionTimeout);
865cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            mConnectedDeviceGroupInfo = info;
866cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            mConnectedDevice = mConnectingDevice;
867cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            mConnectingDevice = null;
868cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            updateConnection();
869cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        }
870cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
871cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                });
872cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
873cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        } else {
8741f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            mConnectedDeviceGroupInfo = null;
875ce468a35b388ca46578934706b38dbae94941643Jeff Brown
876ce468a35b388ca46578934706b38dbae94941643Jeff Brown            // Disconnect if we lost the network while connecting or connected to a display.
877ce468a35b388ca46578934706b38dbae94941643Jeff Brown            if (mConnectingDevice != null || mConnectedDevice != null) {
878ce468a35b388ca46578934706b38dbae94941643Jeff Brown                disconnect();
879ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
880180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown
881180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown            // After disconnection for a group, for some reason we have a tendency
882180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown            // to get a peer change notification with an empty list of peers.
883180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown            // Perform a fresh scan.
884180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown            if (mWfdEnabled) {
885180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                requestPeers();
886180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown            }
887cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
888cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
889cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
890ce468a35b388ca46578934706b38dbae94941643Jeff Brown    private final Runnable mDiscoverPeers = new Runnable() {
891ce468a35b388ca46578934706b38dbae94941643Jeff Brown        @Override
892ce468a35b388ca46578934706b38dbae94941643Jeff Brown        public void run() {
893ce468a35b388ca46578934706b38dbae94941643Jeff Brown            tryDiscoverPeers();
894ce468a35b388ca46578934706b38dbae94941643Jeff Brown        }
895ce468a35b388ca46578934706b38dbae94941643Jeff Brown    };
896ce468a35b388ca46578934706b38dbae94941643Jeff Brown
897cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final Runnable mConnectionTimeout = new Runnable() {
898cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
899cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void run() {
900cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) {
901cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Slog.i(TAG, "Timed out waiting for Wifi display connection after "
902cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + CONNECTION_TIMEOUT_SECONDS + " seconds: "
903cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + mConnectingDevice.deviceName);
9040cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                handleConnectionFailure(true);
905cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
906cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
907cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    };
908cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
909f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private final Runnable mRtspTimeout = new Runnable() {
910f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        @Override
911f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        public void run() {
912f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            if (mConnectedDevice != null
913f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    && mRemoteDisplay != null && !mRemoteDisplayConnected) {
914f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                Slog.i(TAG, "Timed out waiting for Wifi display RTSP connection after "
915f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        + RTSP_TIMEOUT_SECONDS + " seconds: "
916f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        + mConnectedDevice.deviceName);
917f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                handleConnectionFailure(true);
918f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            }
919f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        }
920f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    };
921f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
9220cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private void handleConnectionFailure(boolean timeoutOccurred) {
923f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        Slog.i(TAG, "Wifi display connection failed!");
9240cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
925f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        if (mDesiredDevice != null) {
9260cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown            if (mConnectionRetriesLeft > 0) {
92789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                final WifiP2pDevice oldDevice = mDesiredDevice;
9280cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                mHandler.postDelayed(new Runnable() {
9290cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                    @Override
9300cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                    public void run() {
93189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        if (mDesiredDevice == oldDevice && mConnectionRetriesLeft > 0) {
93289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            mConnectionRetriesLeft -= 1;
93389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            Slog.i(TAG, "Retrying Wifi display connection.  Retries left: "
93489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                                    + mConnectionRetriesLeft);
93589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            retryConnection();
93689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        }
9370cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                    }
9380cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                }, timeoutOccurred ? 0 : CONNECT_RETRY_DELAY_MILLIS);
9390cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown            } else {
9400cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                disconnect();
9410cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown            }
942cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
943cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
944cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
945c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private void advertiseDisplay(final WifiDisplay display,
946c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            final Surface surface, final int width, final int height, final int flags) {
947c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        if (!Objects.equal(mAdvertisedDisplay, display)
948c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                || mAdvertisedDisplaySurface != surface
949c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                || mAdvertisedDisplayWidth != width
950c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                || mAdvertisedDisplayHeight != height
951c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                || mAdvertisedDisplayFlags != flags) {
952c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            final WifiDisplay oldDisplay = mAdvertisedDisplay;
953c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            final Surface oldSurface = mAdvertisedDisplaySurface;
954c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
955c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mAdvertisedDisplay = display;
956c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mAdvertisedDisplaySurface = surface;
957c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mAdvertisedDisplayWidth = width;
958c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mAdvertisedDisplayHeight = height;
959c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mAdvertisedDisplayFlags = flags;
960c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
961c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mHandler.post(new Runnable() {
962c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                @Override
963c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                public void run() {
964c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                    if (oldSurface != null && surface != oldSurface) {
965c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        mListener.onDisplayDisconnected();
96674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    } else if (oldDisplay != null && !oldDisplay.hasSameAddress(display)) {
967c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        mListener.onDisplayConnectionFailed();
968c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                    }
969c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
970c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                    if (display != null) {
97174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                        if (!display.hasSameAddress(oldDisplay)) {
972c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                            mListener.onDisplayConnecting(display);
97374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                        } else if (!display.equals(oldDisplay)) {
97474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                            // The address is the same but some other property such as the
97574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                            // name must have changed.
97674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                            mListener.onDisplayChanged(display);
977c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        }
978c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        if (surface != null && surface != oldSurface) {
979c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                            mListener.onDisplayConnected(display, surface, width, height, flags);
980c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        }
981c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                    }
982c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                }
983c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            });
984c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        }
985c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    }
986c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
987c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private void unadvertiseDisplay() {
988c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        advertiseDisplay(null, null, 0, 0, 0);
989c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    }
990c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
99174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private void readvertiseDisplay(WifiDisplay display) {
99274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        advertiseDisplay(display, mAdvertisedDisplaySurface,
99374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                mAdvertisedDisplayWidth, mAdvertisedDisplayHeight,
99474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                mAdvertisedDisplayFlags);
99574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    }
99674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
997cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static Inet4Address getInterfaceAddress(WifiP2pGroup info) {
998cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        NetworkInterface iface;
999cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        try {
1000cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            iface = NetworkInterface.getByName(info.getInterface());
1001cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        } catch (SocketException ex) {
1002cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Slog.w(TAG, "Could not obtain address of network interface "
1003cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    + info.getInterface(), ex);
1004cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return null;
1005cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
1006cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1007cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        Enumeration<InetAddress> addrs = iface.getInetAddresses();
1008cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        while (addrs.hasMoreElements()) {
1009cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            InetAddress addr = addrs.nextElement();
1010cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (addr instanceof Inet4Address) {
1011cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                return (Inet4Address)addr;
1012cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
1013cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
1014cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1015cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        Slog.w(TAG, "Could not obtain address of network interface "
1016cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                + info.getInterface() + " because it had no IPv4 addresses.");
1017cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        return null;
1018cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
1019cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
10200f68d166e6ca45fe27410ea520967275e0733757Jeff Brown    private static int getPortNumber(WifiP2pDevice device) {
10210f68d166e6ca45fe27410ea520967275e0733757Jeff Brown        if (device.deviceName.startsWith("DIRECT-")
10220f68d166e6ca45fe27410ea520967275e0733757Jeff Brown                && device.deviceName.endsWith("Broadcom")) {
10230f68d166e6ca45fe27410ea520967275e0733757Jeff Brown            // These dongles ignore the port we broadcast in our WFD IE.
10240f68d166e6ca45fe27410ea520967275e0733757Jeff Brown            return 8554;
10250f68d166e6ca45fe27410ea520967275e0733757Jeff Brown        }
10260f68d166e6ca45fe27410ea520967275e0733757Jeff Brown        return DEFAULT_CONTROL_PORT;
10270f68d166e6ca45fe27410ea520967275e0733757Jeff Brown    }
10280f68d166e6ca45fe27410ea520967275e0733757Jeff Brown
1029cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static boolean isWifiDisplay(WifiP2pDevice device) {
10300f68d166e6ca45fe27410ea520967275e0733757Jeff Brown        return device.wfdInfo != null
10310f68d166e6ca45fe27410ea520967275e0733757Jeff Brown                && device.wfdInfo.isWfdEnabled()
10320f68d166e6ca45fe27410ea520967275e0733757Jeff Brown                && isPrimarySinkDeviceType(device.wfdInfo.getDeviceType());
10330f68d166e6ca45fe27410ea520967275e0733757Jeff Brown    }
10340f68d166e6ca45fe27410ea520967275e0733757Jeff Brown
10350f68d166e6ca45fe27410ea520967275e0733757Jeff Brown    private static boolean isPrimarySinkDeviceType(int deviceType) {
10360f68d166e6ca45fe27410ea520967275e0733757Jeff Brown        return deviceType == WifiP2pWfdInfo.PRIMARY_SINK
10370f68d166e6ca45fe27410ea520967275e0733757Jeff Brown                || deviceType == WifiP2pWfdInfo.SOURCE_OR_PRIMARY_SINK;
1038cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
1039cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1040cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static String describeWifiP2pDevice(WifiP2pDevice device) {
1041cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        return device != null ? device.toString().replace('\n', ',') : "null";
1042cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
1043cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1044cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static String describeWifiP2pGroup(WifiP2pGroup group) {
1045cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        return group != null ? group.toString().replace('\n', ',') : "null";
1046cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
1047cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1048e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private static WifiDisplay createWifiDisplay(WifiP2pDevice device) {
104921f603996ed83c7a9a6c430582e8a5af5ac13c6cChong Zhang        return new WifiDisplay(device.deviceAddress, device.deviceName, null,
1050ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                true, device.wfdInfo.isSessionAvailable(), false);
1051e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
1052e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
1053cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final BroadcastReceiver mWifiP2pReceiver = new BroadcastReceiver() {
1054cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
1055cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void onReceive(Context context, Intent intent) {
1056cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            final String action = intent.getAction();
1057cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) {
105889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                // This broadcast is sticky so we'll always get the initial Wifi P2P state
105989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                // on startup.
1060cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                boolean enabled = (intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE,
1061cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        WifiP2pManager.WIFI_P2P_STATE_DISABLED)) ==
1062cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        WifiP2pManager.WIFI_P2P_STATE_ENABLED;
1063cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
1064cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Received WIFI_P2P_STATE_CHANGED_ACTION: enabled="
1065cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            + enabled);
1066cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
1067cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1068cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                handleStateChanged(enabled);
1069cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            } else if (action.equals(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)) {
1070cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
1071cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Received WIFI_P2P_PEERS_CHANGED_ACTION.");
1072cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
1073cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1074cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                handlePeersChanged();
1075cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) {
1076cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra(
1077cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        WifiP2pManager.EXTRA_NETWORK_INFO);
1078cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
1079cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Received WIFI_P2P_CONNECTION_CHANGED_ACTION: networkInfo="
1080cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            + networkInfo);
1081cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
1082cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1083cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                handleConnectionChanged(networkInfo);
10841f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            } else if (action.equals(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)) {
10851f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                mThisDevice = (WifiP2pDevice) intent.getParcelableExtra(
10861f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                        WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);
10871f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                if (DEBUG) {
10881f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                    Slog.d(TAG, "Received WIFI_P2P_THIS_DEVICE_CHANGED_ACTION: mThisDevice= "
10891f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                            + mThisDevice);
10901f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                }
1091cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
1092cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
1093cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    };
1094cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1095cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    /**
1096cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * Called on the handler thread when displays are connected or disconnected.
1097cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     */
1098cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public interface Listener {
109989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        void onFeatureStateChanged(int featureState);
1100e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
1101e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        void onScanStarted();
1102ce468a35b388ca46578934706b38dbae94941643Jeff Brown        void onScanResults(WifiDisplay[] availableDisplays);
1103ce468a35b388ca46578934706b38dbae94941643Jeff Brown        void onScanFinished();
1104e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
1105e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        void onDisplayConnecting(WifiDisplay display);
1106e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        void onDisplayConnectionFailed();
110774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        void onDisplayChanged(WifiDisplay display);
1108f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        void onDisplayConnected(WifiDisplay display,
1109f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                Surface surface, int width, int height, int flags);
11101f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        void onDisplaySessionInfo(WifiDisplaySessionInfo sessionInfo);
1111cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        void onDisplayDisconnected();
1112cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
1113cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown}
1114