1 /* 2 * Copyright (C) 2011 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 17 package android.net.wifi.p2p; 18 19 import android.annotation.SdkConstant; 20 import android.annotation.SdkConstant.SdkConstantType; 21 import android.content.Context; 22 import android.net.ConnectivityManager; 23 import android.net.IConnectivityManager; 24 import android.os.Binder; 25 import android.os.IBinder; 26 import android.os.Handler; 27 import android.os.Looper; 28 import android.os.Message; 29 import android.os.RemoteException; 30 import android.os.ServiceManager; 31 import android.os.WorkSource; 32 import android.os.Messenger; 33 import android.util.Log; 34 35 import com.android.internal.util.AsyncChannel; 36 import com.android.internal.util.Protocol; 37 38 import java.util.HashMap; 39 40 /** 41 * This class provides the API for managing Wi-Fi peer-to-peer connectivity. This lets an 42 * application discover available peers, setup connection to peers and query for the list of peers. 43 * When a p2p connection is formed over wifi, the device continues to maintain the uplink 44 * connection over mobile or any other available network for internet connectivity on the device. 45 * 46 * <p> The API is asynchronous and responses to requests from an application are on listener 47 * callbacks provided by the application. The application needs to do an initialization with 48 * {@link #initialize} before doing any p2p operation. 49 * 50 * <p> Application actions {@link #discoverPeers}, {@link #connect}, {@link #cancelConnect}, 51 * {@link #createGroup} and {@link #removeGroup} need a {@link ActionListener} instance for 52 * receiving callbacks {@link ActionListener#onSuccess} or {@link ActionListener#onFailure}. 53 * Action callbacks indicate whether the initiation of the action was a success or a failure. 54 * Upon failure, the reason of failure can be one of {@link #ERROR}, {@link #P2P_UNSUPPORTED} 55 * or {@link #BUSY}. 56 * 57 * <p> An application can initiate discovery of peers with {@link #discoverPeers}. An initiated 58 * discovery request from an application stays active until the device starts connecting to a peer 59 * or forms a p2p group. The {@link ActionListener} callbacks provide feedback on whether the 60 * discovery initiation was successful or failure. Additionally, applications can listen 61 * to {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent action to know when the peer list changes. 62 * 63 * <p> When the peer list change intent {@link #WIFI_P2P_PEERS_CHANGED_ACTION} is received 64 * or when an application needs to fetch the current list of peers, it can request the list 65 * of peers with {@link #requestPeers}. When the peer list is available 66 * {@link PeerListListener#onPeersAvailable} is called with the device list. 67 * 68 * <p> An application can initiate a connection request to a peer through {@link #connect}. See 69 * {@link WifiP2pConfig} for details on setting up the configuration. For communication with legacy 70 * Wi-Fi devices that do not support p2p, an app can create a group using {@link #createGroup} 71 * which creates an access point whose details can be fetched with {@link #requestGroupInfo}. 72 * 73 * <p> After a successful group formation through {@link #createGroup} or through {@link #connect}, 74 * use {@link #requestConnectionInfo} to fetch the connection details. The connection info 75 * {@link WifiP2pInfo} contains the address of the group owner 76 * {@link WifiP2pInfo#groupOwnerAddress} and a flag {@link WifiP2pInfo#isGroupOwner} to indicate 77 * if the current device is a p2p group owner. A p2p client can thus communicate with 78 * the p2p group owner through a socket connection. 79 * 80 * <p> Android has no platform support for service discovery yet, so applications could 81 * run a service discovery protocol to discover services on the peer-to-peer netework. 82 * 83 * <p class="note"><strong>Note:</strong> 84 * Registering an application handler with {@link #initialize} requires the permissions 85 * {@link android.Manifest.permission#ACCESS_WIFI_STATE} and 86 * {@link android.Manifest.permission#CHANGE_WIFI_STATE} to perform any further peer-to-peer 87 * operations. 88 * 89 * Get an instance of this class by calling {@link android.content.Context#getSystemService(String) 90 * Context.getSystemService(Context.WIFI_P2P_SERVICE)}. 91 * 92 * {@see WifiP2pConfig} 93 * {@see WifiP2pInfo} 94 * {@see WifiP2pGroup} 95 * {@see WifiP2pDevice} 96 * {@see WifiP2pDeviceList} 97 * {@see android.net.wifi.WpsInfo} 98 */ 99 public class WifiP2pManager { 100 private static final String TAG = "WifiP2pManager"; 101 /** 102 * Broadcast intent action to indicate whether Wi-Fi p2p is enabled or disabled. An 103 * extra {@link #EXTRA_WIFI_STATE} provides the state information as int. 104 * 105 * @see #EXTRA_WIFI_STATE 106 */ 107 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 108 public static final String WIFI_P2P_STATE_CHANGED_ACTION = 109 "android.net.wifi.p2p.STATE_CHANGED"; 110 111 /** 112 * The lookup key for an int that indicates whether Wi-Fi p2p is enabled or disabled. 113 * Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}. 114 * 115 * @see #WIFI_P2P_STATE_DISABLED 116 * @see #WIFI_P2P_STATE_ENABLED 117 */ 118 public static final String EXTRA_WIFI_STATE = "wifi_p2p_state"; 119 120 /** 121 * Wi-Fi p2p is disabled. 122 * 123 * @see #WIFI_P2P_STATE_CHANGED_ACTION 124 */ 125 public static final int WIFI_P2P_STATE_DISABLED = 1; 126 127 /** 128 * Wi-Fi p2p is enabled. 129 * 130 * @see #WIFI_P2P_STATE_CHANGED_ACTION 131 */ 132 public static final int WIFI_P2P_STATE_ENABLED = 2; 133 134 /** 135 * Broadcast intent action indicating that the state of Wi-Fi p2p connectivity 136 * has changed. One extra {@link #EXTRA_WIFI_P2P_INFO} provides the p2p connection info in 137 * the form of a {@link WifiP2pInfo} object. Another extra {@link #EXTRA_NETWORK_INFO} provides 138 * the network info in the form of a {@link android.net.NetworkInfo}. 139 * 140 * @see #EXTRA_WIFI_P2P_INFO 141 * @see #EXTRA_NETWORK_INFO 142 */ 143 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 144 public static final String WIFI_P2P_CONNECTION_CHANGED_ACTION = 145 "android.net.wifi.p2p.CONNECTION_STATE_CHANGE"; 146 147 /** 148 * The lookup key for a {@link android.net.wifi.p2p.WifiP2pInfo} object 149 * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}. 150 */ 151 public static final String EXTRA_WIFI_P2P_INFO = "wifiP2pInfo"; 152 153 /** 154 * The lookup key for a {@link android.net.NetworkInfo} object associated with the 155 * Wi-Fi network. Retrieve with 156 * {@link android.content.Intent#getParcelableExtra(String)}. 157 */ 158 public static final String EXTRA_NETWORK_INFO = "networkInfo"; 159 160 /** 161 * The lookup key for a {@link android.net.LinkProperties} object associated with the 162 * network. Retrieve with 163 * {@link android.content.Intent#getParcelableExtra(String)}. 164 * @hide 165 */ 166 public static final String EXTRA_LINK_PROPERTIES = "linkProperties"; 167 168 /** 169 * The lookup key for a {@link android.net.LinkCapabilities} object associated with the 170 * network. Retrieve with 171 * {@link android.content.Intent#getParcelableExtra(String)}. 172 * @hide 173 */ 174 public static final String EXTRA_LINK_CAPABILITIES = "linkCapabilities"; 175 176 /** 177 * Broadcast intent action indicating that the available peer list has changed. Fetch 178 * the changed list of peers with {@link #requestPeers} 179 */ 180 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 181 public static final String WIFI_P2P_PEERS_CHANGED_ACTION = 182 "android.net.wifi.p2p.PEERS_CHANGED"; 183 184 /** 185 * Broadcast intent action indicating that this device details have changed. 186 */ 187 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 188 public static final String WIFI_P2P_THIS_DEVICE_CHANGED_ACTION = 189 "android.net.wifi.p2p.THIS_DEVICE_CHANGED"; 190 191 /** 192 * The lookup key for a {@link android.net.wifi.p2p.WifiP2pDevice} object 193 * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}. 194 */ 195 public static final String EXTRA_WIFI_P2P_DEVICE = "wifiP2pDevice"; 196 197 IWifiP2pManager mService; 198 199 private static final int BASE = Protocol.BASE_WIFI_P2P_MANAGER; 200 201 /** @hide */ 202 public static final int ENABLE_P2P = BASE + 1; 203 /** @hide */ 204 public static final int ENABLE_P2P_FAILED = BASE + 2; 205 /** @hide */ 206 public static final int ENABLE_P2P_SUCCEEDED = BASE + 3; 207 208 /** @hide */ 209 public static final int DISABLE_P2P = BASE + 4; 210 /** @hide */ 211 public static final int DISABLE_P2P_FAILED = BASE + 5; 212 /** @hide */ 213 public static final int DISABLE_P2P_SUCCEEDED = BASE + 6; 214 215 /** @hide */ 216 public static final int DISCOVER_PEERS = BASE + 7; 217 /** @hide */ 218 public static final int DISCOVER_PEERS_FAILED = BASE + 8; 219 /** @hide */ 220 public static final int DISCOVER_PEERS_SUCCEEDED = BASE + 9; 221 222 /** @hide */ 223 public static final int CONNECT = BASE + 10; 224 /** @hide */ 225 public static final int CONNECT_FAILED = BASE + 11; 226 /** @hide */ 227 public static final int CONNECT_SUCCEEDED = BASE + 12; 228 229 /** @hide */ 230 public static final int CANCEL_CONNECT = BASE + 13; 231 /** @hide */ 232 public static final int CANCEL_CONNECT_FAILED = BASE + 14; 233 /** @hide */ 234 public static final int CANCEL_CONNECT_SUCCEEDED = BASE + 15; 235 236 /** @hide */ 237 public static final int CREATE_GROUP = BASE + 16; 238 /** @hide */ 239 public static final int CREATE_GROUP_FAILED = BASE + 17; 240 /** @hide */ 241 public static final int CREATE_GROUP_SUCCEEDED = BASE + 18; 242 243 /** @hide */ 244 public static final int REMOVE_GROUP = BASE + 19; 245 /** @hide */ 246 public static final int REMOVE_GROUP_FAILED = BASE + 20; 247 /** @hide */ 248 public static final int REMOVE_GROUP_SUCCEEDED = BASE + 21; 249 250 /** @hide */ 251 public static final int REQUEST_PEERS = BASE + 22; 252 /** @hide */ 253 public static final int RESPONSE_PEERS = BASE + 23; 254 255 /** @hide */ 256 public static final int REQUEST_CONNECTION_INFO = BASE + 24; 257 /** @hide */ 258 public static final int RESPONSE_CONNECTION_INFO = BASE + 25; 259 260 /** @hide */ 261 public static final int REQUEST_GROUP_INFO = BASE + 26; 262 /** @hide */ 263 public static final int RESPONSE_GROUP_INFO = BASE + 27; 264 265 /** 266 * Create a new WifiP2pManager instance. Applications use 267 * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve 268 * the standard {@link android.content.Context#WIFI_P2P_SERVICE Context.WIFI_P2P_SERVICE}. 269 * @param service the Binder interface 270 * @hide - hide this because it takes in a parameter of type IWifiP2pManager, which 271 * is a system private class. 272 */ 273 public WifiP2pManager(IWifiP2pManager service) { 274 mService = service; 275 } 276 277 /** 278 * Passed with {@link ActionListener#onFailure}. 279 * Indicates that the operation failed due to an internal error. 280 */ 281 public static final int ERROR = 0; 282 283 /** 284 * Passed with {@link ActionListener#onFailure}. 285 * Indicates that the operation failed because p2p is unsupported on the device. 286 */ 287 public static final int P2P_UNSUPPORTED = 1; 288 289 /** 290 * Passed with {@link ActionListener#onFailure}. 291 * Indicates that the operation failed because the framework is busy and 292 * unable to service the request 293 */ 294 public static final int BUSY = 2; 295 296 /** Interface for callback invocation when framework channel is lost */ 297 public interface ChannelListener { 298 /** 299 * The channel to the framework has been disconnected. 300 * Application could try re-initializing using {@link #initialize} 301 */ 302 public void onChannelDisconnected(); 303 } 304 305 /** Interface for callback invocation on an application action */ 306 public interface ActionListener { 307 /** The operation succeeded */ 308 public void onSuccess(); 309 /** 310 * The operation failed 311 * @param reason The reason for failure could be one of {@link #P2P_UNSUPPORTED}, 312 * {@link #ERROR} or {@link #BUSY} 313 */ 314 public void onFailure(int reason); 315 } 316 317 /** Interface for callback invocation when peer list is available */ 318 public interface PeerListListener { 319 /** 320 * The requested peer list is available 321 * @param peers List of available peers 322 */ 323 public void onPeersAvailable(WifiP2pDeviceList peers); 324 } 325 326 /** Interface for callback invocation when connection info is available */ 327 public interface ConnectionInfoListener { 328 /** 329 * The requested connection info is available 330 * @param info Wi-Fi p2p connection info 331 */ 332 public void onConnectionInfoAvailable(WifiP2pInfo info); 333 } 334 335 /** Interface for callback invocation when group info is available */ 336 public interface GroupInfoListener { 337 /** 338 * The requested p2p group info is available 339 * @param group Wi-Fi p2p group info 340 */ 341 public void onGroupInfoAvailable(WifiP2pGroup group); 342 } 343 344 /** 345 * A channel that connects the application to the Wifi p2p framework. 346 * Most p2p operations require a Channel as an argument. An instance of Channel is obtained 347 * by doing a call on {@link #initialize} 348 */ 349 public static class Channel { 350 Channel(Looper looper, ChannelListener l) { 351 mAsyncChannel = new AsyncChannel(); 352 mHandler = new P2pHandler(looper); 353 mChannelListener = l; 354 } 355 private ChannelListener mChannelListener; 356 private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>(); 357 private Object mListenerMapLock = new Object(); 358 private int mListenerKey = 0; 359 360 AsyncChannel mAsyncChannel; 361 P2pHandler mHandler; 362 class P2pHandler extends Handler { 363 P2pHandler(Looper looper) { 364 super(looper); 365 } 366 367 @Override 368 public void handleMessage(Message message) { 369 Object listener = getListener(message.arg2); 370 switch (message.what) { 371 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 372 if (mChannelListener != null) { 373 mChannelListener.onChannelDisconnected(); 374 mChannelListener = null; 375 } 376 break; 377 /* ActionListeners grouped together */ 378 case WifiP2pManager.DISCOVER_PEERS_FAILED: 379 case WifiP2pManager.CONNECT_FAILED: 380 case WifiP2pManager.CANCEL_CONNECT_FAILED: 381 case WifiP2pManager.CREATE_GROUP_FAILED: 382 case WifiP2pManager.REMOVE_GROUP_FAILED: 383 if (listener != null) { 384 ((ActionListener) listener).onFailure(message.arg1); 385 } 386 break; 387 /* ActionListeners grouped together */ 388 case WifiP2pManager.DISCOVER_PEERS_SUCCEEDED: 389 case WifiP2pManager.CONNECT_SUCCEEDED: 390 case WifiP2pManager.CANCEL_CONNECT_SUCCEEDED: 391 case WifiP2pManager.CREATE_GROUP_SUCCEEDED: 392 case WifiP2pManager.REMOVE_GROUP_SUCCEEDED: 393 if (listener != null) { 394 ((ActionListener) listener).onSuccess(); 395 } 396 break; 397 case WifiP2pManager.RESPONSE_PEERS: 398 WifiP2pDeviceList peers = (WifiP2pDeviceList) message.obj; 399 if (listener != null) { 400 ((PeerListListener) listener).onPeersAvailable(peers); 401 } 402 break; 403 case WifiP2pManager.RESPONSE_CONNECTION_INFO: 404 WifiP2pInfo wifiP2pInfo = (WifiP2pInfo) message.obj; 405 if (listener != null) { 406 ((ConnectionInfoListener) listener).onConnectionInfoAvailable(wifiP2pInfo); 407 } 408 break; 409 case WifiP2pManager.RESPONSE_GROUP_INFO: 410 WifiP2pGroup group = (WifiP2pGroup) message.obj; 411 if (listener != null) { 412 ((GroupInfoListener) listener).onGroupInfoAvailable(group); 413 } 414 break; 415 default: 416 Log.d(TAG, "Ignored " + message); 417 break; 418 } 419 } 420 } 421 422 int putListener(Object listener) { 423 if (listener == null) return 0; 424 int key; 425 synchronized (mListenerMapLock) { 426 key = mListenerKey++; 427 mListenerMap.put(key, listener); 428 } 429 return key; 430 } 431 432 Object getListener(int key) { 433 synchronized (mListenerMapLock) { 434 return mListenerMap.remove(key); 435 } 436 } 437 } 438 439 /** 440 * Registers the application with the Wi-Fi framework. This function 441 * must be the first to be called before any p2p operations are performed. 442 * 443 * @param srcContext is the context of the source 444 * @param srcLooper is the Looper on which the callbacks are receivied 445 * @param listener for callback at loss of framework communication. Can be null. 446 * @return Channel instance that is necessary for performing any further p2p operations 447 */ 448 public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) { 449 Messenger messenger = getMessenger(); 450 if (messenger == null) return null; 451 452 Channel c = new Channel(srcLooper, listener); 453 if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger) 454 == AsyncChannel.STATUS_SUCCESSFUL) { 455 return c; 456 } else { 457 return null; 458 } 459 } 460 461 /** 462 * Sends in a request to the system to enable p2p. This will pop up a dialog 463 * to the user and upon authorization will enable p2p. 464 * @hide 465 */ 466 public void enableP2p(Channel c) { 467 if (c == null) return; 468 c.mAsyncChannel.sendMessage(ENABLE_P2P); 469 } 470 471 /** 472 * Sends in a request to the system to disable p2p. This will pop up a dialog 473 * to the user and upon authorization will enable p2p. 474 * @hide 475 */ 476 public void disableP2p(Channel c) { 477 if (c == null) return; 478 c.mAsyncChannel.sendMessage(DISABLE_P2P); 479 } 480 481 /** 482 * Initiate peer discovery. A discovery process involves scanning for available Wi-Fi peers 483 * for the purpose of establishing a connection. 484 * 485 * <p> The function call immediately returns after sending a discovery request 486 * to the framework. The application is notified of a success or failure to initiate 487 * discovery through listener callbacks {@link ActionListener#onSuccess} or 488 * {@link ActionListener#onFailure}. 489 * 490 * <p> The discovery remains active until a connection is initiated or 491 * a p2p group is formed. Register for {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent to 492 * determine when the framework notifies of a change as peers are discovered. 493 * 494 * <p> Upon receiving a {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent, an application 495 * can request for the list of peers using {@link #requestPeers}. 496 * 497 * @param c is the channel created at {@link #initialize} 498 * @param listener for callbacks on success or failure. Can be null. 499 */ 500 public void discoverPeers(Channel c, ActionListener listener) { 501 if (c == null) return; 502 c.mAsyncChannel.sendMessage(DISCOVER_PEERS, 0, c.putListener(listener)); 503 } 504 505 /** 506 * Start a p2p connection to a device with the specified configuration. 507 * 508 * <p> The function call immediately returns after sending a connection request 509 * to the framework. The application is notified of a success or failure to initiate 510 * connect through listener callbacks {@link ActionListener#onSuccess} or 511 * {@link ActionListener#onFailure}. 512 * 513 * <p> Register for {@link #WIFI_P2P_CONNECTION_CHANGED_ACTION} intent to 514 * determine when the framework notifies of a change in connectivity. 515 * 516 * <p> If the current device is not part of a p2p group, a connect request initiates 517 * a group negotiation with the peer. 518 * 519 * <p> If the current device is part of an existing p2p group or has created 520 * a p2p group with {@link #createGroup}, an invitation to join the group is sent to 521 * the peer device. 522 * 523 * @param c is the channel created at {@link #initialize} 524 * @param config options as described in {@link WifiP2pConfig} class 525 * @param listener for callbacks on success or failure. Can be null. 526 */ 527 public void connect(Channel c, WifiP2pConfig config, ActionListener listener) { 528 if (c == null) return; 529 c.mAsyncChannel.sendMessage(CONNECT, 0, c.putListener(listener), config); 530 } 531 532 /** 533 * Cancel any ongoing p2p group negotiation 534 * 535 * <p> The function call immediately returns after sending a connection cancellation request 536 * to the framework. The application is notified of a success or failure to initiate 537 * cancellation through listener callbacks {@link ActionListener#onSuccess} or 538 * {@link ActionListener#onFailure}. 539 * 540 * @param c is the channel created at {@link #initialize} 541 * @param listener for callbacks on success or failure. Can be null. 542 */ 543 public void cancelConnect(Channel c, ActionListener listener) { 544 if (c == null) return; 545 c.mAsyncChannel.sendMessage(CANCEL_CONNECT, 0, c.putListener(listener)); 546 } 547 548 /** 549 * Create a p2p group with the current device as the group owner. This essentially creates 550 * an access point that can accept connections from legacy clients as well as other p2p 551 * devices. 552 * 553 * <p class="note"><strong>Note:</strong> 554 * This function would normally not be used unless the current device needs 555 * to form a p2p connection with a legacy client 556 * 557 * <p> The function call immediately returns after sending a group creation request 558 * to the framework. The application is notified of a success or failure to initiate 559 * group creation through listener callbacks {@link ActionListener#onSuccess} or 560 * {@link ActionListener#onFailure}. 561 * 562 * <p> Application can request for the group details with {@link #requestGroupInfo}. 563 * 564 * @param c is the channel created at {@link #initialize} 565 * @param listener for callbacks on success or failure. Can be null. 566 */ 567 public void createGroup(Channel c, ActionListener listener) { 568 if (c == null) return; 569 c.mAsyncChannel.sendMessage(CREATE_GROUP, 0, c.putListener(listener)); 570 } 571 572 /** 573 * Remove the current p2p group. 574 * 575 * <p> The function call immediately returns after sending a group removal request 576 * to the framework. The application is notified of a success or failure to initiate 577 * group removal through listener callbacks {@link ActionListener#onSuccess} or 578 * {@link ActionListener#onFailure}. 579 * 580 * @param c is the channel created at {@link #initialize} 581 * @param listener for callbacks on success or failure. Can be null. 582 */ 583 public void removeGroup(Channel c, ActionListener listener) { 584 if (c == null) return; 585 c.mAsyncChannel.sendMessage(REMOVE_GROUP, 0, c.putListener(listener)); 586 } 587 588 /** 589 * Request the current list of peers. 590 * 591 * @param c is the channel created at {@link #initialize} 592 * @param listener for callback when peer list is available. Can be null. 593 */ 594 public void requestPeers(Channel c, PeerListListener listener) { 595 if (c == null) return; 596 c.mAsyncChannel.sendMessage(REQUEST_PEERS, 0, c.putListener(listener)); 597 } 598 599 /** 600 * Request device connection info. 601 * 602 * @param c is the channel created at {@link #initialize} 603 * @param listener for callback when connection info is available. Can be null. 604 */ 605 public void requestConnectionInfo(Channel c, ConnectionInfoListener listener) { 606 if (c == null) return; 607 c.mAsyncChannel.sendMessage(REQUEST_CONNECTION_INFO, 0, c.putListener(listener)); 608 } 609 610 /** 611 * Request p2p group info. 612 * 613 * @param c is the channel created at {@link #initialize} 614 * @param listener for callback when group info is available. Can be null. 615 */ 616 public void requestGroupInfo(Channel c, GroupInfoListener listener) { 617 if (c == null) return; 618 c.mAsyncChannel.sendMessage(REQUEST_GROUP_INFO, 0, c.putListener(listener)); 619 } 620 621 /** 622 * Get a reference to WifiP2pService handler. This is used to establish 623 * an AsyncChannel communication with WifiService 624 * 625 * @return Messenger pointing to the WifiP2pService handler 626 * @hide 627 */ 628 public Messenger getMessenger() { 629 try { 630 return mService.getMessenger(); 631 } catch (RemoteException e) { 632 return null; 633 } 634 } 635 636 } 637