WifiDisplayController.java revision 5e0cc0d7ab29e5fbd11316cd3147ef96d65f8de7
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 discoverPeers(); 183 } 184 } 185 186 @Override 187 public void onFailure(int reason) { 188 if (DEBUG) { 189 Slog.d(TAG, "Failed to set WFD info with reason " + reason + "."); 190 } 191 mWfdEnabling = false; 192 } 193 }); 194 } 195 } 196 197 private void setWfdEnabled(final boolean enabled) { 198 if (mWfdEnabled != enabled) { 199 mWfdEnabled = enabled; 200 mHandler.post(new Runnable() { 201 @Override 202 public void run() { 203 mListener.onEnablementChanged(enabled); 204 } 205 }); 206 } 207 } 208 209 private void discoverPeers() { 210 if (!mDiscoverPeersInProgress) { 211 mDiscoverPeersInProgress = true; 212 mDiscoverPeersRetriesLeft = DISCOVER_PEERS_MAX_RETRIES; 213 handleScanStarted(); 214 tryDiscoverPeers(); 215 } 216 } 217 218 private void tryDiscoverPeers() { 219 mWifiP2pManager.discoverPeers(mWifiP2pChannel, new ActionListener() { 220 @Override 221 public void onSuccess() { 222 if (DEBUG) { 223 Slog.d(TAG, "Discover peers succeeded. Requesting peers now."); 224 } 225 226 mDiscoverPeersInProgress = false; 227 requestPeers(); 228 } 229 230 @Override 231 public void onFailure(int reason) { 232 if (DEBUG) { 233 Slog.d(TAG, "Discover peers failed with reason " + reason + "."); 234 } 235 236 if (mDiscoverPeersInProgress) { 237 if (reason == 0 && mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) { 238 mHandler.postDelayed(new Runnable() { 239 @Override 240 public void run() { 241 if (mDiscoverPeersInProgress) { 242 if (mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) { 243 mDiscoverPeersRetriesLeft -= 1; 244 if (DEBUG) { 245 Slog.d(TAG, "Retrying discovery. Retries left: " 246 + mDiscoverPeersRetriesLeft); 247 } 248 tryDiscoverPeers(); 249 } else { 250 handleScanFinished(); 251 mDiscoverPeersInProgress = false; 252 } 253 } 254 } 255 }, DISCOVER_PEERS_RETRY_DELAY_MILLIS); 256 } else { 257 handleScanFinished(); 258 mDiscoverPeersInProgress = false; 259 } 260 } 261 } 262 }); 263 } 264 265 private void requestPeers() { 266 mWifiP2pManager.requestPeers(mWifiP2pChannel, new PeerListListener() { 267 @Override 268 public void onPeersAvailable(WifiP2pDeviceList peers) { 269 if (DEBUG) { 270 Slog.d(TAG, "Received list of peers."); 271 } 272 273 mKnownWifiDisplayPeers.clear(); 274 for (WifiP2pDevice device : peers.getDeviceList()) { 275 if (DEBUG) { 276 Slog.d(TAG, " " + describeWifiP2pDevice(device)); 277 } 278 279 if (isWifiDisplay(device)) { 280 mKnownWifiDisplayPeers.add(device); 281 } 282 } 283 284 handleScanFinished(); 285 } 286 }); 287 } 288 289 private void handleScanStarted() { 290 mHandler.post(new Runnable() { 291 @Override 292 public void run() { 293 mListener.onScanStarted(); 294 } 295 }); 296 } 297 298 private void handleScanFinished() { 299 final int count = mKnownWifiDisplayPeers.size(); 300 final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count); 301 for (int i = 0; i < count; i++) { 302 displays[i] = createWifiDisplay(mKnownWifiDisplayPeers.get(i)); 303 } 304 305 mHandler.post(new Runnable() { 306 @Override 307 public void run() { 308 mListener.onScanFinished(displays); 309 } 310 }); 311 } 312 313 private void connect(final WifiP2pDevice device) { 314 if (mDesiredDevice != null 315 && !mDesiredDevice.deviceAddress.equals(device.deviceAddress)) { 316 if (DEBUG) { 317 Slog.d(TAG, "connect: nothing to do, already connecting to " 318 + describeWifiP2pDevice(device)); 319 } 320 return; 321 } 322 323 if (mConnectedDevice != null 324 && !mConnectedDevice.deviceAddress.equals(device.deviceAddress) 325 && mDesiredDevice == null) { 326 if (DEBUG) { 327 Slog.d(TAG, "connect: nothing to do, already connected to " 328 + describeWifiP2pDevice(device) + " and not part way through " 329 + "connecting to a different device."); 330 } 331 return; 332 } 333 334 mDesiredDevice = device; 335 mConnectionRetriesLeft = CONNECT_MAX_RETRIES; 336 updateConnection(); 337 } 338 339 private void disconnect() { 340 mDesiredDevice = null; 341 updateConnection(); 342 } 343 344 private void retryConnection() { 345 if (mDesiredDevice != null && mPublishedDevice != mDesiredDevice 346 && mConnectionRetriesLeft > 0) { 347 mConnectionRetriesLeft -= 1; 348 Slog.i(TAG, "Retrying Wifi display connection. Retries left: " 349 + mConnectionRetriesLeft); 350 351 // Cheap hack. Make a new instance of the device object so that we 352 // can distinguish it from the previous connection attempt. 353 // This will cause us to tear everything down before we try again. 354 mDesiredDevice = new WifiP2pDevice(mDesiredDevice); 355 updateConnection(); 356 } 357 } 358 359 /** 360 * This function is called repeatedly after each asynchronous operation 361 * until all preconditions for the connection have been satisfied and the 362 * connection is established (or not). 363 */ 364 private void updateConnection() { 365 // Step 1. Before we try to connect to a new device, tell the system we 366 // have disconnected from the old one. 367 if (mPublishedDevice != null && mPublishedDevice != mDesiredDevice) { 368 mHandler.post(new Runnable() { 369 @Override 370 public void run() { 371 mListener.onDisplayDisconnected(); 372 } 373 }); 374 mPublishedDevice = null; 375 376 // continue to next step 377 } 378 379 // Step 2. Before we try to connect to a new device, disconnect from the old one. 380 if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) { 381 Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName); 382 383 final WifiP2pDevice oldDevice = mConnectedDevice; 384 mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() { 385 @Override 386 public void onSuccess() { 387 Slog.i(TAG, "Disconnected from Wifi display: " + oldDevice.deviceName); 388 next(); 389 } 390 391 @Override 392 public void onFailure(int reason) { 393 Slog.i(TAG, "Failed to disconnect from Wifi display: " 394 + oldDevice.deviceName + ", reason=" + reason); 395 next(); 396 } 397 398 private void next() { 399 if (mConnectedDevice == oldDevice) { 400 mConnectedDevice = null; 401 updateConnection(); 402 } 403 } 404 }); 405 return; // wait for asynchronous callback 406 } 407 408 // Step 3. Before we try to connect to a new device, stop trying to connect 409 // to the old one. 410 if (mConnectingDevice != null && mConnectingDevice != mDesiredDevice) { 411 Slog.i(TAG, "Canceling connection to Wifi display: " + mConnectingDevice.deviceName); 412 413 mHandler.removeCallbacks(mConnectionTimeout); 414 415 final WifiP2pDevice oldDevice = mConnectingDevice; 416 mWifiP2pManager.cancelConnect(mWifiP2pChannel, new ActionListener() { 417 @Override 418 public void onSuccess() { 419 Slog.i(TAG, "Canceled connection to Wifi display: " + oldDevice.deviceName); 420 next(); 421 } 422 423 @Override 424 public void onFailure(int reason) { 425 Slog.i(TAG, "Failed to cancel connection to Wifi display: " 426 + oldDevice.deviceName + ", reason=" + reason); 427 next(); 428 } 429 430 private void next() { 431 if (mConnectingDevice == oldDevice) { 432 mConnectingDevice = null; 433 updateConnection(); 434 } 435 } 436 }); 437 return; // wait for asynchronous callback 438 } 439 440 // Step 4. If we wanted to disconnect, then mission accomplished. 441 if (mDesiredDevice == null) { 442 return; // done 443 } 444 445 // Step 5. Try to connect. 446 if (mConnectedDevice == null && mConnectingDevice == null) { 447 Slog.i(TAG, "Connecting to Wifi display: " + mDesiredDevice.deviceName); 448 449 mConnectingDevice = mDesiredDevice; 450 WifiP2pConfig config = new WifiP2pConfig(); 451 config.deviceAddress = mConnectingDevice.deviceAddress; 452 453 final WifiDisplay display = createWifiDisplay(mConnectingDevice); 454 mHandler.post(new Runnable() { 455 @Override 456 public void run() { 457 mListener.onDisplayConnecting(display); 458 } 459 }); 460 461 final WifiP2pDevice newDevice = mDesiredDevice; 462 mWifiP2pManager.connect(mWifiP2pChannel, config, new ActionListener() { 463 @Override 464 public void onSuccess() { 465 // The connection may not yet be established. We still need to wait 466 // for WIFI_P2P_CONNECTION_CHANGED_ACTION. However, we might never 467 // get that broadcast, so we register a timeout. 468 Slog.i(TAG, "Initiated connection to Wifi display: " + newDevice.deviceName); 469 470 mHandler.postDelayed(mConnectionTimeout, CONNECTION_TIMEOUT_SECONDS * 1000); 471 } 472 473 @Override 474 public void onFailure(int reason) { 475 Slog.i(TAG, "Failed to initiate connection to Wifi display: " 476 + newDevice.deviceName + ", reason=" + reason); 477 if (mConnectingDevice == newDevice) { 478 mConnectingDevice = null; 479 handleConnectionFailure(false); 480 } 481 } 482 }); 483 return; // wait for asynchronous callback 484 } 485 486 // Step 6. Publish the new connection. 487 if (mConnectedDevice != null && mPublishedDevice == null) { 488 Inet4Address addr = getInterfaceAddress(mConnectedDeviceGroupInfo); 489 if (addr == null) { 490 Slog.i(TAG, "Failed to get local interface address for communicating " 491 + "with Wifi display: " + mConnectedDevice.deviceName); 492 handleConnectionFailure(false); 493 return; // done 494 } 495 496 int port = DEFAULT_CONTROL_PORT; 497 if (mConnectedDevice.deviceName.startsWith("DIRECT-") 498 && mConnectedDevice.deviceName.endsWith("Broadcom")) { 499 // These dongles ignore the port we broadcast in our WFD IE. 500 port = 8554; 501 } 502 503 final WifiDisplay display = createWifiDisplay(mConnectedDevice); 504 final String iface = addr.getHostAddress() + ":" + port; 505 506 mPublishedDevice = mConnectedDevice; 507 mHandler.post(new Runnable() { 508 @Override 509 public void run() { 510 mListener.onDisplayConnected(display, iface); 511 } 512 }); 513 } 514 } 515 516 private void handleStateChanged(boolean enabled) { 517 if (mWifiP2pEnabled != enabled) { 518 mWifiP2pEnabled = enabled; 519 if (enabled) { 520 if (mWfdEnabled) { 521 discoverPeers(); 522 } else { 523 enableWfd(); 524 } 525 } else { 526 setWfdEnabled(false); 527 disconnect(); 528 } 529 } 530 } 531 532 private void handlePeersChanged() { 533 if (mWifiP2pEnabled) { 534 if (mWfdEnabled) { 535 requestPeers(); 536 } else { 537 enableWfd(); 538 } 539 } 540 } 541 542 private void handleConnectionChanged(NetworkInfo networkInfo) { 543 mNetworkInfo = networkInfo; 544 if (mWfdEnabled && networkInfo.isConnected()) { 545 if (mDesiredDevice != null) { 546 mWifiP2pManager.requestGroupInfo(mWifiP2pChannel, new GroupInfoListener() { 547 @Override 548 public void onGroupInfoAvailable(WifiP2pGroup info) { 549 if (DEBUG) { 550 Slog.d(TAG, "Received group info: " + describeWifiP2pGroup(info)); 551 } 552 553 if (mConnectingDevice != null && !info.contains(mConnectingDevice)) { 554 Slog.i(TAG, "Aborting connection to Wifi display because " 555 + "the current P2P group does not contain the device " 556 + "we expected to find: " + mConnectingDevice.deviceName); 557 handleConnectionFailure(false); 558 return; 559 } 560 561 if (mDesiredDevice != null && !info.contains(mDesiredDevice)) { 562 disconnect(); 563 return; 564 } 565 566 if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) { 567 Slog.i(TAG, "Connected to Wifi display: " 568 + mConnectingDevice.deviceName); 569 570 mHandler.removeCallbacks(mConnectionTimeout); 571 mConnectedDeviceGroupInfo = info; 572 mConnectedDevice = mConnectingDevice; 573 mConnectingDevice = null; 574 updateConnection(); 575 } 576 } 577 }); 578 } 579 } else { 580 disconnect(); 581 582 // After disconnection for a group, for some reason we have a tendency 583 // to get a peer change notification with an empty list of peers. 584 // Perform a fresh scan. 585 if (mWfdEnabled) { 586 requestPeers(); 587 } 588 } 589 } 590 591 private final Runnable mConnectionTimeout = new Runnable() { 592 @Override 593 public void run() { 594 if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) { 595 Slog.i(TAG, "Timed out waiting for Wifi display connection after " 596 + CONNECTION_TIMEOUT_SECONDS + " seconds: " 597 + mConnectingDevice.deviceName); 598 handleConnectionFailure(true); 599 } 600 } 601 }; 602 603 private void handleConnectionFailure(boolean timeoutOccurred) { 604 if (mDesiredDevice != null) { 605 Slog.i(TAG, "Wifi display connection failed!"); 606 607 mHandler.post(new Runnable() { 608 @Override 609 public void run() { 610 mListener.onDisplayConnectionFailed(); 611 } 612 }); 613 614 if (mConnectionRetriesLeft > 0) { 615 mHandler.postDelayed(new Runnable() { 616 @Override 617 public void run() { 618 retryConnection(); 619 } 620 }, timeoutOccurred ? 0 : CONNECT_RETRY_DELAY_MILLIS); 621 } else { 622 disconnect(); 623 } 624 } 625 } 626 627 private static Inet4Address getInterfaceAddress(WifiP2pGroup info) { 628 NetworkInterface iface; 629 try { 630 iface = NetworkInterface.getByName(info.getInterface()); 631 } catch (SocketException ex) { 632 Slog.w(TAG, "Could not obtain address of network interface " 633 + info.getInterface(), ex); 634 return null; 635 } 636 637 Enumeration<InetAddress> addrs = iface.getInetAddresses(); 638 while (addrs.hasMoreElements()) { 639 InetAddress addr = addrs.nextElement(); 640 if (addr instanceof Inet4Address) { 641 return (Inet4Address)addr; 642 } 643 } 644 645 Slog.w(TAG, "Could not obtain address of network interface " 646 + info.getInterface() + " because it had no IPv4 addresses."); 647 return null; 648 } 649 650 private static boolean isWifiDisplay(WifiP2pDevice device) { 651 // FIXME: the wfdInfo API doesn't work yet 652 return device.deviceName.startsWith("DWD-") 653 || device.deviceName.startsWith("DIRECT-") 654 || device.deviceName.startsWith("CAVM-"); 655 //device.wfdInfo != null && device.wfdInfo.isWfdEnabled(); 656 } 657 658 private static String describeWifiP2pDevice(WifiP2pDevice device) { 659 return device != null ? device.toString().replace('\n', ',') : "null"; 660 } 661 662 private static String describeWifiP2pGroup(WifiP2pGroup group) { 663 return group != null ? group.toString().replace('\n', ',') : "null"; 664 } 665 666 private static WifiDisplay createWifiDisplay(WifiP2pDevice device) { 667 return new WifiDisplay(device.deviceAddress, device.deviceName); 668 } 669 670 private final BroadcastReceiver mWifiP2pReceiver = new BroadcastReceiver() { 671 @Override 672 public void onReceive(Context context, Intent intent) { 673 final String action = intent.getAction(); 674 if (action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) { 675 boolean enabled = (intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, 676 WifiP2pManager.WIFI_P2P_STATE_DISABLED)) == 677 WifiP2pManager.WIFI_P2P_STATE_ENABLED; 678 if (DEBUG) { 679 Slog.d(TAG, "Received WIFI_P2P_STATE_CHANGED_ACTION: enabled=" 680 + enabled); 681 } 682 683 handleStateChanged(enabled); 684 } else if (action.equals(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)) { 685 if (DEBUG) { 686 Slog.d(TAG, "Received WIFI_P2P_PEERS_CHANGED_ACTION."); 687 } 688 689 handlePeersChanged(); 690 } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) { 691 NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra( 692 WifiP2pManager.EXTRA_NETWORK_INFO); 693 if (DEBUG) { 694 Slog.d(TAG, "Received WIFI_P2P_CONNECTION_CHANGED_ACTION: networkInfo=" 695 + networkInfo); 696 } 697 698 handleConnectionChanged(networkInfo); 699 } 700 } 701 }; 702 703 /** 704 * Called on the handler thread when displays are connected or disconnected. 705 */ 706 public interface Listener { 707 void onEnablementChanged(boolean enabled); 708 709 void onScanStarted(); 710 void onScanFinished(WifiDisplay[] knownDisplays); 711 712 void onDisplayConnecting(WifiDisplay display); 713 void onDisplayConnectionFailed(); 714 void onDisplayConnected(WifiDisplay display, String iface); 715 void onDisplayDisconnected(); 716 } 717} 718