WifiDisplayController.java revision 59c53c6224e2f84d31a56854ebe90d22055100d2
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.display; 18 19import com.android.internal.util.DumpUtils; 20 21import android.content.BroadcastReceiver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.IntentFilter; 25import android.hardware.display.WifiDisplay; 26import android.net.NetworkInfo; 27import android.net.wifi.p2p.WifiP2pConfig; 28import android.net.wifi.p2p.WifiP2pDevice; 29import android.net.wifi.p2p.WifiP2pDeviceList; 30import android.net.wifi.p2p.WifiP2pGroup; 31import android.net.wifi.p2p.WifiP2pManager; 32import android.net.wifi.p2p.WifiP2pWfdInfo; 33import android.net.wifi.p2p.WifiP2pManager.ActionListener; 34import android.net.wifi.p2p.WifiP2pManager.Channel; 35import android.net.wifi.p2p.WifiP2pManager.GroupInfoListener; 36import android.net.wifi.p2p.WifiP2pManager.PeerListListener; 37import android.os.Handler; 38import android.util.Slog; 39 40import java.io.PrintWriter; 41import java.net.Inet4Address; 42import java.net.InetAddress; 43import java.net.NetworkInterface; 44import java.net.SocketException; 45import java.util.ArrayList; 46import java.util.Enumeration; 47 48/** 49 * Manages all of the various asynchronous interactions with the {@link WifiP2pManager} 50 * on behalf of {@link WifiDisplayAdapter}. 51 * <p> 52 * This code is isolated from {@link WifiDisplayAdapter} so that we can avoid 53 * accidentally introducing any deadlocks due to the display manager calling 54 * outside of itself while holding its lock. It's also way easier to write this 55 * asynchronous code if we can assume that it is single-threaded. 56 * </p><p> 57 * The controller must be instantiated on the handler thread. 58 * </p> 59 */ 60final class WifiDisplayController implements DumpUtils.Dump { 61 private static final String TAG = "WifiDisplayController"; 62 private static final boolean DEBUG = true; 63 64 private static final int DEFAULT_CONTROL_PORT = 7236; 65 private static final int MAX_THROUGHPUT = 50; 66 private static final int CONNECTION_TIMEOUT_SECONDS = 30; 67 68 private static final int DISCOVER_PEERS_MAX_RETRIES = 10; 69 private static final int DISCOVER_PEERS_RETRY_DELAY_MILLIS = 500; 70 71 private static final int CONNECT_MAX_RETRIES = 3; 72 private static final int CONNECT_RETRY_DELAY_MILLIS = 500; 73 74 private final Context mContext; 75 private final Handler mHandler; 76 private final Listener mListener; 77 private final WifiP2pManager mWifiP2pManager; 78 private final Channel mWifiP2pChannel; 79 80 private boolean mWifiP2pEnabled; 81 private boolean mWfdEnabled; 82 private boolean mWfdEnabling; 83 private NetworkInfo mNetworkInfo; 84 85 private final ArrayList<WifiP2pDevice> mKnownWifiDisplayPeers = 86 new ArrayList<WifiP2pDevice>(); 87 88 // True if there is a call to discoverPeers in progress. 89 private boolean mDiscoverPeersInProgress; 90 91 // Number of discover peers retries remaining. 92 private int mDiscoverPeersRetriesLeft; 93 94 // The device to which we want to connect, or null if we want to be disconnected. 95 private WifiP2pDevice mDesiredDevice; 96 97 // The device to which we are currently connecting, or null if we have already connected 98 // or are not trying to connect. 99 private WifiP2pDevice mConnectingDevice; 100 101 // The device to which we are currently connected, which means we have an active P2P group. 102 private WifiP2pDevice mConnectedDevice; 103 104 // The group info obtained after connecting. 105 private WifiP2pGroup mConnectedDeviceGroupInfo; 106 107 // The device that we announced to the rest of the system. 108 private WifiP2pDevice mPublishedDevice; 109 110 // Number of connection retries remaining. 111 private int mConnectionRetriesLeft; 112 113 public WifiDisplayController(Context context, Handler handler, Listener listener) { 114 mContext = context; 115 mHandler = handler; 116 mListener = listener; 117 118 mWifiP2pManager = (WifiP2pManager)context.getSystemService(Context.WIFI_P2P_SERVICE); 119 mWifiP2pChannel = mWifiP2pManager.initialize(context, handler.getLooper(), null); 120 121 IntentFilter intentFilter = new IntentFilter(); 122 intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); 123 intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); 124 intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); 125 context.registerReceiver(mWifiP2pReceiver, intentFilter); 126 } 127 128 public void dump(PrintWriter pw) { 129 pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled); 130 pw.println("mWfdEnabled=" + mWfdEnabled); 131 pw.println("mWfdEnabling=" + mWfdEnabling); 132 pw.println("mNetworkInfo=" + mNetworkInfo); 133 pw.println("mDiscoverPeersInProgress=" + mDiscoverPeersInProgress); 134 pw.println("mDiscoverPeersRetriesLeft=" + mDiscoverPeersRetriesLeft); 135 pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice)); 136 pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice)); 137 pw.println("mConnectedDevice=" + describeWifiP2pDevice(mConnectedDevice)); 138 pw.println("mPublishedDevice=" + describeWifiP2pDevice(mPublishedDevice)); 139 pw.println("mConnectionRetriesLeft=" + mConnectionRetriesLeft); 140 141 pw.println("mKnownWifiDisplayPeers: size=" + mKnownWifiDisplayPeers.size()); 142 for (WifiP2pDevice device : mKnownWifiDisplayPeers) { 143 pw.println(" " + describeWifiP2pDevice(device)); 144 } 145 } 146 147 public void requestScan() { 148 discoverPeers(); 149 } 150 151 public void requestConnect(String address) { 152 for (WifiP2pDevice device : mKnownWifiDisplayPeers) { 153 if (device.deviceAddress.equals(address)) { 154 connect(device); 155 } 156 } 157 } 158 159 public void requestDisconnect() { 160 disconnect(); 161 } 162 163 private void enableWfd() { 164 if (!mWfdEnabled && !mWfdEnabling) { 165 mWfdEnabling = true; 166 167 WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo(); 168 wfdInfo.setWfdEnabled(true); 169 wfdInfo.setDeviceType(WifiP2pWfdInfo.WFD_SOURCE); 170 wfdInfo.setSessionAvailable(true); 171 wfdInfo.setControlPort(DEFAULT_CONTROL_PORT); 172 wfdInfo.setMaxThroughput(MAX_THROUGHPUT); 173 mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() { 174 @Override 175 public void onSuccess() { 176 if (DEBUG) { 177 Slog.d(TAG, "Successfully set WFD info."); 178 } 179 if (mWfdEnabling) { 180 mWfdEnabling = false; 181 setWfdEnabled(true); 182 } 183 } 184 185 @Override 186 public void onFailure(int reason) { 187 if (DEBUG) { 188 Slog.d(TAG, "Failed to set WFD info with reason " + reason + "."); 189 } 190 mWfdEnabling = false; 191 } 192 }); 193 } 194 } 195 196 private void setWfdEnabled(final boolean enabled) { 197 if (mWfdEnabled != enabled) { 198 mWfdEnabled = enabled; 199 mHandler.post(new Runnable() { 200 @Override 201 public void run() { 202 mListener.onEnablementChanged(enabled); 203 } 204 }); 205 } 206 } 207 208 private void discoverPeers() { 209 if (!mDiscoverPeersInProgress) { 210 mDiscoverPeersInProgress = true; 211 mDiscoverPeersRetriesLeft = DISCOVER_PEERS_MAX_RETRIES; 212 handleScanStarted(); 213 tryDiscoverPeers(); 214 } 215 } 216 217 private void tryDiscoverPeers() { 218 mWifiP2pManager.discoverPeers(mWifiP2pChannel, new ActionListener() { 219 @Override 220 public void onSuccess() { 221 if (DEBUG) { 222 Slog.d(TAG, "Discover peers succeeded. Requesting peers now."); 223 } 224 225 mDiscoverPeersInProgress = false; 226 requestPeers(); 227 } 228 229 @Override 230 public void onFailure(int reason) { 231 if (DEBUG) { 232 Slog.d(TAG, "Discover peers failed with reason " + reason + "."); 233 } 234 235 if (mDiscoverPeersInProgress) { 236 if (reason == 0 && mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) { 237 mHandler.postDelayed(new Runnable() { 238 @Override 239 public void run() { 240 if (mDiscoverPeersInProgress) { 241 if (mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) { 242 mDiscoverPeersRetriesLeft -= 1; 243 if (DEBUG) { 244 Slog.d(TAG, "Retrying discovery. Retries left: " 245 + mDiscoverPeersRetriesLeft); 246 } 247 tryDiscoverPeers(); 248 } else { 249 handleScanFinished(); 250 mDiscoverPeersInProgress = false; 251 } 252 } 253 } 254 }, DISCOVER_PEERS_RETRY_DELAY_MILLIS); 255 } else { 256 handleScanFinished(); 257 mDiscoverPeersInProgress = false; 258 } 259 } 260 } 261 }); 262 } 263 264 private void requestPeers() { 265 mWifiP2pManager.requestPeers(mWifiP2pChannel, new PeerListListener() { 266 @Override 267 public void onPeersAvailable(WifiP2pDeviceList peers) { 268 if (DEBUG) { 269 Slog.d(TAG, "Received list of peers."); 270 } 271 272 mKnownWifiDisplayPeers.clear(); 273 for (WifiP2pDevice device : peers.getDeviceList()) { 274 if (DEBUG) { 275 Slog.d(TAG, " " + describeWifiP2pDevice(device)); 276 } 277 278 if (isWifiDisplay(device)) { 279 mKnownWifiDisplayPeers.add(device); 280 } 281 } 282 283 handleScanFinished(); 284 } 285 }); 286 } 287 288 private void handleScanStarted() { 289 mHandler.post(new Runnable() { 290 @Override 291 public void run() { 292 mListener.onScanStarted(); 293 } 294 }); 295 } 296 297 private void handleScanFinished() { 298 final int count = mKnownWifiDisplayPeers.size(); 299 final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count); 300 for (int i = 0; i < count; i++) { 301 displays[i] = createWifiDisplay(mKnownWifiDisplayPeers.get(i)); 302 } 303 304 mHandler.post(new Runnable() { 305 @Override 306 public void run() { 307 mListener.onScanFinished(displays); 308 } 309 }); 310 } 311 312 private void connect(final WifiP2pDevice device) { 313 if (mDesiredDevice != null 314 && !mDesiredDevice.deviceAddress.equals(device.deviceAddress)) { 315 if (DEBUG) { 316 Slog.d(TAG, "connect: nothing to do, already connecting to " 317 + describeWifiP2pDevice(device)); 318 } 319 return; 320 } 321 322 if (mConnectedDevice != null 323 && !mConnectedDevice.deviceAddress.equals(device.deviceAddress) 324 && mDesiredDevice == null) { 325 if (DEBUG) { 326 Slog.d(TAG, "connect: nothing to do, already connected to " 327 + describeWifiP2pDevice(device) + " and not part way through " 328 + "connecting to a different device."); 329 } 330 return; 331 } 332 333 mDesiredDevice = device; 334 mConnectionRetriesLeft = CONNECT_MAX_RETRIES; 335 updateConnection(); 336 } 337 338 private void disconnect() { 339 mDesiredDevice = null; 340 updateConnection(); 341 } 342 343 private void retryConnection() { 344 if (mDesiredDevice != null && mPublishedDevice != mDesiredDevice 345 && mConnectionRetriesLeft > 0) { 346 mConnectionRetriesLeft -= 1; 347 Slog.i(TAG, "Retrying Wifi display connection. Retries left: " 348 + mConnectionRetriesLeft); 349 350 // Cheap hack. Make a new instance of the device object so that we 351 // can distinguish it from the previous connection attempt. 352 // This will cause us to tear everything down before we try again. 353 mDesiredDevice = new WifiP2pDevice(mDesiredDevice); 354 updateConnection(); 355 } 356 } 357 358 /** 359 * This function is called repeatedly after each asynchronous operation 360 * until all preconditions for the connection have been satisfied and the 361 * connection is established (or not). 362 */ 363 private void updateConnection() { 364 // Step 1. Before we try to connect to a new device, tell the system we 365 // have disconnected from the old one. 366 if (mPublishedDevice != null && mPublishedDevice != mDesiredDevice) { 367 mHandler.post(new Runnable() { 368 @Override 369 public void run() { 370 mListener.onDisplayDisconnected(); 371 } 372 }); 373 mPublishedDevice = null; 374 375 // continue to next step 376 } 377 378 // Step 2. Before we try to connect to a new device, disconnect from the old one. 379 if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) { 380 Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName); 381 382 final WifiP2pDevice oldDevice = mConnectedDevice; 383 mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() { 384 @Override 385 public void onSuccess() { 386 Slog.i(TAG, "Disconnected from Wifi display: " + oldDevice.deviceName); 387 next(); 388 } 389 390 @Override 391 public void onFailure(int reason) { 392 Slog.i(TAG, "Failed to disconnect from Wifi display: " 393 + oldDevice.deviceName + ", reason=" + reason); 394 next(); 395 } 396 397 private void next() { 398 if (mConnectedDevice == oldDevice) { 399 mConnectedDevice = null; 400 updateConnection(); 401 } 402 } 403 }); 404 return; // wait for asynchronous callback 405 } 406 407 // Step 3. Before we try to connect to a new device, stop trying to connect 408 // to the old one. 409 if (mConnectingDevice != null && mConnectingDevice != mDesiredDevice) { 410 Slog.i(TAG, "Canceling connection to Wifi display: " + mConnectingDevice.deviceName); 411 412 mHandler.removeCallbacks(mConnectionTimeout); 413 414 final WifiP2pDevice oldDevice = mConnectingDevice; 415 mWifiP2pManager.cancelConnect(mWifiP2pChannel, new ActionListener() { 416 @Override 417 public void onSuccess() { 418 Slog.i(TAG, "Canceled connection to Wifi display: " + oldDevice.deviceName); 419 next(); 420 } 421 422 @Override 423 public void onFailure(int reason) { 424 Slog.i(TAG, "Failed to cancel connection to Wifi display: " 425 + oldDevice.deviceName + ", reason=" + reason); 426 next(); 427 } 428 429 private void next() { 430 if (mConnectingDevice == oldDevice) { 431 mConnectingDevice = null; 432 updateConnection(); 433 } 434 } 435 }); 436 return; // wait for asynchronous callback 437 } 438 439 // Step 4. If we wanted to disconnect, then mission accomplished. 440 if (mDesiredDevice == null) { 441 return; // done 442 } 443 444 // Step 5. Try to connect. 445 if (mConnectedDevice == null && mConnectingDevice == null) { 446 Slog.i(TAG, "Connecting to Wifi display: " + mDesiredDevice.deviceName); 447 448 mConnectingDevice = mDesiredDevice; 449 WifiP2pConfig config = new WifiP2pConfig(); 450 config.deviceAddress = mConnectingDevice.deviceAddress; 451 452 final WifiDisplay display = createWifiDisplay(mConnectingDevice); 453 mHandler.post(new Runnable() { 454 @Override 455 public void run() { 456 mListener.onDisplayConnecting(display); 457 } 458 }); 459 460 final WifiP2pDevice newDevice = mDesiredDevice; 461 mWifiP2pManager.connect(mWifiP2pChannel, config, new ActionListener() { 462 @Override 463 public void onSuccess() { 464 // The connection may not yet be established. We still need to wait 465 // for WIFI_P2P_CONNECTION_CHANGED_ACTION. However, we might never 466 // get that broadcast, so we register a timeout. 467 Slog.i(TAG, "Initiated connection to Wifi display: " + newDevice.deviceName); 468 469 mHandler.postDelayed(mConnectionTimeout, CONNECTION_TIMEOUT_SECONDS * 1000); 470 } 471 472 @Override 473 public void onFailure(int reason) { 474 Slog.i(TAG, "Failed to initiate connection to Wifi display: " 475 + newDevice.deviceName + ", reason=" + reason); 476 if (mConnectingDevice == newDevice) { 477 mConnectingDevice = null; 478 handleConnectionFailure(false); 479 } 480 } 481 }); 482 return; // wait for asynchronous callback 483 } 484 485 // Step 6. Publish the new connection. 486 if (mConnectedDevice != null && mPublishedDevice == null) { 487 Inet4Address addr = getInterfaceAddress(mConnectedDeviceGroupInfo); 488 if (addr == null) { 489 Slog.i(TAG, "Failed to get local interface address for communicating " 490 + "with Wifi display: " + mConnectedDevice.deviceName); 491 handleConnectionFailure(false); 492 return; // done 493 } 494 495 final WifiDisplay display = createWifiDisplay(mConnectedDevice); 496 final int port = getPortNumber(mConnectedDevice); 497 final String iface = addr.getHostAddress() + ":" + port; 498 499 mPublishedDevice = mConnectedDevice; 500 mHandler.post(new Runnable() { 501 @Override 502 public void run() { 503 mListener.onDisplayConnected(display, iface); 504 } 505 }); 506 } 507 } 508 509 private void handleStateChanged(boolean enabled) { 510 if (mWifiP2pEnabled != enabled) { 511 mWifiP2pEnabled = enabled; 512 if (enabled) { 513 if (!mWfdEnabled) { 514 enableWfd(); 515 } 516 } else { 517 setWfdEnabled(false); 518 disconnect(); 519 } 520 } 521 } 522 523 private void handlePeersChanged() { 524 if (mWifiP2pEnabled) { 525 if (mWfdEnabled) { 526 requestPeers(); 527 } else { 528 enableWfd(); 529 } 530 } 531 } 532 533 private void handleConnectionChanged(NetworkInfo networkInfo) { 534 mNetworkInfo = networkInfo; 535 if (mWfdEnabled && networkInfo.isConnected()) { 536 if (mDesiredDevice != null) { 537 mWifiP2pManager.requestGroupInfo(mWifiP2pChannel, new GroupInfoListener() { 538 @Override 539 public void onGroupInfoAvailable(WifiP2pGroup info) { 540 if (DEBUG) { 541 Slog.d(TAG, "Received group info: " + describeWifiP2pGroup(info)); 542 } 543 544 if (mConnectingDevice != null && !info.contains(mConnectingDevice)) { 545 Slog.i(TAG, "Aborting connection to Wifi display because " 546 + "the current P2P group does not contain the device " 547 + "we expected to find: " + mConnectingDevice.deviceName); 548 handleConnectionFailure(false); 549 return; 550 } 551 552 if (mDesiredDevice != null && !info.contains(mDesiredDevice)) { 553 disconnect(); 554 return; 555 } 556 557 if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) { 558 Slog.i(TAG, "Connected to Wifi display: " 559 + mConnectingDevice.deviceName); 560 561 mHandler.removeCallbacks(mConnectionTimeout); 562 mConnectedDeviceGroupInfo = info; 563 mConnectedDevice = mConnectingDevice; 564 mConnectingDevice = null; 565 updateConnection(); 566 } 567 } 568 }); 569 } 570 } else { 571 disconnect(); 572 573 // After disconnection for a group, for some reason we have a tendency 574 // to get a peer change notification with an empty list of peers. 575 // Perform a fresh scan. 576 if (mWfdEnabled) { 577 requestPeers(); 578 } 579 } 580 } 581 582 private final Runnable mConnectionTimeout = new Runnable() { 583 @Override 584 public void run() { 585 if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) { 586 Slog.i(TAG, "Timed out waiting for Wifi display connection after " 587 + CONNECTION_TIMEOUT_SECONDS + " seconds: " 588 + mConnectingDevice.deviceName); 589 handleConnectionFailure(true); 590 } 591 } 592 }; 593 594 private void handleConnectionFailure(boolean timeoutOccurred) { 595 if (mDesiredDevice != null) { 596 Slog.i(TAG, "Wifi display connection failed!"); 597 598 mHandler.post(new Runnable() { 599 @Override 600 public void run() { 601 mListener.onDisplayConnectionFailed(); 602 } 603 }); 604 605 if (mConnectionRetriesLeft > 0) { 606 mHandler.postDelayed(new Runnable() { 607 @Override 608 public void run() { 609 retryConnection(); 610 } 611 }, timeoutOccurred ? 0 : CONNECT_RETRY_DELAY_MILLIS); 612 } else { 613 disconnect(); 614 } 615 } 616 } 617 618 private static Inet4Address getInterfaceAddress(WifiP2pGroup info) { 619 NetworkInterface iface; 620 try { 621 iface = NetworkInterface.getByName(info.getInterface()); 622 } catch (SocketException ex) { 623 Slog.w(TAG, "Could not obtain address of network interface " 624 + info.getInterface(), ex); 625 return null; 626 } 627 628 Enumeration<InetAddress> addrs = iface.getInetAddresses(); 629 while (addrs.hasMoreElements()) { 630 InetAddress addr = addrs.nextElement(); 631 if (addr instanceof Inet4Address) { 632 return (Inet4Address)addr; 633 } 634 } 635 636 Slog.w(TAG, "Could not obtain address of network interface " 637 + info.getInterface() + " because it had no IPv4 addresses."); 638 return null; 639 } 640 641 private static int getPortNumber(WifiP2pDevice device) { 642 if (device.deviceName.startsWith("DIRECT-") 643 && device.deviceName.endsWith("Broadcom")) { 644 // These dongles ignore the port we broadcast in our WFD IE. 645 return 8554; 646 } 647 return DEFAULT_CONTROL_PORT; 648 } 649 650 private static boolean isWifiDisplay(WifiP2pDevice device) { 651 return device.wfdInfo != null 652 && device.wfdInfo.isWfdEnabled() 653 && isPrimarySinkDeviceType(device.wfdInfo.getDeviceType()); 654 } 655 656 private static boolean isPrimarySinkDeviceType(int deviceType) { 657 return deviceType == WifiP2pWfdInfo.PRIMARY_SINK 658 || deviceType == WifiP2pWfdInfo.SOURCE_OR_PRIMARY_SINK; 659 } 660 661 private static String describeWifiP2pDevice(WifiP2pDevice device) { 662 return device != null ? device.toString().replace('\n', ',') : "null"; 663 } 664 665 private static String describeWifiP2pGroup(WifiP2pGroup group) { 666 return group != null ? group.toString().replace('\n', ',') : "null"; 667 } 668 669 private static WifiDisplay createWifiDisplay(WifiP2pDevice device) { 670 return new WifiDisplay(device.deviceAddress, device.deviceName); 671 } 672 673 private final BroadcastReceiver mWifiP2pReceiver = new BroadcastReceiver() { 674 @Override 675 public void onReceive(Context context, Intent intent) { 676 final String action = intent.getAction(); 677 if (action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) { 678 boolean enabled = (intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, 679 WifiP2pManager.WIFI_P2P_STATE_DISABLED)) == 680 WifiP2pManager.WIFI_P2P_STATE_ENABLED; 681 if (DEBUG) { 682 Slog.d(TAG, "Received WIFI_P2P_STATE_CHANGED_ACTION: enabled=" 683 + enabled); 684 } 685 686 handleStateChanged(enabled); 687 } else if (action.equals(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)) { 688 if (DEBUG) { 689 Slog.d(TAG, "Received WIFI_P2P_PEERS_CHANGED_ACTION."); 690 } 691 692 handlePeersChanged(); 693 } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) { 694 NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra( 695 WifiP2pManager.EXTRA_NETWORK_INFO); 696 if (DEBUG) { 697 Slog.d(TAG, "Received WIFI_P2P_CONNECTION_CHANGED_ACTION: networkInfo=" 698 + networkInfo); 699 } 700 701 handleConnectionChanged(networkInfo); 702 } 703 } 704 }; 705 706 /** 707 * Called on the handler thread when displays are connected or disconnected. 708 */ 709 public interface Listener { 710 void onEnablementChanged(boolean enabled); 711 712 void onScanStarted(); 713 void onScanFinished(WifiDisplay[] knownDisplays); 714 715 void onDisplayConnecting(WifiDisplay display); 716 void onDisplayConnectionFailed(); 717 void onDisplayConnected(WifiDisplay display, String iface); 718 void onDisplayDisconnected(); 719 } 720} 721