WifiP2pService.java revision 9cb980422ac53b81d6ad15242b0de35b5f3ce13c
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 17package android.net.wifi.p2p; 18 19import android.app.Activity; 20import android.app.ActivityManager; 21import android.app.AlertDialog; 22import android.app.Notification; 23import android.app.NotificationManager; 24import android.app.PendingIntent; 25import android.app.ActivityManager.RunningTaskInfo; 26import android.content.BroadcastReceiver; 27import android.content.Context; 28import android.content.DialogInterface; 29import android.content.DialogInterface.OnClickListener; 30import android.content.Intent; 31import android.content.IntentFilter; 32import android.content.pm.PackageManager; 33import android.content.res.Resources; 34import android.net.IConnectivityManager; 35import android.net.ConnectivityManager; 36import android.net.DhcpInfoInternal; 37import android.net.DhcpStateMachine; 38import android.net.InterfaceConfiguration; 39import android.net.LinkAddress; 40import android.net.LinkProperties; 41import android.net.NetworkInfo; 42import android.net.NetworkUtils; 43import android.net.wifi.WifiManager; 44import android.net.wifi.WifiMonitor; 45import android.net.wifi.WifiNative; 46import android.net.wifi.WifiStateMachine; 47import android.net.wifi.WpsInfo; 48import android.net.wifi.p2p.nsd.WifiP2pServiceInfo; 49import android.net.wifi.p2p.nsd.WifiP2pServiceRequest; 50import android.net.wifi.p2p.nsd.WifiP2pServiceResponse; 51import android.os.Binder; 52import android.os.Bundle; 53import android.os.IBinder; 54import android.os.INetworkManagementService; 55import android.os.Handler; 56import android.os.HandlerThread; 57import android.os.Message; 58import android.os.Messenger; 59import android.os.Parcel; 60import android.os.Parcelable; 61import android.os.RemoteException; 62import android.os.ServiceManager; 63import android.os.SystemProperties; 64import android.os.Parcelable.Creator; 65import android.provider.Settings; 66import android.text.TextUtils; 67import android.util.Slog; 68import android.util.SparseArray; 69import android.view.LayoutInflater; 70import android.view.View; 71import android.view.ViewGroup; 72import android.view.WindowManager; 73import android.widget.EditText; 74import android.widget.TextView; 75 76import com.android.internal.R; 77import com.android.internal.telephony.TelephonyIntents; 78import com.android.internal.util.AsyncChannel; 79import com.android.internal.util.Protocol; 80import com.android.internal.util.State; 81import com.android.internal.util.StateMachine; 82 83import java.io.FileDescriptor; 84import java.io.PrintWriter; 85import java.util.ArrayList; 86import java.util.Collection; 87import java.util.HashMap; 88import java.util.List; 89 90/** 91 * WifiP2pService includes a state machine to perform Wi-Fi p2p operations. Applications 92 * communicate with this service to issue device discovery and connectivity requests 93 * through the WifiP2pManager interface. The state machine communicates with the wifi 94 * driver through wpa_supplicant and handles the event responses through WifiMonitor. 95 * 96 * Note that the term Wifi when used without a p2p suffix refers to the client mode 97 * of Wifi operation 98 * @hide 99 */ 100public class WifiP2pService extends IWifiP2pManager.Stub { 101 private static final String TAG = "WifiP2pService"; 102 private static final boolean DBG = false; 103 private static final String NETWORKTYPE = "WIFI_P2P"; 104 105 private Context mContext; 106 private String mInterface; 107 private Notification mNotification; 108 109 INetworkManagementService mNwService; 110 private DhcpStateMachine mDhcpStateMachine; 111 112 private ActivityManager mActivityMgr; 113 114 private P2pStateMachine mP2pStateMachine; 115 private AsyncChannel mReplyChannel = new AsyncChannel(); 116 private AsyncChannel mWifiChannel; 117 118 private static final Boolean JOIN_GROUP = true; 119 private static final Boolean FORM_GROUP = false; 120 121 /* Two minutes comes from the wpa_supplicant setting */ 122 private static final int GROUP_CREATING_WAIT_TIME_MS = 120 * 1000; 123 private static int mGroupCreatingTimeoutIndex = 0; 124 125 /* Set a two minute discover timeout to avoid STA scans from being blocked */ 126 private static final int DISCOVER_TIMEOUT_S = 120; 127 128 /* Idle time after a peer is gone when the group is torn down */ 129 private static final int GROUP_IDLE_TIME_S = 2; 130 131 /** 132 * Delay between restarts upon failure to setup connection with supplicant 133 */ 134 private static final int P2P_RESTART_INTERVAL_MSECS = 5000; 135 136 /** 137 * Number of times we attempt to restart p2p 138 */ 139 private static final int P2P_RESTART_TRIES = 5; 140 141 private int mP2pRestartCount = 0; 142 143 private static final int BASE = Protocol.BASE_WIFI_P2P_SERVICE; 144 145 /* Delayed message to timeout group creation */ 146 public static final int GROUP_CREATING_TIMED_OUT = BASE + 1; 147 148 /* User accepted a peer request */ 149 private static final int PEER_CONNECTION_USER_ACCEPT = BASE + 2; 150 /* User rejected a peer request */ 151 private static final int PEER_CONNECTION_USER_REJECT = BASE + 3; 152 153 private final boolean mP2pSupported; 154 155 private WifiP2pDevice mThisDevice = new WifiP2pDevice(); 156 157 /* When a group has been explicitly created by an app, we persist the group 158 * even after all clients have been disconnected until an explicit remove 159 * is invoked */ 160 private boolean mAutonomousGroup; 161 162 /* Invitation to join an existing p2p group */ 163 private boolean mJoinExistingGroup; 164 165 /* Track whether we are in p2p discovery. This is used to avoid sending duplicate 166 * broadcasts 167 */ 168 private boolean mDiscoveryStarted; 169 170 private NetworkInfo mNetworkInfo; 171 172 /* The transaction Id of service discovery request */ 173 private byte mServiceTransactionId = 0; 174 175 /* Service discovery request ID of wpa_supplicant. 176 * null means it's not set yet. */ 177 private String mServiceDiscReqId; 178 179 /* clients(application) information list. */ 180 private HashMap<Messenger, ClientInfo> mClientInfoList = new HashMap<Messenger, ClientInfo>(); 181 182 /* The foreground application's messenger. 183 * The connection request is notified only to foreground application */ 184 private Messenger mForegroundAppMessenger; 185 186 /* the package name of foreground application. */ 187 private String mForegroundAppPkgName; 188 189 /* Is chosen as a unique range to avoid conflict with 190 the range defined in Tethering.java */ 191 private static final String[] DHCP_RANGE = {"192.168.49.2", "192.168.49.254"}; 192 private static final String SERVER_ADDRESS = "192.168.49.1"; 193 194 public WifiP2pService(Context context) { 195 mContext = context; 196 197 //STOPSHIP: get this from native side 198 mInterface = "p2p0"; 199 mActivityMgr = (ActivityManager)context.getSystemService(Activity.ACTIVITY_SERVICE); 200 201 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, ""); 202 203 mP2pSupported = mContext.getPackageManager().hasSystemFeature( 204 PackageManager.FEATURE_WIFI_DIRECT); 205 206 mThisDevice.primaryDeviceType = mContext.getResources().getString( 207 com.android.internal.R.string.config_wifi_p2p_device_type); 208 209 mP2pStateMachine = new P2pStateMachine(TAG, mP2pSupported); 210 mP2pStateMachine.start(); 211 } 212 213 public void connectivityServiceReady() { 214 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 215 mNwService = INetworkManagementService.Stub.asInterface(b); 216 } 217 218 private void enforceAccessPermission() { 219 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, 220 "WifiP2pService"); 221 } 222 223 private void enforceChangePermission() { 224 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, 225 "WifiP2pService"); 226 } 227 228 /** 229 * Get a reference to handler. This is used by a client to establish 230 * an AsyncChannel communication with WifiP2pService 231 */ 232 public Messenger getMessenger() { 233 enforceAccessPermission(); 234 enforceChangePermission(); 235 return new Messenger(mP2pStateMachine.getHandler()); 236 } 237 238 @Override 239 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 240 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 241 != PackageManager.PERMISSION_GRANTED) { 242 pw.println("Permission Denial: can't dump WifiP2pService from from pid=" 243 + Binder.getCallingPid() 244 + ", uid=" + Binder.getCallingUid()); 245 return; 246 } 247 } 248 249 250 /** 251 * Handles interaction with WifiStateMachine 252 */ 253 private class P2pStateMachine extends StateMachine { 254 255 private DefaultState mDefaultState = new DefaultState(); 256 private P2pNotSupportedState mP2pNotSupportedState = new P2pNotSupportedState(); 257 private P2pDisablingState mP2pDisablingState = new P2pDisablingState(); 258 private P2pDisabledState mP2pDisabledState = new P2pDisabledState(); 259 private P2pEnablingState mP2pEnablingState = new P2pEnablingState(); 260 private P2pEnabledState mP2pEnabledState = new P2pEnabledState(); 261 // Inactive is when p2p is enabled with no connectivity 262 private InactiveState mInactiveState = new InactiveState(); 263 private GroupCreatingState mGroupCreatingState = new GroupCreatingState(); 264 private UserAuthorizingInvitationState mUserAuthorizingInvitationState 265 = new UserAuthorizingInvitationState(); 266 private ProvisionDiscoveryState mProvisionDiscoveryState = new ProvisionDiscoveryState(); 267 private GroupNegotiationState mGroupNegotiationState = new GroupNegotiationState(); 268 269 private GroupCreatedState mGroupCreatedState = new GroupCreatedState(); 270 private UserAuthorizingJoinState mUserAuthorizingJoinState = new UserAuthorizingJoinState(); 271 272 private WifiNative mWifiNative = new WifiNative(mInterface); 273 private WifiMonitor mWifiMonitor = new WifiMonitor(this, mWifiNative); 274 275 private WifiP2pDeviceList mPeers = new WifiP2pDeviceList(); 276 private WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo(); 277 private WifiP2pGroup mGroup; 278 279 // Saved WifiP2pConfig for a peer connection 280 private WifiP2pConfig mSavedPeerConfig; 281 282 // Saved WifiP2pGroup from invitation request 283 private WifiP2pGroup mSavedP2pGroup; 284 285 // Saved WifiP2pDevice from provisioning request 286 private WifiP2pDevice mSavedProvDiscDevice; 287 288 P2pStateMachine(String name, boolean p2pSupported) { 289 super(name); 290 291 addState(mDefaultState); 292 addState(mP2pNotSupportedState, mDefaultState); 293 addState(mP2pDisablingState, mDefaultState); 294 addState(mP2pDisabledState, mDefaultState); 295 addState(mP2pEnablingState, mDefaultState); 296 addState(mP2pEnabledState, mDefaultState); 297 addState(mInactiveState, mP2pEnabledState); 298 addState(mGroupCreatingState, mP2pEnabledState); 299 addState(mUserAuthorizingInvitationState, mGroupCreatingState); 300 addState(mProvisionDiscoveryState, mGroupCreatingState); 301 addState(mGroupNegotiationState, mGroupCreatingState); 302 addState(mGroupCreatedState, mP2pEnabledState); 303 addState(mUserAuthorizingJoinState, mGroupCreatedState); 304 305 if (p2pSupported) { 306 setInitialState(mP2pDisabledState); 307 } else { 308 setInitialState(mP2pNotSupportedState); 309 } 310 } 311 312 class DefaultState extends State { 313 @Override 314 public boolean processMessage(Message message) { 315 if (DBG) logd(getName() + message.toString()); 316 switch (message.what) { 317 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 318 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 319 if (DBG) logd("Full connection with WifiStateMachine established"); 320 mWifiChannel = (AsyncChannel) message.obj; 321 } else { 322 loge("Full connection failure, error = " + message.arg1); 323 mWifiChannel = null; 324 } 325 break; 326 327 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 328 if (message.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { 329 loge("Send failed, client connection lost"); 330 } else { 331 loge("Client connection lost with reason: " + message.arg1); 332 } 333 mWifiChannel = null; 334 break; 335 336 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: 337 AsyncChannel ac = new AsyncChannel(); 338 ac.connect(mContext, getHandler(), message.replyTo); 339 break; 340 case WifiP2pManager.DISCOVER_PEERS: 341 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, 342 WifiP2pManager.BUSY); 343 break; 344 case WifiP2pManager.STOP_DISCOVERY: 345 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, 346 WifiP2pManager.BUSY); 347 break; 348 case WifiP2pManager.DISCOVER_SERVICES: 349 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, 350 WifiP2pManager.BUSY); 351 break; 352 case WifiP2pManager.CONNECT: 353 replyToMessage(message, WifiP2pManager.CONNECT_FAILED, 354 WifiP2pManager.BUSY); 355 break; 356 case WifiP2pManager.CANCEL_CONNECT: 357 replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED, 358 WifiP2pManager.BUSY); 359 break; 360 case WifiP2pManager.CREATE_GROUP: 361 replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED, 362 WifiP2pManager.BUSY); 363 break; 364 case WifiP2pManager.REMOVE_GROUP: 365 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED, 366 WifiP2pManager.BUSY); 367 break; 368 case WifiP2pManager.ADD_LOCAL_SERVICE: 369 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED, 370 WifiP2pManager.BUSY); 371 break; 372 case WifiP2pManager.REMOVE_LOCAL_SERVICE: 373 replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED, 374 WifiP2pManager.BUSY); 375 break; 376 case WifiP2pManager.CLEAR_LOCAL_SERVICES: 377 replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED, 378 WifiP2pManager.BUSY); 379 break; 380 case WifiP2pManager.ADD_SERVICE_REQUEST: 381 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED, 382 WifiP2pManager.BUSY); 383 break; 384 case WifiP2pManager.REMOVE_SERVICE_REQUEST: 385 replyToMessage(message, 386 WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED, 387 WifiP2pManager.BUSY); 388 break; 389 case WifiP2pManager.CLEAR_SERVICE_REQUESTS: 390 replyToMessage(message, 391 WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED, 392 WifiP2pManager.BUSY); 393 break; 394 case WifiP2pManager.SET_DEVICE_NAME: 395 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED, 396 WifiP2pManager.BUSY); 397 break; 398 case WifiP2pManager.REQUEST_PEERS: 399 replyToMessage(message, WifiP2pManager.RESPONSE_PEERS, mPeers); 400 break; 401 case WifiP2pManager.REQUEST_CONNECTION_INFO: 402 replyToMessage(message, WifiP2pManager.RESPONSE_CONNECTION_INFO, mWifiP2pInfo); 403 break; 404 case WifiP2pManager.REQUEST_GROUP_INFO: 405 replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO, mGroup); 406 break; 407 case WifiP2pManager.SET_DIALOG_LISTENER: 408 String appPkgName = (String)message.getData().getString( 409 WifiP2pManager.APP_PKG_BUNDLE_KEY); 410 boolean isReset = message.getData().getBoolean( 411 WifiP2pManager.RESET_DIALOG_LISTENER_BUNDLE_KEY); 412 if (setDialogListenerApp(message.replyTo, appPkgName, isReset)) { 413 replyToMessage(message, WifiP2pManager.DIALOG_LISTENER_ATTACHED); 414 } else { 415 replyToMessage(message, WifiP2pManager.DIALOG_LISTENER_DETACHED, 416 WifiP2pManager.NOT_IN_FOREGROUND); 417 } 418 break; 419 // Ignore 420 case WifiMonitor.P2P_INVITATION_RESULT_EVENT: 421 case WifiMonitor.SCAN_RESULTS_EVENT: 422 case WifiMonitor.SUP_CONNECTION_EVENT: 423 case WifiMonitor.SUP_DISCONNECTION_EVENT: 424 case WifiMonitor.NETWORK_CONNECTION_EVENT: 425 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 426 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 427 case WifiMonitor.P2P_GROUP_REMOVED_EVENT: 428 case WifiMonitor.P2P_DEVICE_FOUND_EVENT: 429 case WifiMonitor.P2P_DEVICE_LOST_EVENT: 430 case WifiMonitor.P2P_FIND_STOPPED_EVENT: 431 case WifiMonitor.P2P_SERV_DISC_RESP_EVENT: 432 case WifiStateMachine.CMD_ENABLE_P2P: 433 case WifiStateMachine.CMD_DISABLE_P2P: 434 case PEER_CONNECTION_USER_ACCEPT: 435 case PEER_CONNECTION_USER_REJECT: 436 case GROUP_CREATING_TIMED_OUT: 437 break; 438 /* unexpected group created, remove */ 439 case WifiMonitor.P2P_GROUP_STARTED_EVENT: 440 mGroup = (WifiP2pGroup) message.obj; 441 loge("Unexpected group creation, remove " + mGroup); 442 mWifiNative.p2pGroupRemove(mGroup.getInterface()); 443 break; 444 // A group formation failure is always followed by 445 // a group removed event. Flushing things at group formation 446 // failure causes supplicant issues. Ignore right now. 447 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT: 448 break; 449 default: 450 loge("Unhandled message " + message); 451 return NOT_HANDLED; 452 } 453 return HANDLED; 454 } 455 } 456 457 class P2pNotSupportedState extends State { 458 @Override 459 public boolean processMessage(Message message) { 460 switch (message.what) { 461 case WifiP2pManager.DISCOVER_PEERS: 462 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, 463 WifiP2pManager.P2P_UNSUPPORTED); 464 break; 465 case WifiP2pManager.STOP_DISCOVERY: 466 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, 467 WifiP2pManager.P2P_UNSUPPORTED); 468 break; 469 case WifiP2pManager.DISCOVER_SERVICES: 470 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, 471 WifiP2pManager.P2P_UNSUPPORTED); 472 break; 473 case WifiP2pManager.CONNECT: 474 replyToMessage(message, WifiP2pManager.CONNECT_FAILED, 475 WifiP2pManager.P2P_UNSUPPORTED); 476 break; 477 case WifiP2pManager.CANCEL_CONNECT: 478 replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED, 479 WifiP2pManager.P2P_UNSUPPORTED); 480 break; 481 case WifiP2pManager.CREATE_GROUP: 482 replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED, 483 WifiP2pManager.P2P_UNSUPPORTED); 484 break; 485 case WifiP2pManager.REMOVE_GROUP: 486 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED, 487 WifiP2pManager.P2P_UNSUPPORTED); 488 break; 489 case WifiP2pManager.ADD_LOCAL_SERVICE: 490 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED, 491 WifiP2pManager.P2P_UNSUPPORTED); 492 break; 493 case WifiP2pManager.SET_DIALOG_LISTENER: 494 replyToMessage(message, WifiP2pManager.DIALOG_LISTENER_DETACHED, 495 WifiP2pManager.P2P_UNSUPPORTED); 496 break; 497 case WifiP2pManager.REMOVE_LOCAL_SERVICE: 498 replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED, 499 WifiP2pManager.P2P_UNSUPPORTED); 500 break; 501 case WifiP2pManager.CLEAR_LOCAL_SERVICES: 502 replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED, 503 WifiP2pManager.P2P_UNSUPPORTED); 504 break; 505 case WifiP2pManager.ADD_SERVICE_REQUEST: 506 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED, 507 WifiP2pManager.P2P_UNSUPPORTED); 508 break; 509 case WifiP2pManager.REMOVE_SERVICE_REQUEST: 510 replyToMessage(message, 511 WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED, 512 WifiP2pManager.P2P_UNSUPPORTED); 513 break; 514 case WifiP2pManager.CLEAR_SERVICE_REQUESTS: 515 replyToMessage(message, 516 WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED, 517 WifiP2pManager.P2P_UNSUPPORTED); 518 break; 519 case WifiP2pManager.SET_DEVICE_NAME: 520 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED, 521 WifiP2pManager.P2P_UNSUPPORTED); 522 break; 523 default: 524 return NOT_HANDLED; 525 } 526 return HANDLED; 527 } 528 } 529 530 class P2pDisablingState extends State { 531 @Override 532 public boolean processMessage(Message message) { 533 if (DBG) logd(getName() + message.toString()); 534 switch (message.what) { 535 case WifiMonitor.SUP_DISCONNECTION_EVENT: 536 if (DBG) logd("p2p socket connection lost"); 537 transitionTo(mP2pDisabledState); 538 break; 539 case WifiStateMachine.CMD_ENABLE_P2P: 540 case WifiStateMachine.CMD_DISABLE_P2P: 541 deferMessage(message); 542 break; 543 default: 544 return NOT_HANDLED; 545 } 546 return HANDLED; 547 } 548 } 549 550 class P2pDisabledState extends State { 551 @Override 552 public void enter() { 553 if (DBG) logd(getName()); 554 } 555 556 @Override 557 public boolean processMessage(Message message) { 558 if (DBG) logd(getName() + message.toString()); 559 switch (message.what) { 560 case WifiStateMachine.CMD_ENABLE_P2P: 561 try { 562 mNwService.setInterfaceUp(mInterface); 563 } catch (RemoteException re) { 564 loge("Unable to change interface settings: " + re); 565 } catch (IllegalStateException ie) { 566 loge("Unable to change interface settings: " + ie); 567 } 568 mWifiMonitor.startMonitoring(); 569 transitionTo(mP2pEnablingState); 570 break; 571 case WifiStateMachine.CMD_DISABLE_P2P: 572 //Nothing to do 573 break; 574 default: 575 return NOT_HANDLED; 576 } 577 return HANDLED; 578 } 579 } 580 581 class P2pEnablingState extends State { 582 @Override 583 public void enter() { 584 if (DBG) logd(getName()); 585 } 586 587 @Override 588 public boolean processMessage(Message message) { 589 if (DBG) logd(getName() + message.toString()); 590 switch (message.what) { 591 case WifiMonitor.SUP_CONNECTION_EVENT: 592 if (DBG) logd("P2p socket connection successful"); 593 transitionTo(mInactiveState); 594 break; 595 case WifiMonitor.SUP_DISCONNECTION_EVENT: 596 loge("P2p socket connection failed"); 597 transitionTo(mP2pDisabledState); 598 break; 599 case WifiStateMachine.CMD_ENABLE_P2P: 600 case WifiStateMachine.CMD_DISABLE_P2P: 601 deferMessage(message); 602 break; 603 default: 604 return NOT_HANDLED; 605 } 606 return HANDLED; 607 } 608 } 609 610 class P2pEnabledState extends State { 611 @Override 612 public void enter() { 613 if (DBG) logd(getName()); 614 sendP2pStateChangedBroadcast(true); 615 mNetworkInfo.setIsAvailable(true); 616 sendP2pConnectionChangedBroadcast(); 617 initializeP2pSettings(); 618 } 619 620 @Override 621 public boolean processMessage(Message message) { 622 if (DBG) logd(getName() + message.toString()); 623 switch (message.what) { 624 case WifiStateMachine.CMD_ENABLE_P2P: 625 //Nothing to do 626 break; 627 case WifiStateMachine.CMD_DISABLE_P2P: 628 if (mPeers.clear()) sendP2pPeersChangedBroadcast(); 629 mWifiNative.closeSupplicantConnection(); 630 transitionTo(mP2pDisablingState); 631 break; 632 case WifiP2pManager.SET_DEVICE_NAME: 633 WifiP2pDevice d = (WifiP2pDevice) message.obj; 634 if (d != null && setAndPersistDeviceName(d.deviceName)) { 635 if (DBG) logd("set device name " + d.deviceName); 636 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_SUCCEEDED); 637 } else { 638 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED, 639 WifiP2pManager.ERROR); 640 } 641 break; 642 case WifiP2pManager.DISCOVER_PEERS: 643 // do not send service discovery request while normal find operation. 644 clearSupplicantServiceRequest(); 645 if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) { 646 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED); 647 sendP2pDiscoveryChangedBroadcast(true); 648 } else { 649 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, 650 WifiP2pManager.ERROR); 651 } 652 break; 653 case WifiMonitor.P2P_FIND_STOPPED_EVENT: 654 sendP2pDiscoveryChangedBroadcast(false); 655 break; 656 case WifiP2pManager.STOP_DISCOVERY: 657 if (mWifiNative.p2pStopFind()) { 658 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED); 659 } else { 660 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, 661 WifiP2pManager.ERROR); 662 } 663 break; 664 case WifiP2pManager.DISCOVER_SERVICES: 665 if (DBG) logd(getName() + " discover services"); 666 if (!updateSupplicantServiceRequest()) { 667 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, 668 WifiP2pManager.NO_SERVICE_REQUESTS); 669 break; 670 } 671 if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) { 672 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_SUCCEEDED); 673 } else { 674 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, 675 WifiP2pManager.ERROR); 676 } 677 break; 678 case WifiMonitor.P2P_DEVICE_FOUND_EVENT: 679 WifiP2pDevice device = (WifiP2pDevice) message.obj; 680 if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break; 681 mPeers.update(device); 682 sendP2pPeersChangedBroadcast(); 683 break; 684 case WifiMonitor.P2P_DEVICE_LOST_EVENT: 685 device = (WifiP2pDevice) message.obj; 686 if (mPeers.remove(device)) sendP2pPeersChangedBroadcast(); 687 break; 688 case WifiP2pManager.ADD_LOCAL_SERVICE: 689 if (DBG) logd(getName() + " add service"); 690 WifiP2pServiceInfo servInfo = (WifiP2pServiceInfo)message.obj; 691 if (addLocalService(message.replyTo, servInfo)) { 692 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_SUCCEEDED); 693 } else { 694 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED); 695 } 696 break; 697 case WifiP2pManager.REMOVE_LOCAL_SERVICE: 698 if (DBG) logd(getName() + " remove service"); 699 servInfo = (WifiP2pServiceInfo)message.obj; 700 removeLocalService(message.replyTo, servInfo); 701 replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_SUCCEEDED); 702 break; 703 case WifiP2pManager.CLEAR_LOCAL_SERVICES: 704 if (DBG) logd(getName() + " clear service"); 705 clearLocalServices(message.replyTo); 706 break; 707 case WifiP2pManager.ADD_SERVICE_REQUEST: 708 if (DBG) logd(getName() + " add service request"); 709 if (!addServiceRequest(message.replyTo, (WifiP2pServiceRequest)message.obj)) { 710 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED); 711 break; 712 } 713 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_SUCCEEDED); 714 break; 715 case WifiP2pManager.REMOVE_SERVICE_REQUEST: 716 if (DBG) logd(getName() + " remove service request"); 717 removeServiceRequest(message.replyTo, (WifiP2pServiceRequest)message.obj); 718 replyToMessage(message, WifiP2pManager.REMOVE_SERVICE_REQUEST_SUCCEEDED); 719 break; 720 case WifiP2pManager.CLEAR_SERVICE_REQUESTS: 721 if (DBG) logd(getName() + " clear service request"); 722 clearServiceRequests(message.replyTo); 723 replyToMessage(message, WifiP2pManager.CLEAR_SERVICE_REQUESTS_SUCCEEDED); 724 break; 725 case WifiMonitor.P2P_SERV_DISC_RESP_EVENT: 726 if (DBG) logd(getName() + " receive service response"); 727 List<WifiP2pServiceResponse> sdRespList = 728 (List<WifiP2pServiceResponse>) message.obj; 729 for (WifiP2pServiceResponse resp : sdRespList) { 730 WifiP2pDevice dev = 731 mPeers.get(resp.getSrcDevice().deviceAddress); 732 resp.setSrcDevice(dev); 733 sendServiceResponse(resp); 734 } 735 break; 736 default: 737 return NOT_HANDLED; 738 } 739 return HANDLED; 740 } 741 742 @Override 743 public void exit() { 744 sendP2pStateChangedBroadcast(false); 745 mNetworkInfo.setIsAvailable(false); 746 } 747 } 748 749 class InactiveState extends State { 750 @Override 751 public void enter() { 752 if (DBG) logd(getName()); 753 //Start listening every time we get inactive 754 //TODO: Fix listen after driver behavior is fixed 755 //mWifiNative.p2pListen(); 756 } 757 758 @Override 759 public boolean processMessage(Message message) { 760 if (DBG) logd(getName() + message.toString()); 761 switch (message.what) { 762 case WifiP2pManager.CONNECT: 763 if (DBG) logd(getName() + " sending connect"); 764 WifiP2pConfig config = (WifiP2pConfig) message.obj; 765 mAutonomousGroup = false; 766 767 if (mSavedPeerConfig != null && config.deviceAddress.equals( 768 mSavedPeerConfig.deviceAddress)) { 769 mSavedPeerConfig = config; 770 771 //Stop discovery before issuing connect 772 mWifiNative.p2pStopFind(); 773 if (mPeers.isGroupOwner(mSavedPeerConfig.deviceAddress)) { 774 p2pConnectWithPinDisplay(mSavedPeerConfig, JOIN_GROUP); 775 } else { 776 p2pConnectWithPinDisplay(mSavedPeerConfig, FORM_GROUP); 777 } 778 transitionTo(mGroupNegotiationState); 779 } else { 780 mSavedPeerConfig = config; 781 int netId = configuredNetworkId(mSavedPeerConfig.deviceAddress); 782 if (netId >= 0) { 783 //TODO: if failure, remove config and do a regular p2pConnect() 784 mWifiNative.p2pReinvoke(netId, mSavedPeerConfig.deviceAddress); 785 } else { 786 //Stop discovery before issuing connect 787 mWifiNative.p2pStopFind(); 788 //If peer is a GO, we do not need to send provisional discovery, 789 //the supplicant takes care of it. 790 if (mPeers.isGroupOwner(mSavedPeerConfig.deviceAddress)) { 791 if (DBG) logd("Sending join to GO"); 792 p2pConnectWithPinDisplay(mSavedPeerConfig, JOIN_GROUP); 793 transitionTo(mGroupNegotiationState); 794 } else { 795 if (DBG) logd("Sending prov disc"); 796 transitionTo(mProvisionDiscoveryState); 797 } 798 } 799 } 800 mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED); 801 sendP2pPeersChangedBroadcast(); 802 replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED); 803 break; 804 case WifiMonitor.P2P_GO_NEGOTIATION_REQUEST_EVENT: 805 mSavedPeerConfig = (WifiP2pConfig) message.obj; 806 807 mAutonomousGroup = false; 808 mJoinExistingGroup = false; 809 if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress), 810 mSavedPeerConfig)) { 811 transitionTo(mUserAuthorizingInvitationState); 812 } 813 break; 814 case WifiMonitor.P2P_INVITATION_RECEIVED_EVENT: 815 WifiP2pGroup group = (WifiP2pGroup) message.obj; 816 WifiP2pDevice owner = group.getOwner(); 817 818 if (owner == null) { 819 if (DBG) loge("Ignored invitation from null owner"); 820 break; 821 } 822 823 mSavedPeerConfig = new WifiP2pConfig(); 824 mSavedPeerConfig.deviceAddress = group.getOwner().deviceAddress; 825 826 //Check if we have the owner in peer list and use appropriate 827 //wps method. Default is to use PBC. 828 if ((owner = mPeers.get(owner.deviceAddress)) != null) { 829 if (owner.wpsPbcSupported()) { 830 mSavedPeerConfig.wps.setup = WpsInfo.PBC; 831 } else if (owner.wpsKeypadSupported()) { 832 mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD; 833 } else if (owner.wpsDisplaySupported()) { 834 mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY; 835 } 836 } 837 838 mAutonomousGroup = false; 839 mJoinExistingGroup = true; 840 //TODO In the p2p client case, we should set source address correctly. 841 if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress), 842 mSavedPeerConfig)) { 843 transitionTo(mUserAuthorizingInvitationState); 844 } 845 break; 846 case WifiMonitor.P2P_FIND_STOPPED_EVENT: 847 // When discovery stops in inactive state, flush to clear 848 // state peer data 849 mWifiNative.p2pFlush(); 850 mServiceDiscReqId = null; 851 sendP2pDiscoveryChangedBroadcast(false); 852 break; 853 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT: 854 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: 855 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: 856 //We let the supplicant handle the provision discovery response 857 //and wait instead for the GO_NEGOTIATION_REQUEST_EVENT. 858 //Handling provision discovery and issuing a p2p_connect before 859 //group negotiation comes through causes issues 860 break; 861 case WifiP2pManager.CREATE_GROUP: 862 mAutonomousGroup = true; 863 if (mWifiNative.p2pGroupAdd()) { 864 replyToMessage(message, WifiP2pManager.CREATE_GROUP_SUCCEEDED); 865 } else { 866 replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED, 867 WifiP2pManager.ERROR); 868 } 869 transitionTo(mGroupNegotiationState); 870 break; 871 default: 872 return NOT_HANDLED; 873 } 874 return HANDLED; 875 } 876 } 877 878 class GroupCreatingState extends State { 879 @Override 880 public void enter() { 881 if (DBG) logd(getName()); 882 sendMessageDelayed(obtainMessage(GROUP_CREATING_TIMED_OUT, 883 ++mGroupCreatingTimeoutIndex, 0), GROUP_CREATING_WAIT_TIME_MS); 884 } 885 886 @Override 887 public boolean processMessage(Message message) { 888 if (DBG) logd(getName() + message.toString()); 889 boolean ret = HANDLED; 890 switch (message.what) { 891 case GROUP_CREATING_TIMED_OUT: 892 if (mGroupCreatingTimeoutIndex == message.arg1) { 893 if (DBG) logd("Group negotiation timed out"); 894 handleGroupCreationFailure(); 895 transitionTo(mInactiveState); 896 } 897 break; 898 case WifiMonitor.P2P_DEVICE_LOST_EVENT: 899 WifiP2pDevice device = (WifiP2pDevice) message.obj; 900 if (!mSavedPeerConfig.deviceAddress.equals(device.deviceAddress)) { 901 // Do the regular device lost handling 902 ret = NOT_HANDLED; 903 break; 904 } 905 // Do nothing 906 if (DBG) logd("Retain connecting device " + device); 907 break; 908 case WifiP2pManager.DISCOVER_PEERS: 909 /* Discovery will break negotiation */ 910 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, 911 WifiP2pManager.BUSY); 912 break; 913 case WifiP2pManager.CANCEL_CONNECT: 914 //Do a supplicant p2p_cancel which only cancels an ongoing 915 //group negotiation. This will fail for a pending provision 916 //discovery or for a pending user action, but at the framework 917 //level, we always treat cancel as succeeded and enter 918 //an inactive state 919 mWifiNative.p2pCancelConnect(); 920 handleGroupCreationFailure(); 921 transitionTo(mInactiveState); 922 replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_SUCCEEDED); 923 break; 924 default: 925 ret = NOT_HANDLED; 926 } 927 return ret; 928 } 929 } 930 931 class UserAuthorizingInvitationState extends State { 932 @Override 933 public void enter() { 934 if (DBG) logd(getName()); 935 if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress), 936 mSavedPeerConfig)) { 937 notifyInvitationReceived(); 938 } 939 } 940 941 @Override 942 public boolean processMessage(Message message) { 943 if (DBG) logd(getName() + message.toString()); 944 boolean ret = HANDLED; 945 switch (message.what) { 946 case PEER_CONNECTION_USER_ACCEPT: 947 //TODO: handle persistence 948 if (mJoinExistingGroup) { 949 p2pConnectWithPinDisplay(mSavedPeerConfig, JOIN_GROUP); 950 } else { 951 p2pConnectWithPinDisplay(mSavedPeerConfig, FORM_GROUP); 952 } 953 mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED); 954 sendP2pPeersChangedBroadcast(); 955 transitionTo(mGroupNegotiationState); 956 break; 957 case PEER_CONNECTION_USER_REJECT: 958 if (DBG) logd("User rejected invitation " + mSavedPeerConfig); 959 mSavedPeerConfig = null; 960 transitionTo(mInactiveState); 961 break; 962 default: 963 return NOT_HANDLED; 964 } 965 return ret; 966 } 967 968 @Override 969 public void exit() { 970 //TODO: dismiss dialog if not already done 971 } 972 } 973 974 class ProvisionDiscoveryState extends State { 975 @Override 976 public void enter() { 977 if (DBG) logd(getName()); 978 mWifiNative.p2pProvisionDiscovery(mSavedPeerConfig); 979 } 980 981 @Override 982 public boolean processMessage(Message message) { 983 if (DBG) logd(getName() + message.toString()); 984 WifiP2pProvDiscEvent provDisc; 985 WifiP2pDevice device; 986 switch (message.what) { 987 case WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT: 988 provDisc = (WifiP2pProvDiscEvent) message.obj; 989 device = provDisc.device; 990 if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break; 991 992 if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) { 993 if (DBG) logd("Found a match " + mSavedPeerConfig); 994 mWifiNative.p2pConnect(mSavedPeerConfig, FORM_GROUP); 995 transitionTo(mGroupNegotiationState); 996 } 997 break; 998 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: 999 provDisc = (WifiP2pProvDiscEvent) message.obj; 1000 device = provDisc.device; 1001 if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break; 1002 1003 if (mSavedPeerConfig.wps.setup == WpsInfo.KEYPAD) { 1004 if (DBG) logd("Found a match " + mSavedPeerConfig); 1005 /* we already have the pin */ 1006 if (!TextUtils.isEmpty(mSavedPeerConfig.wps.pin)) { 1007 mWifiNative.p2pConnect(mSavedPeerConfig, FORM_GROUP); 1008 transitionTo(mGroupNegotiationState); 1009 } else { 1010 mJoinExistingGroup = false; 1011 transitionTo(mUserAuthorizingInvitationState); 1012 } 1013 } 1014 break; 1015 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: 1016 provDisc = (WifiP2pProvDiscEvent) message.obj; 1017 device = provDisc.device; 1018 if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break; 1019 1020 if (mSavedPeerConfig.wps.setup == WpsInfo.DISPLAY) { 1021 if (DBG) logd("Found a match " + mSavedPeerConfig); 1022 mSavedPeerConfig.wps.pin = provDisc.pin; 1023 mWifiNative.p2pConnect(mSavedPeerConfig, FORM_GROUP); 1024 if (!sendShowPinReqToFrontApp(provDisc.pin)) { 1025 notifyInvitationSent(provDisc.pin, device.deviceAddress); 1026 } 1027 transitionTo(mGroupNegotiationState); 1028 } 1029 break; 1030 default: 1031 return NOT_HANDLED; 1032 } 1033 return HANDLED; 1034 } 1035 } 1036 1037 class GroupNegotiationState extends State { 1038 @Override 1039 public void enter() { 1040 if (DBG) logd(getName()); 1041 } 1042 1043 @Override 1044 public boolean processMessage(Message message) { 1045 if (DBG) logd(getName() + message.toString()); 1046 switch (message.what) { 1047 // We ignore these right now, since we get a GROUP_STARTED notification 1048 // afterwards 1049 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT: 1050 case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT: 1051 if (DBG) logd(getName() + " go success"); 1052 break; 1053 case WifiMonitor.P2P_GROUP_STARTED_EVENT: 1054 mGroup = (WifiP2pGroup) message.obj; 1055 if (DBG) logd(getName() + " group started"); 1056 if (mGroup.isGroupOwner()) { 1057 startDhcpServer(mGroup.getInterface()); 1058 } else { 1059 // Set group idle only for a client on the group interface to speed up 1060 // disconnect when GO is gone. Setting group idle time for a group owner 1061 // causes connectivity issues for new clients 1062 mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S); 1063 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(mContext, 1064 P2pStateMachine.this, mGroup.getInterface()); 1065 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); 1066 WifiP2pDevice groupOwner = mGroup.getOwner(); 1067 mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED); 1068 sendP2pPeersChangedBroadcast(); 1069 } 1070 mSavedPeerConfig = null; 1071 transitionTo(mGroupCreatedState); 1072 break; 1073 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT: 1074 case WifiMonitor.P2P_GROUP_REMOVED_EVENT: 1075 if (DBG) logd(getName() + " go failure"); 1076 handleGroupCreationFailure(); 1077 transitionTo(mInactiveState); 1078 break; 1079 // A group formation failure is always followed by 1080 // a group removed event. Flushing things at group formation 1081 // failure causes supplicant issues. Ignore right now. 1082 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT: 1083 break; 1084 default: 1085 return NOT_HANDLED; 1086 } 1087 return HANDLED; 1088 } 1089 } 1090 1091 1092 1093 class GroupCreatedState extends State { 1094 @Override 1095 public void enter() { 1096 if (DBG) logd(getName()); 1097 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null); 1098 1099 updateThisDevice(WifiP2pDevice.CONNECTED); 1100 1101 //DHCP server has already been started if I am a group owner 1102 if (mGroup.isGroupOwner()) { 1103 setWifiP2pInfoOnGroupFormation(SERVER_ADDRESS); 1104 sendP2pConnectionChangedBroadcast(); 1105 } 1106 } 1107 1108 @Override 1109 public boolean processMessage(Message message) { 1110 if (DBG) logd(getName() + message.toString()); 1111 switch (message.what) { 1112 case WifiMonitor.AP_STA_CONNECTED_EVENT: 1113 WifiP2pDevice device = (WifiP2pDevice) message.obj; 1114 String deviceAddress = device.deviceAddress; 1115 if (deviceAddress != null) { 1116 if (mSavedProvDiscDevice != null && 1117 deviceAddress.equals(mSavedProvDiscDevice.deviceAddress)) { 1118 mSavedProvDiscDevice = null; 1119 } 1120 mGroup.addClient(deviceAddress); 1121 mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED); 1122 if (DBG) logd(getName() + " ap sta connected"); 1123 sendP2pPeersChangedBroadcast(); 1124 } else { 1125 loge("Connect on null device address, ignore"); 1126 } 1127 break; 1128 case WifiMonitor.AP_STA_DISCONNECTED_EVENT: 1129 device = (WifiP2pDevice) message.obj; 1130 deviceAddress = device.deviceAddress; 1131 if (deviceAddress != null) { 1132 mPeers.updateStatus(deviceAddress, WifiP2pDevice.AVAILABLE); 1133 if (mGroup.removeClient(deviceAddress)) { 1134 if (DBG) logd("Removed client " + deviceAddress); 1135 if (!mAutonomousGroup && mGroup.isClientListEmpty()) { 1136 Slog.d(TAG, "Client list empty, remove non-persistent p2p group"); 1137 mWifiNative.p2pGroupRemove(mGroup.getInterface()); 1138 } 1139 } else { 1140 if (DBG) logd("Failed to remove client " + deviceAddress); 1141 for (WifiP2pDevice c : mGroup.getClientList()) { 1142 if (DBG) logd("client " + c.deviceAddress); 1143 } 1144 } 1145 sendP2pPeersChangedBroadcast(); 1146 if (DBG) loge(getName() + " ap sta disconnected"); 1147 } else { 1148 loge("Disconnect on unknown device: " + device); 1149 } 1150 break; 1151 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 1152 DhcpInfoInternal dhcpInfo = (DhcpInfoInternal) message.obj; 1153 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS && 1154 dhcpInfo != null) { 1155 if (DBG) logd("DhcpInfo: " + dhcpInfo); 1156 setWifiP2pInfoOnGroupFormation(dhcpInfo.serverAddress); 1157 sendP2pConnectionChangedBroadcast(); 1158 //Turn on power save on client 1159 mWifiNative.setP2pPowerSave(mGroup.getInterface(), true); 1160 } else { 1161 loge("DHCP failed"); 1162 mWifiNative.p2pGroupRemove(mGroup.getInterface()); 1163 } 1164 break; 1165 case WifiP2pManager.REMOVE_GROUP: 1166 if (DBG) loge(getName() + " remove group"); 1167 if (mWifiNative.p2pGroupRemove(mGroup.getInterface())) { 1168 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED); 1169 } else { 1170 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED, 1171 WifiP2pManager.ERROR); 1172 } 1173 break; 1174 case WifiMonitor.P2P_GROUP_REMOVED_EVENT: 1175 if (DBG) loge(getName() + " group removed"); 1176 Collection <WifiP2pDevice> devices = mGroup.getClientList(); 1177 boolean changed = false; 1178 for (WifiP2pDevice d : mPeers.getDeviceList()) { 1179 if (devices.contains(d) || mGroup.getOwner().equals(d)) { 1180 d.status = WifiP2pDevice.AVAILABLE; 1181 changed = true; 1182 } 1183 } 1184 1185 if (mGroup.isGroupOwner()) { 1186 stopDhcpServer(); 1187 } else { 1188 if (DBG) logd("stop DHCP client"); 1189 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); 1190 mDhcpStateMachine.quit(); 1191 mDhcpStateMachine = null; 1192 } 1193 1194 mGroup = null; 1195 mWifiNative.p2pFlush(); 1196 mServiceDiscReqId = null; 1197 if (changed) sendP2pPeersChangedBroadcast(); 1198 transitionTo(mInactiveState); 1199 break; 1200 case WifiMonitor.P2P_DEVICE_LOST_EVENT: 1201 device = (WifiP2pDevice) message.obj; 1202 //Device loss for a connected device indicates it is not in discovery any more 1203 if (mGroup.contains(device)) { 1204 if (DBG) logd("Lost " + device +" , do nothing"); 1205 return HANDLED; 1206 } 1207 // Do the regular device lost handling 1208 return NOT_HANDLED; 1209 case WifiStateMachine.CMD_DISABLE_P2P: 1210 sendMessage(WifiP2pManager.REMOVE_GROUP); 1211 deferMessage(message); 1212 break; 1213 case WifiP2pManager.CONNECT: 1214 WifiP2pConfig config = (WifiP2pConfig) message.obj; 1215 if (config.deviceAddress == null || 1216 (mSavedProvDiscDevice != null && 1217 mSavedProvDiscDevice.deviceAddress.equals( 1218 config.deviceAddress))) { 1219 if (config.wps.setup == WpsInfo.PBC) { 1220 mWifiNative.startWpsPbc(mGroup.getInterface(), null); 1221 } else { 1222 if (config.wps.pin == null) { 1223 String pin = mWifiNative.startWpsPinDisplay(mGroup.getInterface()); 1224 try { 1225 Integer.parseInt(pin); 1226 if (!sendShowPinReqToFrontApp(pin)) { 1227 notifyInvitationSent(pin, 1228 config.deviceAddress != null ? 1229 config.deviceAddress : "any"); 1230 } 1231 } catch (NumberFormatException ignore) { 1232 // do nothing if pin is invalid 1233 } 1234 } else { 1235 mWifiNative.startWpsPinKeypad(mGroup.getInterface(), 1236 config.wps.pin); 1237 } 1238 } 1239 if (config.deviceAddress != null) { 1240 mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED); 1241 sendP2pPeersChangedBroadcast(); 1242 } 1243 replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED); 1244 } else { 1245 logd("Inviting device : " + config.deviceAddress); 1246 if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) { 1247 mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED); 1248 sendP2pPeersChangedBroadcast(); 1249 replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED); 1250 } else { 1251 replyToMessage(message, WifiP2pManager.CONNECT_FAILED, 1252 WifiP2pManager.ERROR); 1253 } 1254 } 1255 // TODO: figure out updating the status to declined when invitation is rejected 1256 break; 1257 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT: 1258 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: 1259 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: 1260 WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj; 1261 mSavedProvDiscDevice = provDisc.device; 1262 mSavedPeerConfig = new WifiP2pConfig(); 1263 mSavedPeerConfig.deviceAddress = provDisc.device.deviceAddress; 1264 if (message.what == WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) { 1265 mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD; 1266 } else if (message.what == WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT) { 1267 mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY; 1268 mSavedPeerConfig.wps.pin = provDisc.pin; 1269 } else { 1270 mSavedPeerConfig.wps.setup = WpsInfo.PBC; 1271 } 1272 if (!sendConnectNoticeToApp(mSavedProvDiscDevice, mSavedPeerConfig)) { 1273 transitionTo(mUserAuthorizingJoinState); 1274 } 1275 break; 1276 case WifiMonitor.P2P_GROUP_STARTED_EVENT: 1277 Slog.e(TAG, "Duplicate group creation event notice, ignore"); 1278 break; 1279 default: 1280 return NOT_HANDLED; 1281 } 1282 return HANDLED; 1283 } 1284 1285 public void exit() { 1286 mSavedProvDiscDevice = null; 1287 updateThisDevice(WifiP2pDevice.AVAILABLE); 1288 setWifiP2pInfoOnGroupTermination(); 1289 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null); 1290 sendP2pConnectionChangedBroadcast(); 1291 } 1292 } 1293 1294 class UserAuthorizingJoinState extends State { 1295 @Override 1296 public void enter() { 1297 if (DBG) logd(getName()); 1298 1299 notifyInvitationReceived(); 1300 } 1301 1302 @Override 1303 public boolean processMessage(Message message) { 1304 if (DBG) logd(getName() + message.toString()); 1305 switch (message.what) { 1306 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT: 1307 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: 1308 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: 1309 //Ignore more client requests 1310 break; 1311 case PEER_CONNECTION_USER_ACCEPT: 1312 if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) { 1313 mWifiNative.startWpsPbc(mGroup.getInterface(), null); 1314 } else { 1315 mWifiNative.startWpsPinKeypad(mGroup.getInterface(), 1316 mSavedPeerConfig.wps.pin); 1317 } 1318 mSavedPeerConfig = null; 1319 transitionTo(mGroupCreatedState); 1320 break; 1321 case PEER_CONNECTION_USER_REJECT: 1322 if (DBG) logd("User rejected incoming request"); 1323 mSavedPeerConfig = null; 1324 transitionTo(mGroupCreatedState); 1325 break; 1326 default: 1327 return NOT_HANDLED; 1328 } 1329 return HANDLED; 1330 } 1331 1332 @Override 1333 public void exit() { 1334 //TODO: dismiss dialog if not already done 1335 } 1336 } 1337 1338 private void sendP2pStateChangedBroadcast(boolean enabled) { 1339 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); 1340 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1341 if (enabled) { 1342 intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE, 1343 WifiP2pManager.WIFI_P2P_STATE_ENABLED); 1344 } else { 1345 intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE, 1346 WifiP2pManager.WIFI_P2P_STATE_DISABLED); 1347 } 1348 mContext.sendStickyBroadcast(intent); 1349 } 1350 1351 private void sendP2pDiscoveryChangedBroadcast(boolean started) { 1352 if (mDiscoveryStarted == started) return; 1353 mDiscoveryStarted = started; 1354 1355 if (DBG) logd("discovery change broadcast " + started); 1356 1357 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION); 1358 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1359 intent.putExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE, started ? 1360 WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED : 1361 WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED); 1362 mContext.sendStickyBroadcast(intent); 1363 } 1364 1365 private void sendThisDeviceChangedBroadcast() { 1366 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); 1367 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1368 intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE, new WifiP2pDevice(mThisDevice)); 1369 mContext.sendStickyBroadcast(intent); 1370 } 1371 1372 private void sendP2pPeersChangedBroadcast() { 1373 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); 1374 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1375 mContext.sendBroadcast(intent); 1376 } 1377 1378 private void sendP2pConnectionChangedBroadcast() { 1379 if (DBG) logd("sending p2p connection changed broadcast"); 1380 Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); 1381 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 1382 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 1383 intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, new WifiP2pInfo(mWifiP2pInfo)); 1384 intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); 1385 mContext.sendStickyBroadcast(intent); 1386 } 1387 1388 private void startDhcpServer(String intf) { 1389 InterfaceConfiguration ifcg = null; 1390 try { 1391 ifcg = mNwService.getInterfaceConfig(intf); 1392 ifcg.setLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress( 1393 SERVER_ADDRESS), 24)); 1394 ifcg.setInterfaceUp(); 1395 mNwService.setInterfaceConfig(intf, ifcg); 1396 /* This starts the dnsmasq server */ 1397 mNwService.startTethering(DHCP_RANGE); 1398 } catch (Exception e) { 1399 loge("Error configuring interface " + intf + ", :" + e); 1400 return; 1401 } 1402 1403 logd("Started Dhcp server on " + intf); 1404 } 1405 1406 private void stopDhcpServer() { 1407 try { 1408 mNwService.stopTethering(); 1409 } catch (Exception e) { 1410 loge("Error stopping Dhcp server" + e); 1411 return; 1412 } 1413 1414 logd("Stopped Dhcp server"); 1415 } 1416 1417 private void notifyP2pEnableFailure() { 1418 Resources r = Resources.getSystem(); 1419 AlertDialog dialog = new AlertDialog.Builder(mContext) 1420 .setTitle(r.getString(R.string.wifi_p2p_dialog_title)) 1421 .setMessage(r.getString(R.string.wifi_p2p_failed_message)) 1422 .setPositiveButton(r.getString(R.string.ok), null) 1423 .create(); 1424 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 1425 dialog.show(); 1426 } 1427 1428 private void addRowToDialog(ViewGroup group, int stringId, String value) { 1429 Resources r = Resources.getSystem(); 1430 View row = LayoutInflater.from(mContext).inflate(R.layout.wifi_p2p_dialog_row, 1431 group, false); 1432 ((TextView) row.findViewById(R.id.name)).setText(r.getString(stringId)); 1433 ((TextView) row.findViewById(R.id.value)).setText(value); 1434 group.addView(row); 1435 } 1436 1437 private void notifyInvitationSent(String pin, String peerAddress) { 1438 Resources r = Resources.getSystem(); 1439 1440 final View textEntryView = LayoutInflater.from(mContext) 1441 .inflate(R.layout.wifi_p2p_dialog, null); 1442 1443 ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info); 1444 addRowToDialog(group, R.string.wifi_p2p_to_message, getDeviceName(peerAddress)); 1445 addRowToDialog(group, R.string.wifi_p2p_show_pin_message, pin); 1446 1447 AlertDialog dialog = new AlertDialog.Builder(mContext) 1448 .setTitle(r.getString(R.string.wifi_p2p_invitation_sent_title)) 1449 .setView(textEntryView) 1450 .setPositiveButton(r.getString(R.string.ok), null) 1451 .create(); 1452 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 1453 dialog.show(); 1454 } 1455 1456 private void notifyInvitationReceived() { 1457 Resources r = Resources.getSystem(); 1458 final WpsInfo wps = mSavedPeerConfig.wps; 1459 final View textEntryView = LayoutInflater.from(mContext) 1460 .inflate(R.layout.wifi_p2p_dialog, null); 1461 1462 ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info); 1463 addRowToDialog(group, R.string.wifi_p2p_from_message, getDeviceName( 1464 mSavedPeerConfig.deviceAddress)); 1465 1466 final EditText pin = (EditText) textEntryView.findViewById(R.id.wifi_p2p_wps_pin); 1467 1468 AlertDialog dialog = new AlertDialog.Builder(mContext) 1469 .setTitle(r.getString(R.string.wifi_p2p_invitation_to_connect_title)) 1470 .setView(textEntryView) 1471 .setPositiveButton(r.getString(R.string.accept), new OnClickListener() { 1472 public void onClick(DialogInterface dialog, int which) { 1473 if (wps.setup == WpsInfo.KEYPAD) { 1474 mSavedPeerConfig.wps.pin = pin.getText().toString(); 1475 } 1476 if (DBG) logd(getName() + " accept invitation " + mSavedPeerConfig); 1477 sendMessage(PEER_CONNECTION_USER_ACCEPT); 1478 } 1479 }) 1480 .setNegativeButton(r.getString(R.string.decline), new OnClickListener() { 1481 @Override 1482 public void onClick(DialogInterface dialog, int which) { 1483 if (DBG) logd(getName() + " ignore connect"); 1484 sendMessage(PEER_CONNECTION_USER_REJECT); 1485 } 1486 }) 1487 .setOnCancelListener(new DialogInterface.OnCancelListener() { 1488 @Override 1489 public void onCancel(DialogInterface arg0) { 1490 if (DBG) logd(getName() + " ignore connect"); 1491 sendMessage(PEER_CONNECTION_USER_REJECT); 1492 } 1493 }) 1494 .create(); 1495 1496 //make the enter pin area or the display pin area visible 1497 switch (wps.setup) { 1498 case WpsInfo.KEYPAD: 1499 if (DBG) logd("Enter pin section visible"); 1500 textEntryView.findViewById(R.id.enter_pin_section).setVisibility(View.VISIBLE); 1501 break; 1502 case WpsInfo.DISPLAY: 1503 if (DBG) logd("Shown pin section visible"); 1504 addRowToDialog(group, R.string.wifi_p2p_show_pin_message, wps.pin); 1505 break; 1506 default: 1507 break; 1508 } 1509 1510 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 1511 dialog.show(); 1512 } 1513 1514 //TODO: implement when wpa_supplicant is fixed 1515 private int configuredNetworkId(String deviceAddress) { 1516 return -1; 1517 } 1518 1519 private void setWifiP2pInfoOnGroupFormation(String serverAddress) { 1520 mWifiP2pInfo.groupFormed = true; 1521 mWifiP2pInfo.isGroupOwner = mGroup.isGroupOwner(); 1522 mWifiP2pInfo.groupOwnerAddress = NetworkUtils.numericToInetAddress(serverAddress); 1523 } 1524 1525 private void setWifiP2pInfoOnGroupTermination() { 1526 mWifiP2pInfo.groupFormed = false; 1527 mWifiP2pInfo.isGroupOwner = false; 1528 mWifiP2pInfo.groupOwnerAddress = null; 1529 } 1530 1531 private String getDeviceName(String deviceAddress) { 1532 WifiP2pDevice d = mPeers.get(deviceAddress); 1533 if (d != null) { 1534 return d.deviceName; 1535 } 1536 //Treat the address as name if there is no match 1537 return deviceAddress; 1538 } 1539 1540 private void p2pConnectWithPinDisplay(WifiP2pConfig config, boolean join) { 1541 String pin = mWifiNative.p2pConnect(config, join); 1542 try { 1543 Integer.parseInt(pin); 1544 if (!sendShowPinReqToFrontApp(pin)) { 1545 notifyInvitationSent(pin, config.deviceAddress); 1546 } 1547 } catch (NumberFormatException ignore) { 1548 // do nothing if p2pConnect did not return a pin 1549 } 1550 } 1551 1552 private String getPersistedDeviceName() { 1553 String deviceName = Settings.Secure.getString(mContext.getContentResolver(), 1554 Settings.Secure.WIFI_P2P_DEVICE_NAME); 1555 if (deviceName == null) { 1556 /* We use the 4 digits of the ANDROID_ID to have a friendly 1557 * default that has low likelihood of collision with a peer */ 1558 String id = Settings.Secure.getString(mContext.getContentResolver(), 1559 Settings.Secure.ANDROID_ID); 1560 return "Android_" + id.substring(0,4); 1561 } 1562 return deviceName; 1563 } 1564 1565 private boolean setAndPersistDeviceName(String devName) { 1566 if (devName == null) return false; 1567 1568 if (!mWifiNative.setDeviceName(devName)) { 1569 loge("Failed to set device name " + devName); 1570 return false; 1571 } 1572 1573 mThisDevice.deviceName = devName; 1574 mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName); 1575 1576 Settings.Secure.putString(mContext.getContentResolver(), 1577 Settings.Secure.WIFI_P2P_DEVICE_NAME, devName); 1578 sendThisDeviceChangedBroadcast(); 1579 return true; 1580 } 1581 1582 private void initializeP2pSettings() { 1583 mWifiNative.setPersistentReconnect(true); 1584 mThisDevice.deviceName = getPersistedDeviceName(); 1585 mWifiNative.setDeviceName(mThisDevice.deviceName); 1586 // DIRECT-XY-DEVICENAME (XY is randomly generated) 1587 mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName); 1588 mWifiNative.setDeviceType(mThisDevice.primaryDeviceType); 1589 // Supplicant defaults to using virtual display with display 1590 // which refers to a remote display. Use physical_display 1591 mWifiNative.setConfigMethods("virtual_push_button physical_display keypad"); 1592 // STA has higher priority over P2P 1593 mWifiNative.setConcurrencyPriority("sta"); 1594 1595 mThisDevice.deviceAddress = mWifiNative.p2pGetDeviceAddress(); 1596 updateThisDevice(WifiP2pDevice.AVAILABLE); 1597 if (DBG) Slog.d(TAG, "DeviceAddress: " + mThisDevice.deviceAddress); 1598 1599 mClientInfoList.clear(); 1600 mWifiNative.p2pFlush(); 1601 mWifiNative.p2pServiceFlush(); 1602 mServiceTransactionId = 0; 1603 mServiceDiscReqId = null; 1604 } 1605 1606 private void updateThisDevice(int status) { 1607 mThisDevice.status = status; 1608 sendThisDeviceChangedBroadcast(); 1609 } 1610 1611 private void handleGroupCreationFailure() { 1612 mSavedPeerConfig = null; 1613 /* After cancelling group formation, new connections on existing peers can fail 1614 * at supplicant. Flush and restart discovery */ 1615 mWifiNative.p2pFlush(); 1616 mServiceDiscReqId = null; 1617 sendMessage(WifiP2pManager.DISCOVER_PEERS); 1618 } 1619 1620 //State machine initiated requests can have replyTo set to null indicating 1621 //there are no recipients, we ignore those reply actions 1622 private void replyToMessage(Message msg, int what) { 1623 if (msg.replyTo == null) return; 1624 Message dstMsg = obtainMessage(msg); 1625 dstMsg.what = what; 1626 mReplyChannel.replyToMessage(msg, dstMsg); 1627 } 1628 1629 private void replyToMessage(Message msg, int what, int arg1) { 1630 if (msg.replyTo == null) return; 1631 Message dstMsg = obtainMessage(msg); 1632 dstMsg.what = what; 1633 dstMsg.arg1 = arg1; 1634 mReplyChannel.replyToMessage(msg, dstMsg); 1635 } 1636 1637 private void replyToMessage(Message msg, int what, Object obj) { 1638 if (msg.replyTo == null) return; 1639 Message dstMsg = obtainMessage(msg); 1640 dstMsg.what = what; 1641 dstMsg.obj = obj; 1642 mReplyChannel.replyToMessage(msg, dstMsg); 1643 } 1644 1645 /* arg2 on the source message has a hash code that needs to be retained in replies 1646 * see WifiP2pManager for details */ 1647 private Message obtainMessage(Message srcMsg) { 1648 Message msg = Message.obtain(); 1649 msg.arg2 = srcMsg.arg2; 1650 return msg; 1651 } 1652 1653 private void logd(String s) { 1654 Slog.d(TAG, s); 1655 } 1656 1657 private void loge(String s) { 1658 Slog.e(TAG, s); 1659 } 1660 1661 /** 1662 * Update service discovery request to wpa_supplicant. 1663 */ 1664 private boolean updateSupplicantServiceRequest() { 1665 clearSupplicantServiceRequest(); 1666 1667 StringBuffer sb = new StringBuffer(); 1668 for (ClientInfo c: mClientInfoList.values()) { 1669 int key; 1670 WifiP2pServiceRequest req; 1671 for (int i=0; i < c.mReqList.size(); i++) { 1672 req = c.mReqList.valueAt(i); 1673 if (req != null) { 1674 sb.append(req.getSupplicantQuery()); 1675 } 1676 } 1677 } 1678 1679 if (sb.length() == 0) { 1680 return false; 1681 } 1682 1683 mServiceDiscReqId = mWifiNative.p2pServDiscReq("00:00:00:00:00:00", sb.toString()); 1684 if (mServiceDiscReqId == null) { 1685 return false; 1686 } 1687 return true; 1688 } 1689 1690 /** 1691 * Clear service discovery request in wpa_supplicant 1692 */ 1693 private void clearSupplicantServiceRequest() { 1694 if (mServiceDiscReqId == null) return; 1695 1696 mWifiNative.p2pServDiscCancelReq(mServiceDiscReqId); 1697 mServiceDiscReqId = null; 1698 } 1699 1700 /* TODO: We could track individual service adds separately and avoid 1701 * having to do update all service requests on every new request 1702 */ 1703 private boolean addServiceRequest(Messenger m, WifiP2pServiceRequest req) { 1704 clearClientDeadChannels(); 1705 ClientInfo clientInfo = getClientInfo(m, true); 1706 if (clientInfo == null) { 1707 return false; 1708 } 1709 1710 ++mServiceTransactionId; 1711 //The Wi-Fi p2p spec says transaction id should be non-zero 1712 if (mServiceTransactionId == 0) ++mServiceTransactionId; 1713 req.setTransactionId(mServiceTransactionId); 1714 clientInfo.mReqList.put(mServiceTransactionId, req); 1715 1716 if (mServiceDiscReqId == null) { 1717 return true; 1718 } 1719 1720 return updateSupplicantServiceRequest(); 1721 } 1722 1723 private void removeServiceRequest(Messenger m, WifiP2pServiceRequest req) { 1724 ClientInfo clientInfo = getClientInfo(m, false); 1725 if (clientInfo == null) { 1726 return; 1727 } 1728 1729 //Application does not have transaction id information 1730 //go through stored requests to remove 1731 boolean removed = false; 1732 for (int i=0; i < clientInfo.mReqList.size(); i++) { 1733 if (req.equals(clientInfo.mReqList.valueAt(i))) { 1734 removed = true; 1735 clientInfo.mReqList.removeAt(i); 1736 break; 1737 } 1738 } 1739 1740 if (!removed) return; 1741 1742 if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) { 1743 if (DBG) logd("remove client information from framework"); 1744 mClientInfoList.remove(clientInfo.mMessenger); 1745 } 1746 1747 if (mServiceDiscReqId == null) { 1748 return; 1749 } 1750 1751 updateSupplicantServiceRequest(); 1752 } 1753 1754 private void clearServiceRequests(Messenger m) { 1755 1756 ClientInfo clientInfo = getClientInfo(m, false); 1757 if (clientInfo == null) { 1758 return; 1759 } 1760 1761 if (clientInfo.mReqList.size() == 0) { 1762 return; 1763 } 1764 1765 clientInfo.mReqList.clear(); 1766 1767 if (clientInfo.mServList.size() == 0) { 1768 if (DBG) logd("remove channel information from framework"); 1769 mClientInfoList.remove(clientInfo.mMessenger); 1770 } 1771 1772 if (mServiceDiscReqId == null) { 1773 return; 1774 } 1775 1776 updateSupplicantServiceRequest(); 1777 } 1778 1779 private boolean addLocalService(Messenger m, WifiP2pServiceInfo servInfo) { 1780 clearClientDeadChannels(); 1781 ClientInfo clientInfo = getClientInfo(m, true); 1782 if (clientInfo == null) { 1783 return false; 1784 } 1785 1786 if (!clientInfo.mServList.add(servInfo)) { 1787 return false; 1788 } 1789 1790 if (!mWifiNative.p2pServiceAdd(servInfo)) { 1791 clientInfo.mServList.remove(servInfo); 1792 return false; 1793 } 1794 1795 return true; 1796 } 1797 1798 private void removeLocalService(Messenger m, WifiP2pServiceInfo servInfo) { 1799 ClientInfo clientInfo = getClientInfo(m, false); 1800 if (clientInfo == null) { 1801 return; 1802 } 1803 1804 mWifiNative.p2pServiceDel(servInfo); 1805 1806 clientInfo.mServList.remove(servInfo); 1807 if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) { 1808 if (DBG) logd("remove client information from framework"); 1809 mClientInfoList.remove(clientInfo.mMessenger); 1810 } 1811 } 1812 1813 private void clearLocalServices(Messenger m) { 1814 ClientInfo clientInfo = getClientInfo(m, false); 1815 if (clientInfo == null) { 1816 return; 1817 } 1818 1819 for (WifiP2pServiceInfo servInfo: clientInfo.mServList) { 1820 mWifiNative.p2pServiceDel(servInfo); 1821 } 1822 1823 clientInfo.mServList.clear(); 1824 if (clientInfo.mReqList.size() == 0) { 1825 if (DBG) logd("remove client information from framework"); 1826 mClientInfoList.remove(clientInfo.mMessenger); 1827 } 1828 } 1829 1830 private void clearClientInfo(Messenger m) { 1831 clearLocalServices(m); 1832 clearServiceRequests(m); 1833 } 1834 1835 /** 1836 * Send the service response to the WifiP2pManager.Channel. 1837 * 1838 * @param resp 1839 */ 1840 private void sendServiceResponse(WifiP2pServiceResponse resp) { 1841 for (ClientInfo c : mClientInfoList.values()) { 1842 WifiP2pServiceRequest req = c.mReqList.get(resp.getTransactionId()); 1843 if (req != null) { 1844 Message msg = Message.obtain(); 1845 msg.what = WifiP2pManager.RESPONSE_SERVICE; 1846 msg.arg1 = 0; 1847 msg.arg2 = 0; 1848 msg.obj = resp; 1849 try { 1850 c.mMessenger.send(msg); 1851 } catch (RemoteException e) { 1852 if (DBG) logd("detect dead channel"); 1853 clearClientInfo(c.mMessenger); 1854 return; 1855 } 1856 } 1857 } 1858 } 1859 1860 /** 1861 * We dont get notifications of clients that have gone away. 1862 * We detect this actively when services are added and throw 1863 * them away. 1864 * 1865 * TODO: This can be done better with full async channels. 1866 */ 1867 private void clearClientDeadChannels() { 1868 ArrayList<Messenger> deadClients = new ArrayList<Messenger>(); 1869 1870 for (ClientInfo c : mClientInfoList.values()) { 1871 Message msg = Message.obtain(); 1872 msg.what = WifiP2pManager.PING; 1873 msg.arg1 = 0; 1874 msg.arg2 = 0; 1875 msg.obj = null; 1876 try { 1877 c.mMessenger.send(msg); 1878 } catch (RemoteException e) { 1879 if (DBG) logd("detect dead channel"); 1880 deadClients.add(c.mMessenger); 1881 } 1882 } 1883 1884 for (Messenger m : deadClients) { 1885 clearClientInfo(m); 1886 } 1887 } 1888 1889 /** 1890 * Return the specified ClientInfo. 1891 * @param m Messenger 1892 * @param createIfNotExist if true and the specified channel info does not exist, 1893 * create new client info. 1894 * @return the specified ClientInfo. 1895 */ 1896 private ClientInfo getClientInfo(Messenger m, boolean createIfNotExist) { 1897 ClientInfo clientInfo = mClientInfoList.get(m); 1898 1899 if (clientInfo == null && createIfNotExist) { 1900 if (DBG) logd("add a new client"); 1901 clientInfo = new ClientInfo(m); 1902 mClientInfoList.put(m, clientInfo); 1903 } 1904 1905 return clientInfo; 1906 } 1907 1908 /** 1909 * Send detached message to dialog listener in the foreground application. 1910 * @param reason 1911 */ 1912 private void sendDetachedMsg(int reason) { 1913 if (mForegroundAppMessenger == null) return; 1914 1915 Message msg = Message.obtain(); 1916 msg.what = WifiP2pManager.DIALOG_LISTENER_DETACHED; 1917 msg.arg1 = reason; 1918 try { 1919 mForegroundAppMessenger.send(msg); 1920 } catch (RemoteException e) { 1921 } 1922 mForegroundAppMessenger = null; 1923 mForegroundAppPkgName = null; 1924 } 1925 1926 /** 1927 * Send a request to show wps pin to dialog listener in the foreground application. 1928 * @param pin WPS pin 1929 * @return 1930 */ 1931 private boolean sendShowPinReqToFrontApp(String pin) { 1932 if (!isForegroundApp(mForegroundAppPkgName)) { 1933 sendDetachedMsg(WifiP2pManager.NOT_IN_FOREGROUND); 1934 return false; 1935 } 1936 Message msg = Message.obtain(); 1937 msg.what = WifiP2pManager.SHOW_PIN_REQUESTED; 1938 Bundle bundle = new Bundle(); 1939 bundle.putString(WifiP2pManager.WPS_PIN_BUNDLE_KEY, pin); 1940 msg.setData(bundle); 1941 return sendDialogMsgToFrontApp(msg); 1942 } 1943 1944 /** 1945 * Send a request to establish the connection to dialog listener in the foreground 1946 * application. 1947 * @param dev source device 1948 * @param config 1949 * @return 1950 */ 1951 private boolean sendConnectNoticeToApp(WifiP2pDevice dev, WifiP2pConfig config) { 1952 if (dev == null) { 1953 dev = new WifiP2pDevice(config.deviceAddress); 1954 } 1955 1956 if (!isForegroundApp(mForegroundAppPkgName)) { 1957 if (DBG) logd("application is NOT foreground"); 1958 sendDetachedMsg(WifiP2pManager.NOT_IN_FOREGROUND); 1959 return false; 1960 } 1961 1962 Message msg = Message.obtain(); 1963 msg.what = WifiP2pManager.CONNECTION_REQUESTED; 1964 Bundle bundle = new Bundle(); 1965 bundle.putParcelable(WifiP2pManager.P2P_DEV_BUNDLE_KEY, dev); 1966 bundle.putParcelable(WifiP2pManager.P2P_CONFIG_BUNDLE_KEY, config); 1967 msg.setData(bundle); 1968 return sendDialogMsgToFrontApp(msg); 1969 } 1970 1971 /** 1972 * Send dialog event message to front application's dialog listener. 1973 * @param msg 1974 * @return true if success. 1975 */ 1976 private boolean sendDialogMsgToFrontApp(Message msg) { 1977 try { 1978 mForegroundAppMessenger.send(msg); 1979 } catch (RemoteException e) { 1980 mForegroundAppMessenger = null; 1981 mForegroundAppPkgName = null; 1982 return false; 1983 } 1984 return true; 1985 } 1986 1987 /** 1988 * Set dialog listener application. 1989 * @param m 1990 * @param appPkgName if null, reset the listener. 1991 * @param isReset if true, try to reset. 1992 * @return 1993 */ 1994 private boolean setDialogListenerApp(Messenger m, 1995 String appPkgName, boolean isReset) { 1996 1997 if (mForegroundAppPkgName != null && !mForegroundAppPkgName.equals(appPkgName)) { 1998 if (isForegroundApp(mForegroundAppPkgName)) { 1999 // The current dialog listener is foreground app's. 2000 if (DBG) logd("application is NOT foreground"); 2001 return false; 2002 } 2003 // detach an old listener. 2004 sendDetachedMsg(WifiP2pManager.NOT_IN_FOREGROUND); 2005 } 2006 2007 if (isReset) { 2008 if (DBG) logd("reset dialog listener"); 2009 mForegroundAppMessenger = null; 2010 mForegroundAppPkgName = null; 2011 return true; 2012 } 2013 2014 if (!isForegroundApp(appPkgName)) { 2015 return false; 2016 } 2017 2018 mForegroundAppMessenger = m; 2019 mForegroundAppPkgName = appPkgName; 2020 if (DBG) logd("set dialog listener. app=" + appPkgName); 2021 return true; 2022 } 2023 2024 /** 2025 * Return true if the specified package name is foreground app's. 2026 * 2027 * @param pkgName application package name. 2028 * @return 2029 */ 2030 private boolean isForegroundApp(String pkgName) { 2031 if (pkgName == null) return false; 2032 2033 List<RunningTaskInfo> tasks = mActivityMgr.getRunningTasks(1); 2034 if (tasks.size() == 0) { 2035 return false; 2036 } 2037 2038 return pkgName.equals(tasks.get(0).baseActivity.getPackageName()); 2039 } 2040 2041 } 2042 2043 /** 2044 * Information about a particular client and we track the service discovery requests 2045 * and the local services registered by the client. 2046 */ 2047 private class ClientInfo { 2048 2049 /* 2050 * A reference to WifiP2pManager.Channel handler. 2051 * The response of this request is notified to WifiP2pManager.Channel handler 2052 */ 2053 private Messenger mMessenger; 2054 2055 /* 2056 * A service discovery request list. 2057 */ 2058 private SparseArray<WifiP2pServiceRequest> mReqList; 2059 2060 /* 2061 * A local service information list. 2062 */ 2063 private List<WifiP2pServiceInfo> mServList; 2064 2065 private ClientInfo(Messenger m) { 2066 mMessenger = m; 2067 mReqList = new SparseArray(); 2068 mServList = new ArrayList<WifiP2pServiceInfo>(); 2069 } 2070 } 2071 2072} 2073