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;
2889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport android.hardware.display.WifiDisplayStatus;
2988469e56c8294a928e65398352e8444d66bdb75aJeff Brownimport android.media.AudioManager;
30f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brownimport android.media.RemoteDisplay;
31cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.NetworkInfo;
3289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport android.net.Uri;
33cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pConfig;
34cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pDevice;
35cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pDeviceList;
36cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pGroup;
37cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pManager;
38cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pWfdInfo;
39cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pManager.ActionListener;
40cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pManager.Channel;
41cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pManager.GroupInfoListener;
42cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.net.wifi.p2p.WifiP2pManager.PeerListListener;
43cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.os.Handler;
4489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brownimport android.provider.Settings;
45cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.util.Slog;
46f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brownimport android.view.Surface;
47cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
48cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.io.PrintWriter;
49cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.net.Inet4Address;
50cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.net.InetAddress;
51cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.net.NetworkInterface;
52cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.net.SocketException;
53cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.util.ArrayList;
54cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.util.Enumeration;
55cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
56c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brownimport libcore.util.Objects;
57c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
58cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown/**
59cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Manages all of the various asynchronous interactions with the {@link WifiP2pManager}
60cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * on behalf of {@link WifiDisplayAdapter}.
61cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * <p>
62cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * This code is isolated from {@link WifiDisplayAdapter} so that we can avoid
63cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * accidentally introducing any deadlocks due to the display manager calling
64cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * outside of itself while holding its lock.  It's also way easier to write this
65cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * asynchronous code if we can assume that it is single-threaded.
66cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p><p>
67cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * The controller must be instantiated on the handler thread.
68cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p>
69cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown */
70cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownfinal class WifiDisplayController implements DumpUtils.Dump {
71cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static final String TAG = "WifiDisplayController";
72c5df37c285221d0fb113f55b9e78b35632241d3fJeff Brown    private static final boolean DEBUG = false;
73cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
74cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static final int DEFAULT_CONTROL_PORT = 7236;
75cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static final int MAX_THROUGHPUT = 50;
762c2ca5cb7c083cd53dee00e71af99d1abf931976Irfan Sheriff    private static final int CONNECTION_TIMEOUT_SECONDS = 60;
77f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private static final int RTSP_TIMEOUT_SECONDS = 15;
78cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
790cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private static final int DISCOVER_PEERS_MAX_RETRIES = 10;
800cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private static final int DISCOVER_PEERS_RETRY_DELAY_MILLIS = 500;
810cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
820cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private static final int CONNECT_MAX_RETRIES = 3;
830cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private static final int CONNECT_RETRY_DELAY_MILLIS = 500;
840cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
8588469e56c8294a928e65398352e8444d66bdb75aJeff Brown    // A unique token to identify the remote submix that is managed by Wifi display.
8688469e56c8294a928e65398352e8444d66bdb75aJeff Brown    // It must match what the media server uses when it starts recording the submix
8788469e56c8294a928e65398352e8444d66bdb75aJeff Brown    // for transmission.  We use 0 although the actual value is currently ignored.
8888469e56c8294a928e65398352e8444d66bdb75aJeff Brown    private static final int REMOTE_SUBMIX_ADDRESS = 0;
8988469e56c8294a928e65398352e8444d66bdb75aJeff Brown
90cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final Context mContext;
91cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final Handler mHandler;
92cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final Listener mListener;
9388469e56c8294a928e65398352e8444d66bdb75aJeff Brown
94cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final WifiP2pManager mWifiP2pManager;
95cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final Channel mWifiP2pChannel;
96cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
9788469e56c8294a928e65398352e8444d66bdb75aJeff Brown    private final AudioManager mAudioManager;
9888469e56c8294a928e65398352e8444d66bdb75aJeff Brown
99cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private boolean mWifiP2pEnabled;
100cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private boolean mWfdEnabled;
101cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private boolean mWfdEnabling;
102cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private NetworkInfo mNetworkInfo;
103cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
10489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private final ArrayList<WifiP2pDevice> mAvailableWifiDisplayPeers =
105cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            new ArrayList<WifiP2pDevice>();
106cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
10789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    // True if Wifi display is enabled by the user.
10889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private boolean mWifiDisplayOnSetting;
10989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
1100cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    // True if there is a call to discoverPeers in progress.
1110cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private boolean mDiscoverPeersInProgress;
1120cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
1130cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    // Number of discover peers retries remaining.
1140cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private int mDiscoverPeersRetriesLeft;
1150cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
116cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // The device to which we want to connect, or null if we want to be disconnected.
117cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiP2pDevice mDesiredDevice;
118cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
119cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // The device to which we are currently connecting, or null if we have already connected
120cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // or are not trying to connect.
121cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiP2pDevice mConnectingDevice;
122cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
123cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // The device to which we are currently connected, which means we have an active P2P group.
124cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiP2pDevice mConnectedDevice;
125cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
126cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // The group info obtained after connecting.
127cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiP2pGroup mConnectedDeviceGroupInfo;
128cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1290cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    // Number of connection retries remaining.
1300cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private int mConnectionRetriesLeft;
1310cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
132f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    // The remote display that is listening on the connection.
133f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    // Created after the Wifi P2P network is connected.
134f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private RemoteDisplay mRemoteDisplay;
135f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
136f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    // The remote display interface.
137f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private String mRemoteDisplayInterface;
138f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
139f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    // True if RTSP has connected.
140f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private boolean mRemoteDisplayConnected;
141f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
142c9bd4ca005768cb30aaaa44c1171e113c13cd107Jeff Brown    // True if the remote submix is enabled.
143c9bd4ca005768cb30aaaa44c1171e113c13cd107Jeff Brown    private boolean mRemoteSubmixOn;
144c9bd4ca005768cb30aaaa44c1171e113c13cd107Jeff Brown
145c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    // The information we have most recently told WifiDisplayAdapter about.
146c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private WifiDisplay mAdvertisedDisplay;
147c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private Surface mAdvertisedDisplaySurface;
148c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private int mAdvertisedDisplayWidth;
149c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private int mAdvertisedDisplayHeight;
150c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private int mAdvertisedDisplayFlags;
151c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
152cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public WifiDisplayController(Context context, Handler handler, Listener listener) {
153cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mContext = context;
154cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mHandler = handler;
155cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mListener = listener;
156cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
157cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mWifiP2pManager = (WifiP2pManager)context.getSystemService(Context.WIFI_P2P_SERVICE);
158cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mWifiP2pChannel = mWifiP2pManager.initialize(context, handler.getLooper(), null);
159cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
16088469e56c8294a928e65398352e8444d66bdb75aJeff Brown        mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
16188469e56c8294a928e65398352e8444d66bdb75aJeff Brown
162cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        IntentFilter intentFilter = new IntentFilter();
163cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
164cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
165cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
16689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        context.registerReceiver(mWifiP2pReceiver, intentFilter, null, mHandler);
16789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
16889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        ContentObserver settingsObserver = new ContentObserver(mHandler) {
16989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            @Override
17089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            public void onChange(boolean selfChange, Uri uri) {
17189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                updateSettings();
17289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
17389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        };
17489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
17589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        final ContentResolver resolver = mContext.getContentResolver();
17689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        resolver.registerContentObserver(Settings.Global.getUriFor(
17789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                Settings.Global.WIFI_DISPLAY_ON), false, settingsObserver);
17889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        updateSettings();
17989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
18089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
18189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void updateSettings() {
18289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        final ContentResolver resolver = mContext.getContentResolver();
18389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mWifiDisplayOnSetting = Settings.Global.getInt(resolver,
18489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                Settings.Global.WIFI_DISPLAY_ON, 0) != 0;
18589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
18689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        updateWfdEnableState();
187cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
188cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
189cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public void dump(PrintWriter pw) {
19089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mWifiDisplayOnSetting=" + mWifiDisplayOnSetting);
191cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled);
192cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mWfdEnabled=" + mWfdEnabled);
193cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mWfdEnabling=" + mWfdEnabling);
194cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mNetworkInfo=" + mNetworkInfo);
1950cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown        pw.println("mDiscoverPeersInProgress=" + mDiscoverPeersInProgress);
1960cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown        pw.println("mDiscoverPeersRetriesLeft=" + mDiscoverPeersRetriesLeft);
197cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice));
198cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice));
199cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        pw.println("mConnectedDevice=" + describeWifiP2pDevice(mConnectedDevice));
2000cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown        pw.println("mConnectionRetriesLeft=" + mConnectionRetriesLeft);
201f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        pw.println("mRemoteDisplay=" + mRemoteDisplay);
202f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        pw.println("mRemoteDisplayInterface=" + mRemoteDisplayInterface);
203f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        pw.println("mRemoteDisplayConnected=" + mRemoteDisplayConnected);
204c9bd4ca005768cb30aaaa44c1171e113c13cd107Jeff Brown        pw.println("mRemoteSubmixOn=" + mRemoteSubmixOn);
205c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        pw.println("mAdvertisedDisplay=" + mAdvertisedDisplay);
206c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        pw.println("mAdvertisedDisplaySurface=" + mAdvertisedDisplaySurface);
207c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        pw.println("mAdvertisedDisplayWidth=" + mAdvertisedDisplayWidth);
208c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        pw.println("mAdvertisedDisplayHeight=" + mAdvertisedDisplayHeight);
209c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        pw.println("mAdvertisedDisplayFlags=" + mAdvertisedDisplayFlags);
210cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
21189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mAvailableWifiDisplayPeers: size=" + mAvailableWifiDisplayPeers.size());
21289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        for (WifiP2pDevice device : mAvailableWifiDisplayPeers) {
213cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("  " + describeWifiP2pDevice(device));
214cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
215cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
216cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
217e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestScan() {
218e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        discoverPeers();
219e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
220e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
221e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestConnect(String address) {
22289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        for (WifiP2pDevice device : mAvailableWifiDisplayPeers) {
223e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            if (device.deviceAddress.equals(address)) {
224e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                connect(device);
225e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
226e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
227e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
228e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
229e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestDisconnect() {
230e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        disconnect();
231e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
232e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
23389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void updateWfdEnableState() {
23489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mWifiDisplayOnSetting && mWifiP2pEnabled) {
23589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            // WFD should be enabled.
23689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            if (!mWfdEnabled && !mWfdEnabling) {
23789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                mWfdEnabling = true;
23889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
23989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo();
24089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                wfdInfo.setWfdEnabled(true);
24189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                wfdInfo.setDeviceType(WifiP2pWfdInfo.WFD_SOURCE);
24289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                wfdInfo.setSessionAvailable(true);
24389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                wfdInfo.setControlPort(DEFAULT_CONTROL_PORT);
24489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                wfdInfo.setMaxThroughput(MAX_THROUGHPUT);
24589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() {
24689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    @Override
24789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    public void onSuccess() {
24889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        if (DEBUG) {
24989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            Slog.d(TAG, "Successfully set WFD info.");
25089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        }
25189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        if (mWfdEnabling) {
25289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            mWfdEnabling = false;
25389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            mWfdEnabled = true;
25489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            reportFeatureState();
25589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        }
256cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
257cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
25889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    @Override
25989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    public void onFailure(int reason) {
26089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        if (DEBUG) {
26189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            Slog.d(TAG, "Failed to set WFD info with reason " + reason + ".");
26289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        }
26389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        mWfdEnabling = false;
264cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
26589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                });
26689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
26789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        } else {
26889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            // WFD should be disabled.
26989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mWfdEnabling = false;
27089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mWfdEnabled = false;
27189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            reportFeatureState();
27289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            disconnect();
273cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
274cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
275cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
27689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void reportFeatureState() {
27789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        final int featureState = computeFeatureState();
27889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mHandler.post(new Runnable() {
27989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            @Override
28089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            public void run() {
28189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                mListener.onFeatureStateChanged(featureState);
28289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
28389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        });
28489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
28589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
28689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private int computeFeatureState() {
28789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (!mWifiP2pEnabled) {
28889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            return WifiDisplayStatus.FEATURE_STATE_DISABLED;
289e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
29089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        return mWifiDisplayOnSetting ? WifiDisplayStatus.FEATURE_STATE_ON :
29189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                WifiDisplayStatus.FEATURE_STATE_OFF;
292e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
293e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
294cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void discoverPeers() {
2950cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown        if (!mDiscoverPeersInProgress) {
2960cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown            mDiscoverPeersInProgress = true;
2970cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown            mDiscoverPeersRetriesLeft = DISCOVER_PEERS_MAX_RETRIES;
298e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            handleScanStarted();
2990cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown            tryDiscoverPeers();
3000cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown        }
3010cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    }
3020cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
3030cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private void tryDiscoverPeers() {
304cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mWifiP2pManager.discoverPeers(mWifiP2pChannel, new ActionListener() {
305cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
306cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void onSuccess() {
307cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
308cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Discover peers succeeded.  Requesting peers now.");
309cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
310cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
3110cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                mDiscoverPeersInProgress = false;
312cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                requestPeers();
313cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
314cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
315cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
316cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void onFailure(int reason) {
317cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
318cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Discover peers failed with reason " + reason + ".");
319cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
3200cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
3210cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                if (mDiscoverPeersInProgress) {
3220cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                    if (reason == 0 && mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) {
3230cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                        mHandler.postDelayed(new Runnable() {
3240cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                            @Override
3250cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                            public void run() {
3260cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                                if (mDiscoverPeersInProgress) {
3270cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                                    if (mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) {
3280cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                                        mDiscoverPeersRetriesLeft -= 1;
3290cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                                        if (DEBUG) {
3300cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                                            Slog.d(TAG, "Retrying discovery.  Retries left: "
3310cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                                                    + mDiscoverPeersRetriesLeft);
3320cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                                        }
3330cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                                        tryDiscoverPeers();
3340cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                                    } else {
335e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                                        handleScanFinished();
3360cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                                        mDiscoverPeersInProgress = false;
3370cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                                    }
3380cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                                }
3390cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                            }
3400cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                        }, DISCOVER_PEERS_RETRY_DELAY_MILLIS);
3410cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                    } else {
342e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                        handleScanFinished();
3430cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                        mDiscoverPeersInProgress = false;
3440cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                    }
3450cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                }
346cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
347cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        });
348cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
349cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
350cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void requestPeers() {
351cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mWifiP2pManager.requestPeers(mWifiP2pChannel, new PeerListListener() {
352cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
353cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void onPeersAvailable(WifiP2pDeviceList peers) {
354cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
355cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Received list of peers.");
356cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
357cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
35889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                mAvailableWifiDisplayPeers.clear();
359cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                for (WifiP2pDevice device : peers.getDeviceList()) {
360cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    if (DEBUG) {
361cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        Slog.d(TAG, "  " + describeWifiP2pDevice(device));
362cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
363cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
364cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    if (isWifiDisplay(device)) {
36589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        mAvailableWifiDisplayPeers.add(device);
366cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
367cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
368cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
369e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                handleScanFinished();
370e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
371e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
372e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
373cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
374e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private void handleScanStarted() {
375e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        mHandler.post(new Runnable() {
376e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
377e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
378e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                mListener.onScanStarted();
379e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
380e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
381e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
382cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
383e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private void handleScanFinished() {
38489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        final int count = mAvailableWifiDisplayPeers.size();
385e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count);
386e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        for (int i = 0; i < count; i++) {
38789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            displays[i] = createWifiDisplay(mAvailableWifiDisplayPeers.get(i));
388e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
389e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
390e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        mHandler.post(new Runnable() {
391e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
392e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
393e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                mListener.onScanFinished(displays);
394cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
395cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        });
396cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
397cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
398cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void connect(final WifiP2pDevice device) {
399cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mDesiredDevice != null
400cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                && !mDesiredDevice.deviceAddress.equals(device.deviceAddress)) {
401cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (DEBUG) {
402cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Slog.d(TAG, "connect: nothing to do, already connecting to "
403cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + describeWifiP2pDevice(device));
404cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
405cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return;
406cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
407cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
408cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mConnectedDevice != null
409cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                && !mConnectedDevice.deviceAddress.equals(device.deviceAddress)
410cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                && mDesiredDevice == null) {
411cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (DEBUG) {
412cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Slog.d(TAG, "connect: nothing to do, already connected to "
413cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + describeWifiP2pDevice(device) + " and not part way through "
414cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + "connecting to a different device.");
415cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
4160cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown            return;
417cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
418cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
419cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mDesiredDevice = device;
4200cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown        mConnectionRetriesLeft = CONNECT_MAX_RETRIES;
421cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        updateConnection();
422cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
423cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
424cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void disconnect() {
425cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mDesiredDevice = null;
426cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        updateConnection();
427cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
428cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
4290cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private void retryConnection() {
43089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        // Cheap hack.  Make a new instance of the device object so that we
43189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        // can distinguish it from the previous connection attempt.
43289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        // This will cause us to tear everything down before we try again.
43389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mDesiredDevice = new WifiP2pDevice(mDesiredDevice);
43489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        updateConnection();
4350cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    }
4360cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
437cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    /**
438cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * This function is called repeatedly after each asynchronous operation
439cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * until all preconditions for the connection have been satisfied and the
440cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * connection is established (or not).
441cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     */
442cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void updateConnection() {
443cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Step 1. Before we try to connect to a new device, tell the system we
444cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // have disconnected from the old one.
445f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        if (mRemoteDisplay != null && mConnectedDevice != mDesiredDevice) {
446f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            Slog.i(TAG, "Stopped listening for RTSP connection on " + mRemoteDisplayInterface
447f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    + " from Wifi display: " + mConnectedDevice.deviceName);
448f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
449f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplay.dispose();
450f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplay = null;
451f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplayInterface = null;
452f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplayConnected = false;
453f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mHandler.removeCallbacks(mRtspTimeout);
454f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
455c9bd4ca005768cb30aaaa44c1171e113c13cd107Jeff Brown            setRemoteSubmixOn(false);
456c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            unadvertiseDisplay();
457cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
458cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            // continue to next step
459cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
460cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
461cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Step 2. Before we try to connect to a new device, disconnect from the old one.
462cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) {
463cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName);
464cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
465c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            unadvertiseDisplay();
466c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
467cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            final WifiP2pDevice oldDevice = mConnectedDevice;
468cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() {
469cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
470cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onSuccess() {
471cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.i(TAG, "Disconnected from Wifi display: " + oldDevice.deviceName);
472cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    next();
473cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
474cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
475cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
476cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onFailure(int reason) {
477cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.i(TAG, "Failed to disconnect from Wifi display: "
478cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            + oldDevice.deviceName + ", reason=" + reason);
479cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    next();
480cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
481cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
482cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                private void next() {
483cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    if (mConnectedDevice == oldDevice) {
484cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        mConnectedDevice = null;
485cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        updateConnection();
486cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
487cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
488cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            });
489cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return; // wait for asynchronous callback
490cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
491cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
492cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Step 3. Before we try to connect to a new device, stop trying to connect
493cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // to the old one.
494cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mConnectingDevice != null && mConnectingDevice != mDesiredDevice) {
495cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Slog.i(TAG, "Canceling connection to Wifi display: " + mConnectingDevice.deviceName);
496cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
497c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            unadvertiseDisplay();
498cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mHandler.removeCallbacks(mConnectionTimeout);
499cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
500cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            final WifiP2pDevice oldDevice = mConnectingDevice;
501cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mWifiP2pManager.cancelConnect(mWifiP2pChannel, new ActionListener() {
502cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
503cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onSuccess() {
504cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.i(TAG, "Canceled connection to Wifi display: " + oldDevice.deviceName);
505cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    next();
506cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
507cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
508cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
509cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onFailure(int reason) {
510cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.i(TAG, "Failed to cancel connection to Wifi display: "
511cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            + oldDevice.deviceName + ", reason=" + reason);
512cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    next();
513cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
514cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
515cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                private void next() {
516cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    if (mConnectingDevice == oldDevice) {
517cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        mConnectingDevice = null;
518cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        updateConnection();
519cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
520cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
521cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            });
522cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return; // wait for asynchronous callback
523cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
524cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
525cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Step 4. If we wanted to disconnect, then mission accomplished.
526cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mDesiredDevice == null) {
527c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            unadvertiseDisplay();
528cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return; // done
529cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
530cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
531cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Step 5. Try to connect.
532cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mConnectedDevice == null && mConnectingDevice == null) {
533cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Slog.i(TAG, "Connecting to Wifi display: " + mDesiredDevice.deviceName);
534cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
535cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mConnectingDevice = mDesiredDevice;
536cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            WifiP2pConfig config = new WifiP2pConfig();
537cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            config.deviceAddress = mConnectingDevice.deviceAddress;
538e0c28d5f1358fc2d4c464f910bd04fed4b283fefIrfan Sheriff            // Helps with STA & P2P concurrency
53999766cf40ed706aad36032f2107fb0c1e54fc398Irfan Sheriff            config.groupOwnerIntent = WifiP2pConfig.MIN_GROUP_OWNER_INTENT;
540cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
541c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            WifiDisplay display = createWifiDisplay(mConnectingDevice);
542c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            advertiseDisplay(display, null, 0, 0, 0);
543e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
544cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            final WifiP2pDevice newDevice = mDesiredDevice;
545cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mWifiP2pManager.connect(mWifiP2pChannel, config, new ActionListener() {
546cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
547cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onSuccess() {
548cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    // The connection may not yet be established.  We still need to wait
549cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    // for WIFI_P2P_CONNECTION_CHANGED_ACTION.  However, we might never
550cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    // get that broadcast, so we register a timeout.
551cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.i(TAG, "Initiated connection to Wifi display: " + newDevice.deviceName);
552cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
553cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    mHandler.postDelayed(mConnectionTimeout, CONNECTION_TIMEOUT_SECONDS * 1000);
554cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
555cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
556cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
557cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                public void onFailure(int reason) {
558cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    if (mConnectingDevice == newDevice) {
559f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        Slog.i(TAG, "Failed to initiate connection to Wifi display: "
560f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                                + newDevice.deviceName + ", reason=" + reason);
561cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        mConnectingDevice = null;
5620cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                        handleConnectionFailure(false);
563cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
564cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
565cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            });
566cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return; // wait for asynchronous callback
567cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
568cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
569f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        // Step 6. Listen for incoming connections.
570f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        if (mConnectedDevice != null && mRemoteDisplay == null) {
571cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Inet4Address addr = getInterfaceAddress(mConnectedDeviceGroupInfo);
572cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (addr == null) {
573cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Slog.i(TAG, "Failed to get local interface address for communicating "
574cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + "with Wifi display: " + mConnectedDevice.deviceName);
5750cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                handleConnectionFailure(false);
576cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                return; // done
577cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
578cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
579c9bd4ca005768cb30aaaa44c1171e113c13cd107Jeff Brown            setRemoteSubmixOn(true);
580c9bd4ca005768cb30aaaa44c1171e113c13cd107Jeff Brown
581f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            final WifiP2pDevice oldDevice = mConnectedDevice;
5820f68d166e6ca45fe27410ea520967275e0733757Jeff Brown            final int port = getPortNumber(mConnectedDevice);
583cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            final String iface = addr.getHostAddress() + ":" + port;
584f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplayInterface = iface;
585cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
586f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            Slog.i(TAG, "Listening for RTSP connection on " + iface
587f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    + " from Wifi display: " + mConnectedDevice.deviceName);
588f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
589f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mRemoteDisplay = RemoteDisplay.listen(iface, new RemoteDisplay.Listener() {
590cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                @Override
591c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                public void onDisplayConnected(Surface surface,
592c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        int width, int height, int flags) {
593f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    if (mConnectedDevice == oldDevice && !mRemoteDisplayConnected) {
594f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        Slog.i(TAG, "Opened RTSP connection with Wifi display: "
595f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                                + mConnectedDevice.deviceName);
596f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        mRemoteDisplayConnected = true;
597f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        mHandler.removeCallbacks(mRtspTimeout);
598f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
599f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        final WifiDisplay display = createWifiDisplay(mConnectedDevice);
600c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        advertiseDisplay(display, surface, width, height, flags);
601f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    }
602cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
603f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
604f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                @Override
605f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                public void onDisplayDisconnected() {
606f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    if (mConnectedDevice == oldDevice) {
607f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        Slog.i(TAG, "Closed RTSP connection with Wifi display: "
608f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                                + mConnectedDevice.deviceName);
609f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        mHandler.removeCallbacks(mRtspTimeout);
610f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        disconnect();
611f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    }
612f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                }
613f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
614f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                @Override
615f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                public void onDisplayError(int error) {
616f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    if (mConnectedDevice == oldDevice) {
617f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        Slog.i(TAG, "Lost RTSP connection with Wifi display due to error "
618f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                                + error + ": " + mConnectedDevice.deviceName);
619f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        mHandler.removeCallbacks(mRtspTimeout);
620f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        handleConnectionFailure(false);
621f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    }
622f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                }
623f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            }, mHandler);
624f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
625f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mHandler.postDelayed(mRtspTimeout, RTSP_TIMEOUT_SECONDS * 1000);
626cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
627cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
628cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
629c9bd4ca005768cb30aaaa44c1171e113c13cd107Jeff Brown    private void setRemoteSubmixOn(boolean on) {
630c9bd4ca005768cb30aaaa44c1171e113c13cd107Jeff Brown        if (mRemoteSubmixOn != on) {
631c9bd4ca005768cb30aaaa44c1171e113c13cd107Jeff Brown            mRemoteSubmixOn = on;
632c9bd4ca005768cb30aaaa44c1171e113c13cd107Jeff Brown            mAudioManager.setRemoteSubmixOn(on, REMOTE_SUBMIX_ADDRESS);
633c9bd4ca005768cb30aaaa44c1171e113c13cd107Jeff Brown        }
634c9bd4ca005768cb30aaaa44c1171e113c13cd107Jeff Brown    }
635c9bd4ca005768cb30aaaa44c1171e113c13cd107Jeff Brown
636cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void handleStateChanged(boolean enabled) {
63789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mWifiP2pEnabled = enabled;
63889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        updateWfdEnableState();
639cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
640cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
641cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void handlePeersChanged() {
64256925d65fde7f1ac8676ada6f91d0e604645c0a5Irfan Sheriff        // Even if wfd is disabled, it is best to get the latest set of peers to
64356925d65fde7f1ac8676ada6f91d0e604645c0a5Irfan Sheriff        // keep in sync with the p2p framework
64456925d65fde7f1ac8676ada6f91d0e604645c0a5Irfan Sheriff        requestPeers();
645cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
646cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
647cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void handleConnectionChanged(NetworkInfo networkInfo) {
648cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mNetworkInfo = networkInfo;
649180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        if (mWfdEnabled && networkInfo.isConnected()) {
650cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (mDesiredDevice != null) {
651cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mWifiP2pManager.requestGroupInfo(mWifiP2pChannel, new GroupInfoListener() {
652cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    @Override
653cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    public void onGroupInfoAvailable(WifiP2pGroup info) {
654cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        if (DEBUG) {
655cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            Slog.d(TAG, "Received group info: " + describeWifiP2pGroup(info));
656cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        }
657cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
658cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        if (mConnectingDevice != null && !info.contains(mConnectingDevice)) {
659cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            Slog.i(TAG, "Aborting connection to Wifi display because "
660cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                                    + "the current P2P group does not contain the device "
66189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                                    + "we expected to find: " + mConnectingDevice.deviceName
66289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                                    + ", group info was: " + describeWifiP2pGroup(info));
6630cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                            handleConnectionFailure(false);
664cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            return;
665cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        }
666cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
667cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        if (mDesiredDevice != null && !info.contains(mDesiredDevice)) {
668cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            disconnect();
669cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            return;
670cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        }
671cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
672cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) {
6730cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                            Slog.i(TAG, "Connected to Wifi display: "
6740cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                                    + mConnectingDevice.deviceName);
675cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
676cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            mHandler.removeCallbacks(mConnectionTimeout);
677cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            mConnectedDeviceGroupInfo = info;
678cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            mConnectedDevice = mConnectingDevice;
679cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            mConnectingDevice = null;
680cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            updateConnection();
681cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        }
682cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    }
683cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                });
684cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
685cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        } else {
686cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            disconnect();
687180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown
688180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown            // After disconnection for a group, for some reason we have a tendency
689180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown            // to get a peer change notification with an empty list of peers.
690180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown            // Perform a fresh scan.
691180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown            if (mWfdEnabled) {
692180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                requestPeers();
693180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown            }
694cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
695cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
696cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
697cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final Runnable mConnectionTimeout = new Runnable() {
698cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
699cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void run() {
700cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) {
701cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Slog.i(TAG, "Timed out waiting for Wifi display connection after "
702cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + CONNECTION_TIMEOUT_SECONDS + " seconds: "
703cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        + mConnectingDevice.deviceName);
7040cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                handleConnectionFailure(true);
705cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
706cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
707cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    };
708cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
709f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private final Runnable mRtspTimeout = new Runnable() {
710f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        @Override
711f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        public void run() {
712f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            if (mConnectedDevice != null
713f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                    && mRemoteDisplay != null && !mRemoteDisplayConnected) {
714f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                Slog.i(TAG, "Timed out waiting for Wifi display RTSP connection after "
715f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        + RTSP_TIMEOUT_SECONDS + " seconds: "
716f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                        + mConnectedDevice.deviceName);
717f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                handleConnectionFailure(true);
718f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            }
719f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        }
720f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    };
721f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
7220cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown    private void handleConnectionFailure(boolean timeoutOccurred) {
723f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        Slog.i(TAG, "Wifi display connection failed!");
7240cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown
725f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        if (mDesiredDevice != null) {
7260cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown            if (mConnectionRetriesLeft > 0) {
72789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                final WifiP2pDevice oldDevice = mDesiredDevice;
7280cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                mHandler.postDelayed(new Runnable() {
7290cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                    @Override
7300cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                    public void run() {
73189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        if (mDesiredDevice == oldDevice && mConnectionRetriesLeft > 0) {
73289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            mConnectionRetriesLeft -= 1;
73389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            Slog.i(TAG, "Retrying Wifi display connection.  Retries left: "
73489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                                    + mConnectionRetriesLeft);
73589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                            retryConnection();
73689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        }
7370cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                    }
7380cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                }, timeoutOccurred ? 0 : CONNECT_RETRY_DELAY_MILLIS);
7390cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown            } else {
7400cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown                disconnect();
7410cfebf28b15e85a42981a8f9e6a09556bef36ea3Jeff Brown            }
742cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
743cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
744cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
745c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private void advertiseDisplay(final WifiDisplay display,
746c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            final Surface surface, final int width, final int height, final int flags) {
747c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        if (!Objects.equal(mAdvertisedDisplay, display)
748c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                || mAdvertisedDisplaySurface != surface
749c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                || mAdvertisedDisplayWidth != width
750c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                || mAdvertisedDisplayHeight != height
751c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                || mAdvertisedDisplayFlags != flags) {
752c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            final WifiDisplay oldDisplay = mAdvertisedDisplay;
753c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            final Surface oldSurface = mAdvertisedDisplaySurface;
754c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
755c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mAdvertisedDisplay = display;
756c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mAdvertisedDisplaySurface = surface;
757c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mAdvertisedDisplayWidth = width;
758c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mAdvertisedDisplayHeight = height;
759c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mAdvertisedDisplayFlags = flags;
760c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
761c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            mHandler.post(new Runnable() {
762c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                @Override
763c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                public void run() {
764c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                    if (oldSurface != null && surface != oldSurface) {
765c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        mListener.onDisplayDisconnected();
766c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                    } else if (oldDisplay != null && !Objects.equal(display, oldDisplay)) {
767c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        mListener.onDisplayConnectionFailed();
768c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                    }
769c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
770c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                    if (display != null) {
771c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        if (!Objects.equal(display, oldDisplay)) {
772c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                            mListener.onDisplayConnecting(display);
773c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        }
774c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        if (surface != null && surface != oldSurface) {
775c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                            mListener.onDisplayConnected(display, surface, width, height, flags);
776c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                        }
777c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                    }
778c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown                }
779c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown            });
780c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        }
781c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    }
782c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
783c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    private void unadvertiseDisplay() {
784c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown        advertiseDisplay(null, null, 0, 0, 0);
785c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown    }
786c2b9ea624148df80945afad4198fe686a0ab8dcaJeff Brown
787cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static Inet4Address getInterfaceAddress(WifiP2pGroup info) {
788cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        NetworkInterface iface;
789cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        try {
790cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            iface = NetworkInterface.getByName(info.getInterface());
791cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        } catch (SocketException ex) {
792cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Slog.w(TAG, "Could not obtain address of network interface "
793cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    + info.getInterface(), ex);
794cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return null;
795cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
796cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
797cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        Enumeration<InetAddress> addrs = iface.getInetAddresses();
798cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        while (addrs.hasMoreElements()) {
799cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            InetAddress addr = addrs.nextElement();
800cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (addr instanceof Inet4Address) {
801cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                return (Inet4Address)addr;
802cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
803cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
804cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
805cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        Slog.w(TAG, "Could not obtain address of network interface "
806cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                + info.getInterface() + " because it had no IPv4 addresses.");
807cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        return null;
808cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
809cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
8100f68d166e6ca45fe27410ea520967275e0733757Jeff Brown    private static int getPortNumber(WifiP2pDevice device) {
8110f68d166e6ca45fe27410ea520967275e0733757Jeff Brown        if (device.deviceName.startsWith("DIRECT-")
8120f68d166e6ca45fe27410ea520967275e0733757Jeff Brown                && device.deviceName.endsWith("Broadcom")) {
8130f68d166e6ca45fe27410ea520967275e0733757Jeff Brown            // These dongles ignore the port we broadcast in our WFD IE.
8140f68d166e6ca45fe27410ea520967275e0733757Jeff Brown            return 8554;
8150f68d166e6ca45fe27410ea520967275e0733757Jeff Brown        }
8160f68d166e6ca45fe27410ea520967275e0733757Jeff Brown        return DEFAULT_CONTROL_PORT;
8170f68d166e6ca45fe27410ea520967275e0733757Jeff Brown    }
8180f68d166e6ca45fe27410ea520967275e0733757Jeff Brown
819cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static boolean isWifiDisplay(WifiP2pDevice device) {
8200f68d166e6ca45fe27410ea520967275e0733757Jeff Brown        return device.wfdInfo != null
8210f68d166e6ca45fe27410ea520967275e0733757Jeff Brown                && device.wfdInfo.isWfdEnabled()
8220f68d166e6ca45fe27410ea520967275e0733757Jeff Brown                && isPrimarySinkDeviceType(device.wfdInfo.getDeviceType());
8230f68d166e6ca45fe27410ea520967275e0733757Jeff Brown    }
8240f68d166e6ca45fe27410ea520967275e0733757Jeff Brown
8250f68d166e6ca45fe27410ea520967275e0733757Jeff Brown    private static boolean isPrimarySinkDeviceType(int deviceType) {
8260f68d166e6ca45fe27410ea520967275e0733757Jeff Brown        return deviceType == WifiP2pWfdInfo.PRIMARY_SINK
8270f68d166e6ca45fe27410ea520967275e0733757Jeff Brown                || deviceType == WifiP2pWfdInfo.SOURCE_OR_PRIMARY_SINK;
828cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
829cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
830cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static String describeWifiP2pDevice(WifiP2pDevice device) {
831cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        return device != null ? device.toString().replace('\n', ',') : "null";
832cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
833cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
834cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static String describeWifiP2pGroup(WifiP2pGroup group) {
835cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        return group != null ? group.toString().replace('\n', ',') : "null";
836cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
837cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
838e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private static WifiDisplay createWifiDisplay(WifiP2pDevice device) {
83989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        return new WifiDisplay(device.deviceAddress, device.deviceName, null);
840e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
841e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
842cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final BroadcastReceiver mWifiP2pReceiver = new BroadcastReceiver() {
843cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
844cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void onReceive(Context context, Intent intent) {
845cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            final String action = intent.getAction();
846cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) {
84789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                // This broadcast is sticky so we'll always get the initial Wifi P2P state
84889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                // on startup.
849cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                boolean enabled = (intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE,
850cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        WifiP2pManager.WIFI_P2P_STATE_DISABLED)) ==
851cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        WifiP2pManager.WIFI_P2P_STATE_ENABLED;
852cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
853cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Received WIFI_P2P_STATE_CHANGED_ACTION: enabled="
854cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            + enabled);
855cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
856cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
857cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                handleStateChanged(enabled);
858cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            } else if (action.equals(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)) {
859cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
860cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Received WIFI_P2P_PEERS_CHANGED_ACTION.");
861cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
862cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
863cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                handlePeersChanged();
864cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) {
865cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra(
866cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        WifiP2pManager.EXTRA_NETWORK_INFO);
867cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (DEBUG) {
868cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    Slog.d(TAG, "Received WIFI_P2P_CONNECTION_CHANGED_ACTION: networkInfo="
869cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                            + networkInfo);
870cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
871cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
872cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                handleConnectionChanged(networkInfo);
873cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
874cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
875cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    };
876cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
877cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    /**
878cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * Called on the handler thread when displays are connected or disconnected.
879cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     */
880cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public interface Listener {
88189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        void onFeatureStateChanged(int featureState);
882e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
883e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        void onScanStarted();
88489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        void onScanFinished(WifiDisplay[] availableDisplays);
885e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
886e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        void onDisplayConnecting(WifiDisplay display);
887e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        void onDisplayConnectionFailed();
888f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        void onDisplayConnected(WifiDisplay display,
889f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                Surface surface, int width, int height, int flags);
890cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        void onDisplayDisconnected();
891cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
892cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown}
893