2 * Copyright (C) 2011 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package android.net.wifi.p2p;
19 import android.app.Activity;
20 import android.app.ActivityManager;
21 import android.app.AlertDialog;
22 import android.app.Notification;
23 import android.app.NotificationManager;
24 import android.app.PendingIntent;
25 import android.app.ActivityManager.RunningTaskInfo;
26 import android.content.BroadcastReceiver;
27 import android.content.Context;
28 import android.content.DialogInterface;
29 import android.content.DialogInterface.OnClickListener;
30 import android.content.Intent;
31 import android.content.IntentFilter;
32 import android.content.pm.PackageManager;
33 import android.content.res.Resources;
34 import android.net.IConnectivityManager;
35 import android.net.ConnectivityManager;
36 import android.net.DhcpInfoInternal;
37 import android.net.DhcpStateMachine;
38 import android.net.InterfaceConfiguration;
39 import android.net.LinkAddress;
40 import android.net.LinkProperties;
41 import android.net.NetworkInfo;
42 import android.net.NetworkUtils;
43 import android.net.wifi.WifiManager;
44 import android.net.wifi.WifiMonitor;
45 import android.net.wifi.WifiNative;
46 import android.net.wifi.WifiStateMachine;
47 import android.net.wifi.WpsInfo;
48 import android.net.wifi.p2p.WifiP2pGroupList.GroupDeleteListener;
49 import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
50 import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
51 import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
52 import android.os.Binder;
53 import android.os.Bundle;
54 import android.os.IBinder;
55 import android.os.INetworkManagementService;
56 import android.os.Handler;
57 import android.os.HandlerThread;
58 import android.os.Message;
59 import android.os.Messenger;
60 import android.os.Parcel;
61 import android.os.Parcelable;
62 import android.os.RemoteException;
63 import android.os.ServiceManager;
64 import android.os.SystemProperties;
65 import android.os.UserHandle;
66 import android.os.Parcelable.Creator;
67 import android.provider.Settings;
68 import android.text.TextUtils;
69 import android.util.Slog;
70 import android.util.SparseArray;
71 import android.view.LayoutInflater;
72 import android.view.View;
73 import android.view.ViewGroup;
74 import android.view.WindowManager;
75 import android.widget.EditText;
76 import android.widget.TextView;
78 import com.android.internal.R;
79 import com.android.internal.telephony.TelephonyIntents;
80 import com.android.internal.util.AsyncChannel;
81 import com.android.internal.util.Protocol;
82 import com.android.internal.util.State;
83 import com.android.internal.util.StateMachine;
85 import java.io.FileDescriptor;
86 import java.io.PrintWriter;
87 import java.util.ArrayList;
88 import java.util.Collection;
89 import java.util.HashMap;
90 import java.util.List;
93 * WifiP2pService includes a state machine to perform Wi-Fi p2p operations. Applications
94 * communicate with this service to issue device discovery and connectivity requests
95 * through the WifiP2pManager interface. The state machine communicates with the wifi
96 * driver through wpa_supplicant and handles the event responses through WifiMonitor.
98 * Note that the term Wifi when used without a p2p suffix refers to the client mode
102 public class WifiP2pService extends IWifiP2pManager.Stub {
103 private static final String TAG = "WifiP2pService";
104 private static final boolean DBG = false;
105 private static final String NETWORKTYPE = "WIFI_P2P";
107 private Context mContext;
108 private String mInterface;
109 private Notification mNotification;
111 INetworkManagementService mNwService;
112 private DhcpStateMachine mDhcpStateMachine;
114 private ActivityManager mActivityMgr;
116 private P2pStateMachine mP2pStateMachine;
117 private AsyncChannel mReplyChannel = new AsyncChannel();
118 private AsyncChannel mWifiChannel;
120 private static final Boolean JOIN_GROUP = true;
121 private static final Boolean FORM_GROUP = false;
123 private static final Boolean TRY_REINVOCATION = true;;
124 private static final Boolean NO_REINVOCATION = false;
126 private static final Boolean RELOAD = true;
127 private static final Boolean NO_RELOAD = false;
129 private static final int CONNECT_FAILURE = -1;
130 private static final int CONNECT_SUCCESS = 0;
131 private static final int NEEDS_PROVISION_REQ = 1;
133 /* Two minutes comes from the wpa_supplicant setting */
134 private static final int GROUP_CREATING_WAIT_TIME_MS = 120 * 1000;
135 private static int mGroupCreatingTimeoutIndex = 0;
137 private static final int DISABLE_P2P_WAIT_TIME_MS = 5 * 1000;
138 private static int mDisableP2pTimeoutIndex = 0;
140 /* Set a two minute discover timeout to avoid STA scans from being blocked */
141 private static final int DISCOVER_TIMEOUT_S = 120;
143 /* Idle time after a peer is gone when the group is torn down */
144 private static final int GROUP_IDLE_TIME_S = 10;
146 private static final int BASE = Protocol.BASE_WIFI_P2P_SERVICE;
148 /* Delayed message to timeout group creation */
149 public static final int GROUP_CREATING_TIMED_OUT = BASE + 1;
151 /* User accepted a peer request */
152 private static final int PEER_CONNECTION_USER_ACCEPT = BASE + 2;
153 /* User rejected a peer request */
154 private static final int PEER_CONNECTION_USER_REJECT = BASE + 3;
155 /* User wants to disconnect wifi in favour of p2p */
156 private static final int DROP_WIFI_USER_ACCEPT = BASE + 4;
157 /* User wants to keep his wifi connection and drop p2p */
158 private static final int DROP_WIFI_USER_REJECT = BASE + 5;
159 /* Delayed message to timeout p2p disable */
160 public static final int DISABLE_P2P_TIMED_OUT = BASE + 6;
163 /* Commands to the WifiStateMachine */
164 public static final int P2P_CONNECTION_CHANGED = BASE + 11;
166 /* These commands are used to tempoarily disconnect wifi when we detect
167 * a frequency conflict which would make it impossible to have with p2p
168 * and wifi active at the same time.
170 * If the user chooses to disable wifi tempoarily, we keep wifi disconnected
171 * until the p2p connection is done and terminated at which point we will
174 * DISCONNECT_WIFI_REQUEST
175 * msg.arg1 = 1 enables temporary disconnect and 0 disables it.
177 public static final int DISCONNECT_WIFI_REQUEST = BASE + 12;
178 public static final int DISCONNECT_WIFI_RESPONSE = BASE + 13;
180 private final boolean mP2pSupported;
182 private WifiP2pDevice mThisDevice = new WifiP2pDevice();
184 /* When a group has been explicitly created by an app, we persist the group
185 * even after all clients have been disconnected until an explicit remove
187 private boolean mAutonomousGroup;
189 /* Invitation to join an existing p2p group */
190 private boolean mJoinExistingGroup;
192 /* Track whether we are in p2p discovery. This is used to avoid sending duplicate
195 private boolean mDiscoveryStarted;
197 private NetworkInfo mNetworkInfo;
199 private boolean mTempoarilyDisconnectedWifi = false;
201 /* The transaction Id of service discovery request */
202 private byte mServiceTransactionId = 0;
204 /* Service discovery request ID of wpa_supplicant.
205 * null means it's not set yet. */
206 private String mServiceDiscReqId;
208 /* clients(application) information list. */
209 private HashMap<Messenger, ClientInfo> mClientInfoList = new HashMap<Messenger, ClientInfo>();
211 /* The foreground application's messenger.
212 * The connection request is notified only to foreground application */
213 private Messenger mForegroundAppMessenger;
215 /* the package name of foreground application. */
216 private String mForegroundAppPkgName;
218 /* Is chosen as a unique range to avoid conflict with
219 the range defined in Tethering.java */
220 private static final String[] DHCP_RANGE = {"192.168.49.2", "192.168.49.254"};
221 private static final String SERVER_ADDRESS = "192.168.49.1";
224 * Error code definition.
225 * see the Table.8 in the WiFi Direct specification for the detail.
227 public static enum P2pStatus {
231 /* The target device is currently unavailable. */
232 INFORMATION_IS_CURRENTLY_UNAVAILABLE,
234 /* Protocol error. */
235 INCOMPATIBLE_PARAMETERS,
237 /* The target device reached the limit of the number of the connectable device.
238 * For example, device limit or group limit is set. */
241 /* Protocol error. */
244 /* Unable to accommodate request. */
245 UNABLE_TO_ACCOMMODATE_REQUEST,
247 /* Previous protocol error, or disruptive behavior. */
248 PREVIOUS_PROTOCOL_ERROR,
250 /* There is no common channels the both devices can use. */
253 /* Unknown p2p group. For example, Device A tries to invoke the previous persistent group,
254 * but device B has removed the specified credential already. */
257 /* Both p2p devices indicated an intent of 15 in group owner negotiation. */
260 /* Incompatible provisioning method. */
261 INCOMPATIBLE_PROVISIONING_METHOD,
263 /* Rejected by user */
269 public static P2pStatus valueOf(int error) {
274 return INFORMATION_IS_CURRENTLY_UNAVAILABLE;
276 return INCOMPATIBLE_PARAMETERS;
278 return LIMIT_REACHED;
280 return INVALID_PARAMETER;
282 return UNABLE_TO_ACCOMMODATE_REQUEST;
284 return PREVIOUS_PROTOCOL_ERROR;
286 return NO_COMMON_CHANNEL;
288 return UNKNOWN_P2P_GROUP;
290 return BOTH_GO_INTENT_15;
292 return INCOMPATIBLE_PROVISIONING_METHOD;
294 return REJECTED_BY_USER;
301 public WifiP2pService(Context context) {
304 //STOPSHIP: get this from native side
306 mActivityMgr = (ActivityManager)context.getSystemService(Activity.ACTIVITY_SERVICE);
308 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, "");
310 mP2pSupported = mContext.getPackageManager().hasSystemFeature(
311 PackageManager.FEATURE_WIFI_DIRECT);
313 mThisDevice.primaryDeviceType = mContext.getResources().getString(
314 com.android.internal.R.string.config_wifi_p2p_device_type);
316 mP2pStateMachine = new P2pStateMachine(TAG, mP2pSupported);
317 mP2pStateMachine.start();
320 public void connectivityServiceReady() {
321 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
322 mNwService = INetworkManagementService.Stub.asInterface(b);
325 private void enforceAccessPermission() {
326 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
330 private void enforceChangePermission() {
331 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
336 * Get a reference to handler. This is used by a client to establish
337 * an AsyncChannel communication with WifiP2pService
339 public Messenger getMessenger() {
340 enforceAccessPermission();
341 enforceChangePermission();
342 return new Messenger(mP2pStateMachine.getHandler());
346 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
347 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
348 != PackageManager.PERMISSION_GRANTED) {
349 pw.println("Permission Denial: can't dump WifiP2pService from from pid="
350 + Binder.getCallingPid()
351 + ", uid=" + Binder.getCallingUid());
358 * Handles interaction with WifiStateMachine
360 private class P2pStateMachine extends StateMachine {
362 private DefaultState mDefaultState = new DefaultState();
363 private P2pNotSupportedState mP2pNotSupportedState = new P2pNotSupportedState();
364 private P2pDisablingState mP2pDisablingState = new P2pDisablingState();
365 private P2pDisabledState mP2pDisabledState = new P2pDisabledState();
366 private P2pEnablingState mP2pEnablingState = new P2pEnablingState();
367 private P2pEnabledState mP2pEnabledState = new P2pEnabledState();
368 // Inactive is when p2p is enabled with no connectivity
369 private InactiveState mInactiveState = new InactiveState();
370 private GroupCreatingState mGroupCreatingState = new GroupCreatingState();
371 private UserAuthorizingInvitationState mUserAuthorizingInvitationState
372 = new UserAuthorizingInvitationState();
373 private ProvisionDiscoveryState mProvisionDiscoveryState = new ProvisionDiscoveryState();
374 private GroupNegotiationState mGroupNegotiationState = new GroupNegotiationState();
375 private FrequencyConflictState mFrequencyConflictState =new FrequencyConflictState();
377 private GroupCreatedState mGroupCreatedState = new GroupCreatedState();
378 private UserAuthorizingJoinState mUserAuthorizingJoinState = new UserAuthorizingJoinState();
379 private OngoingGroupRemovalState mOngoingGroupRemovalState = new OngoingGroupRemovalState();
381 private WifiNative mWifiNative = new WifiNative(mInterface);
382 private WifiMonitor mWifiMonitor = new WifiMonitor(this, mWifiNative);
384 private final WifiP2pDeviceList mPeers = new WifiP2pDeviceList();
385 /* During a connection, supplicant can tell us that a device was lost. From a supplicant's
386 * perspective, the discovery stops during connection and it purges device since it does
387 * not get latest updates about the device without being in discovery state.
389 * From the framework perspective, the device is still there since we are connecting or
390 * connected to it. so we keep these devices in a seperate list, so that they are removed
391 * when connection is cancelled or lost
393 private final WifiP2pDeviceList mPeersLostDuringConnection = new WifiP2pDeviceList();
394 private final WifiP2pGroupList mGroups = new WifiP2pGroupList(null,
395 new GroupDeleteListener() {
397 public void onDeleteGroup(int netId) {
398 if (DBG) logd("called onDeleteGroup() netId=" + netId);
399 mWifiNative.removeNetwork(netId);
400 mWifiNative.saveConfig();
401 sendP2pPersistentGroupsChangedBroadcast();
404 private final WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo();
405 private WifiP2pGroup mGroup;
407 // Saved WifiP2pConfig for a peer connection
408 private WifiP2pConfig mSavedPeerConfig;
410 // Saved WifiP2pGroup from invitation request
411 private WifiP2pGroup mSavedP2pGroup;
413 // Saved WifiP2pDevice from provisioning request
414 private WifiP2pDevice mSavedProvDiscDevice;
416 P2pStateMachine(String name, boolean p2pSupported) {
419 addState(mDefaultState);
420 addState(mP2pNotSupportedState, mDefaultState);
421 addState(mP2pDisablingState, mDefaultState);
422 addState(mP2pDisabledState, mDefaultState);
423 addState(mP2pEnablingState, mDefaultState);
424 addState(mP2pEnabledState, mDefaultState);
425 addState(mInactiveState, mP2pEnabledState);
426 addState(mGroupCreatingState, mP2pEnabledState);
427 addState(mUserAuthorizingInvitationState, mGroupCreatingState);
428 addState(mProvisionDiscoveryState, mGroupCreatingState);
429 addState(mGroupNegotiationState, mGroupCreatingState);
430 addState(mFrequencyConflictState, mGroupCreatingState);
431 addState(mGroupCreatedState, mP2pEnabledState);
432 addState(mUserAuthorizingJoinState, mGroupCreatedState);
433 addState(mOngoingGroupRemovalState, mGroupCreatedState);
436 setInitialState(mP2pDisabledState);
438 setInitialState(mP2pNotSupportedState);
442 class DefaultState extends State {
444 public boolean processMessage(Message message) {
445 if (DBG) logd(getName() + message.toString());
446 switch (message.what) {
447 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
448 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
449 if (DBG) logd("Full connection with WifiStateMachine established");
450 mWifiChannel = (AsyncChannel) message.obj;
452 loge("Full connection failure, error = " + message.arg1);
457 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
458 if (message.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
459 loge("Send failed, client connection lost");
461 loge("Client connection lost with reason: " + message.arg1);
466 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
467 AsyncChannel ac = new AsyncChannel();
468 ac.connect(mContext, getHandler(), message.replyTo);
470 case WifiP2pManager.DISCOVER_PEERS:
471 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
472 WifiP2pManager.BUSY);
474 case WifiP2pManager.STOP_DISCOVERY:
475 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
476 WifiP2pManager.BUSY);
478 case WifiP2pManager.DISCOVER_SERVICES:
479 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
480 WifiP2pManager.BUSY);
482 case WifiP2pManager.CONNECT:
483 replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
484 WifiP2pManager.BUSY);
486 case WifiP2pManager.CANCEL_CONNECT:
487 replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
488 WifiP2pManager.BUSY);
490 case WifiP2pManager.CREATE_GROUP:
491 replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
492 WifiP2pManager.BUSY);
494 case WifiP2pManager.REMOVE_GROUP:
495 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
496 WifiP2pManager.BUSY);
498 case WifiP2pManager.ADD_LOCAL_SERVICE:
499 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED,
500 WifiP2pManager.BUSY);
502 case WifiP2pManager.REMOVE_LOCAL_SERVICE:
503 replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED,
504 WifiP2pManager.BUSY);
506 case WifiP2pManager.CLEAR_LOCAL_SERVICES:
507 replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED,
508 WifiP2pManager.BUSY);
510 case WifiP2pManager.ADD_SERVICE_REQUEST:
511 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED,
512 WifiP2pManager.BUSY);
514 case WifiP2pManager.REMOVE_SERVICE_REQUEST:
515 replyToMessage(message,
516 WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED,
517 WifiP2pManager.BUSY);
519 case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
520 replyToMessage(message,
521 WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED,
522 WifiP2pManager.BUSY);
524 case WifiP2pManager.SET_DEVICE_NAME:
525 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
526 WifiP2pManager.BUSY);
528 case WifiP2pManager.DELETE_PERSISTENT_GROUP:
529 replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP,
530 WifiP2pManager.BUSY);
532 case WifiP2pManager.SET_WFD_INFO:
533 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
534 WifiP2pManager.BUSY);
536 case WifiP2pManager.REQUEST_PEERS:
537 replyToMessage(message, WifiP2pManager.RESPONSE_PEERS,
538 new WifiP2pDeviceList(mPeers));
540 case WifiP2pManager.REQUEST_CONNECTION_INFO:
541 replyToMessage(message, WifiP2pManager.RESPONSE_CONNECTION_INFO,
542 new WifiP2pInfo(mWifiP2pInfo));
544 case WifiP2pManager.REQUEST_GROUP_INFO:
545 replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO,
546 mGroup != null ? new WifiP2pGroup(mGroup) : null);
548 case WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO:
549 replyToMessage(message, WifiP2pManager.RESPONSE_PERSISTENT_GROUP_INFO,
550 new WifiP2pGroupList(mGroups, null));
552 case WifiP2pManager.SET_DIALOG_LISTENER:
553 String appPkgName = (String)message.getData().getString(
554 WifiP2pManager.APP_PKG_BUNDLE_KEY);
555 boolean isReset = message.getData().getBoolean(
556 WifiP2pManager.RESET_DIALOG_LISTENER_BUNDLE_KEY);
557 if (setDialogListenerApp(message.replyTo, appPkgName, isReset)) {
558 replyToMessage(message, WifiP2pManager.DIALOG_LISTENER_ATTACHED);
560 replyToMessage(message, WifiP2pManager.DIALOG_LISTENER_DETACHED,
561 WifiP2pManager.NOT_IN_FOREGROUND);
565 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
566 case WifiMonitor.SCAN_RESULTS_EVENT:
567 case WifiMonitor.SUP_CONNECTION_EVENT:
568 case WifiMonitor.SUP_DISCONNECTION_EVENT:
569 case WifiMonitor.NETWORK_CONNECTION_EVENT:
570 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
571 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
572 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
573 case WifiMonitor.WPS_SUCCESS_EVENT:
574 case WifiMonitor.WPS_FAIL_EVENT:
575 case WifiMonitor.WPS_OVERLAP_EVENT:
576 case WifiMonitor.WPS_TIMEOUT_EVENT:
577 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
578 case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
579 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
580 case WifiMonitor.P2P_FIND_STOPPED_EVENT:
581 case WifiMonitor.P2P_SERV_DISC_RESP_EVENT:
582 case PEER_CONNECTION_USER_ACCEPT:
583 case PEER_CONNECTION_USER_REJECT:
584 case DISCONNECT_WIFI_RESPONSE:
585 case DROP_WIFI_USER_ACCEPT:
586 case DROP_WIFI_USER_REJECT:
587 case GROUP_CREATING_TIMED_OUT:
588 case DISABLE_P2P_TIMED_OUT:
589 case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
590 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
591 case DhcpStateMachine.CMD_ON_QUIT:
592 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
594 case WifiStateMachine.CMD_ENABLE_P2P:
595 // Enable is lazy and has no response
597 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
598 // If we end up handling in default, p2p is not enabled
599 mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP);
601 /* unexpected group created, remove */
602 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
603 mGroup = (WifiP2pGroup) message.obj;
604 loge("Unexpected group creation, remove " + mGroup);
605 mWifiNative.p2pGroupRemove(mGroup.getInterface());
607 // A group formation failure is always followed by
608 // a group removed event. Flushing things at group formation
609 // failure causes supplicant issues. Ignore right now.
610 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
613 loge("Unhandled message " + message);
620 class P2pNotSupportedState extends State {
622 public boolean processMessage(Message message) {
623 switch (message.what) {
624 case WifiP2pManager.DISCOVER_PEERS:
625 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
626 WifiP2pManager.P2P_UNSUPPORTED);
628 case WifiP2pManager.STOP_DISCOVERY:
629 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
630 WifiP2pManager.P2P_UNSUPPORTED);
632 case WifiP2pManager.DISCOVER_SERVICES:
633 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
634 WifiP2pManager.P2P_UNSUPPORTED);
636 case WifiP2pManager.CONNECT:
637 replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
638 WifiP2pManager.P2P_UNSUPPORTED);
640 case WifiP2pManager.CANCEL_CONNECT:
641 replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
642 WifiP2pManager.P2P_UNSUPPORTED);
644 case WifiP2pManager.CREATE_GROUP:
645 replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
646 WifiP2pManager.P2P_UNSUPPORTED);
648 case WifiP2pManager.REMOVE_GROUP:
649 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
650 WifiP2pManager.P2P_UNSUPPORTED);
652 case WifiP2pManager.ADD_LOCAL_SERVICE:
653 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED,
654 WifiP2pManager.P2P_UNSUPPORTED);
656 case WifiP2pManager.SET_DIALOG_LISTENER:
657 replyToMessage(message, WifiP2pManager.DIALOG_LISTENER_DETACHED,
658 WifiP2pManager.P2P_UNSUPPORTED);
660 case WifiP2pManager.REMOVE_LOCAL_SERVICE:
661 replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED,
662 WifiP2pManager.P2P_UNSUPPORTED);
664 case WifiP2pManager.CLEAR_LOCAL_SERVICES:
665 replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED,
666 WifiP2pManager.P2P_UNSUPPORTED);
668 case WifiP2pManager.ADD_SERVICE_REQUEST:
669 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED,
670 WifiP2pManager.P2P_UNSUPPORTED);
672 case WifiP2pManager.REMOVE_SERVICE_REQUEST:
673 replyToMessage(message,
674 WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED,
675 WifiP2pManager.P2P_UNSUPPORTED);
677 case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
678 replyToMessage(message,
679 WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED,
680 WifiP2pManager.P2P_UNSUPPORTED);
682 case WifiP2pManager.SET_DEVICE_NAME:
683 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
684 WifiP2pManager.P2P_UNSUPPORTED);
686 case WifiP2pManager.DELETE_PERSISTENT_GROUP:
687 replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP,
688 WifiP2pManager.P2P_UNSUPPORTED);
690 case WifiP2pManager.SET_WFD_INFO:
691 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
692 WifiP2pManager.P2P_UNSUPPORTED);
701 class P2pDisablingState extends State {
703 public void enter() {
704 if (DBG) logd(getName());
705 sendMessageDelayed(obtainMessage(DISABLE_P2P_TIMED_OUT,
706 ++mDisableP2pTimeoutIndex, 0), DISABLE_P2P_WAIT_TIME_MS);
710 public boolean processMessage(Message message) {
711 if (DBG) logd(getName() + message.toString());
712 switch (message.what) {
713 case WifiMonitor.SUP_DISCONNECTION_EVENT:
714 if (DBG) logd("p2p socket connection lost");
715 transitionTo(mP2pDisabledState);
717 case WifiStateMachine.CMD_ENABLE_P2P:
718 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
719 deferMessage(message);
721 case DISABLE_P2P_TIMED_OUT:
722 if (mGroupCreatingTimeoutIndex == message.arg1) {
723 loge("P2p disable timed out");
724 transitionTo(mP2pDisabledState);
735 mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP);
739 class P2pDisabledState extends State {
741 public void enter() {
742 if (DBG) logd(getName());
746 public boolean processMessage(Message message) {
747 if (DBG) logd(getName() + message.toString());
748 switch (message.what) {
749 case WifiStateMachine.CMD_ENABLE_P2P:
751 mNwService.setInterfaceUp(mInterface);
752 } catch (RemoteException re) {
753 loge("Unable to change interface settings: " + re);
754 } catch (IllegalStateException ie) {
755 loge("Unable to change interface settings: " + ie);
757 mWifiMonitor.startMonitoring();
758 transitionTo(mP2pEnablingState);
767 class P2pEnablingState extends State {
769 public void enter() {
770 if (DBG) logd(getName());
774 public boolean processMessage(Message message) {
775 if (DBG) logd(getName() + message.toString());
776 switch (message.what) {
777 case WifiMonitor.SUP_CONNECTION_EVENT:
778 if (DBG) logd("P2p socket connection successful");
779 transitionTo(mInactiveState);
781 case WifiMonitor.SUP_DISCONNECTION_EVENT:
782 loge("P2p socket connection failed");
783 transitionTo(mP2pDisabledState);
785 case WifiStateMachine.CMD_ENABLE_P2P:
786 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
787 deferMessage(message);
796 class P2pEnabledState extends State {
798 public void enter() {
799 if (DBG) logd(getName());
800 sendP2pStateChangedBroadcast(true);
801 mNetworkInfo.setIsAvailable(true);
802 sendP2pConnectionChangedBroadcast();
803 initializeP2pSettings();
807 public boolean processMessage(Message message) {
808 if (DBG) logd(getName() + message.toString());
809 switch (message.what) {
810 case WifiMonitor.SUP_DISCONNECTION_EVENT:
811 loge("Unexpected loss of p2p socket connection");
812 transitionTo(mP2pDisabledState);
814 case WifiStateMachine.CMD_ENABLE_P2P:
817 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
818 if (mPeers.clear()) sendP2pPeersChangedBroadcast();
819 if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast();
821 mWifiNative.closeSupplicantConnection();
822 transitionTo(mP2pDisablingState);
824 case WifiP2pManager.SET_DEVICE_NAME:
826 WifiP2pDevice d = (WifiP2pDevice) message.obj;
827 if (d != null && setAndPersistDeviceName(d.deviceName)) {
828 if (DBG) logd("set device name " + d.deviceName);
829 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_SUCCEEDED);
831 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
832 WifiP2pManager.ERROR);
836 case WifiP2pManager.SET_WFD_INFO:
838 WifiP2pWfdInfo d = (WifiP2pWfdInfo) message.obj;
839 if (d != null && setWfdInfo(d)) {
840 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_SUCCEEDED);
842 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
843 WifiP2pManager.ERROR);
847 case WifiP2pManager.DISCOVER_PEERS:
848 // do not send service discovery request while normal find operation.
849 clearSupplicantServiceRequest();
850 if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {
851 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED);
852 sendP2pDiscoveryChangedBroadcast(true);
854 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
855 WifiP2pManager.ERROR);
858 case WifiMonitor.P2P_FIND_STOPPED_EVENT:
859 sendP2pDiscoveryChangedBroadcast(false);
861 case WifiP2pManager.STOP_DISCOVERY:
862 if (mWifiNative.p2pStopFind()) {
863 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED);
865 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
866 WifiP2pManager.ERROR);
869 case WifiP2pManager.DISCOVER_SERVICES:
870 if (DBG) logd(getName() + " discover services");
871 if (!updateSupplicantServiceRequest()) {
872 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
873 WifiP2pManager.NO_SERVICE_REQUESTS);
876 if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {
877 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_SUCCEEDED);
879 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
880 WifiP2pManager.ERROR);
883 case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
884 WifiP2pDevice device = (WifiP2pDevice) message.obj;
885 if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break;
886 mPeers.update(device);
887 sendP2pPeersChangedBroadcast();
889 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
890 device = (WifiP2pDevice) message.obj;
891 if (mPeers.remove(device)) sendP2pPeersChangedBroadcast();
893 case WifiP2pManager.ADD_LOCAL_SERVICE:
894 if (DBG) logd(getName() + " add service");
895 WifiP2pServiceInfo servInfo = (WifiP2pServiceInfo)message.obj;
896 if (addLocalService(message.replyTo, servInfo)) {
897 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_SUCCEEDED);
899 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED);
902 case WifiP2pManager.REMOVE_LOCAL_SERVICE:
903 if (DBG) logd(getName() + " remove service");
904 servInfo = (WifiP2pServiceInfo)message.obj;
905 removeLocalService(message.replyTo, servInfo);
906 replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_SUCCEEDED);
908 case WifiP2pManager.CLEAR_LOCAL_SERVICES:
909 if (DBG) logd(getName() + " clear service");
910 clearLocalServices(message.replyTo);
911 replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_SUCCEEDED);
913 case WifiP2pManager.ADD_SERVICE_REQUEST:
914 if (DBG) logd(getName() + " add service request");
915 if (!addServiceRequest(message.replyTo, (WifiP2pServiceRequest)message.obj)) {
916 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED);
919 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_SUCCEEDED);
921 case WifiP2pManager.REMOVE_SERVICE_REQUEST:
922 if (DBG) logd(getName() + " remove service request");
923 removeServiceRequest(message.replyTo, (WifiP2pServiceRequest)message.obj);
924 replyToMessage(message, WifiP2pManager.REMOVE_SERVICE_REQUEST_SUCCEEDED);
926 case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
927 if (DBG) logd(getName() + " clear service request");
928 clearServiceRequests(message.replyTo);
929 replyToMessage(message, WifiP2pManager.CLEAR_SERVICE_REQUESTS_SUCCEEDED);
931 case WifiMonitor.P2P_SERV_DISC_RESP_EVENT:
932 if (DBG) logd(getName() + " receive service response");
933 List<WifiP2pServiceResponse> sdRespList =
934 (List<WifiP2pServiceResponse>) message.obj;
935 for (WifiP2pServiceResponse resp : sdRespList) {
937 mPeers.get(resp.getSrcDevice().deviceAddress);
938 resp.setSrcDevice(dev);
939 sendServiceResponse(resp);
942 case WifiP2pManager.DELETE_PERSISTENT_GROUP:
943 if (DBG) logd(getName() + " delete persistent group");
944 mGroups.remove(message.arg1);
945 replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP_SUCCEEDED);
955 sendP2pStateChangedBroadcast(false);
956 mNetworkInfo.setIsAvailable(false);
960 class InactiveState extends State {
962 public void enter() {
963 if (DBG) logd(getName());
964 //Start listening every time we get inactive
965 //TODO: Fix listen after driver behavior is fixed
966 //mWifiNative.p2pListen();
970 public boolean processMessage(Message message) {
971 if (DBG) logd(getName() + message.toString());
972 switch (message.what) {
973 case WifiP2pManager.CONNECT:
974 if (DBG) logd(getName() + " sending connect");
975 WifiP2pConfig config = (WifiP2pConfig) message.obj;
976 mAutonomousGroup = false;
978 /* Update group capability before connect */
979 int gc = mWifiNative.getGroupCapability(config.deviceAddress);
980 mPeers.updateGroupCapability(config.deviceAddress, gc);
981 int connectRet = connect(config, TRY_REINVOCATION);
982 if (connectRet == CONNECT_FAILURE) {
983 replyToMessage(message, WifiP2pManager.CONNECT_FAILED);
986 mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
987 sendP2pPeersChangedBroadcast();
988 replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
989 if (connectRet == NEEDS_PROVISION_REQ) {
990 if (DBG) logd("Sending prov disc");
991 transitionTo(mProvisionDiscoveryState);
994 transitionTo(mGroupNegotiationState);
996 case WifiP2pManager.STOP_DISCOVERY:
997 if (mWifiNative.p2pStopFind()) {
998 // When discovery stops in inactive state, flush to clear
1000 mWifiNative.p2pFlush();
1001 mServiceDiscReqId = null;
1002 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED);
1004 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
1005 WifiP2pManager.ERROR);
1008 case WifiMonitor.P2P_GO_NEGOTIATION_REQUEST_EVENT:
1009 mSavedPeerConfig = (WifiP2pConfig) message.obj;
1010 mAutonomousGroup = false;
1011 mJoinExistingGroup = false;
1012 if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress),
1013 mSavedPeerConfig)) {
1014 transitionTo(mUserAuthorizingInvitationState);
1017 case WifiMonitor.P2P_INVITATION_RECEIVED_EVENT:
1018 WifiP2pGroup group = (WifiP2pGroup) message.obj;
1019 WifiP2pDevice owner = group.getOwner();
1021 if (owner == null) {
1022 if (DBG) loge("Ignored invitation from null owner");
1026 mSavedPeerConfig = new WifiP2pConfig();
1027 mSavedPeerConfig.deviceAddress = group.getOwner().deviceAddress;
1029 //Check if we have the owner in peer list and use appropriate
1030 //wps method. Default is to use PBC.
1031 if ((owner = mPeers.get(owner.deviceAddress)) != null) {
1032 if (owner.wpsPbcSupported()) {
1033 mSavedPeerConfig.wps.setup = WpsInfo.PBC;
1034 } else if (owner.wpsKeypadSupported()) {
1035 mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD;
1036 } else if (owner.wpsDisplaySupported()) {
1037 mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;
1041 mAutonomousGroup = false;
1042 mJoinExistingGroup = true;
1043 //TODO In the p2p client case, we should set source address correctly.
1044 if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress),
1045 mSavedPeerConfig)) {
1046 transitionTo(mUserAuthorizingInvitationState);
1049 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
1050 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
1051 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
1052 //We let the supplicant handle the provision discovery response
1053 //and wait instead for the GO_NEGOTIATION_REQUEST_EVENT.
1054 //Handling provision discovery and issuing a p2p_connect before
1055 //group negotiation comes through causes issues
1057 case WifiP2pManager.CREATE_GROUP:
1058 mAutonomousGroup = true;
1059 int netId = message.arg1;
1060 boolean ret = false;
1061 if (netId == WifiP2pGroup.PERSISTENT_NET_ID) {
1062 // check if the go persistent group is present.
1063 netId = mGroups.getNetworkId(mThisDevice.deviceAddress);
1065 ret = mWifiNative.p2pGroupAdd(netId);
1067 ret = mWifiNative.p2pGroupAdd(true);
1070 ret = mWifiNative.p2pGroupAdd(false);
1074 replyToMessage(message, WifiP2pManager.CREATE_GROUP_SUCCEEDED);
1075 transitionTo(mGroupNegotiationState);
1077 replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
1078 WifiP2pManager.ERROR);
1079 // remain at this state.
1082 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
1083 mGroup = (WifiP2pGroup) message.obj;
1084 if (DBG) logd(getName() + " group started");
1086 // We hit this scenario when a persistent group is reinvoked
1087 if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) {
1088 mAutonomousGroup = false;
1089 deferMessage(message);
1090 transitionTo(mGroupNegotiationState);
1092 loge("Unexpected group creation, remove " + mGroup);
1093 mWifiNative.p2pGroupRemove(mGroup.getInterface());
1103 class GroupCreatingState extends State {
1105 public void enter() {
1106 if (DBG) logd(getName());
1107 sendMessageDelayed(obtainMessage(GROUP_CREATING_TIMED_OUT,
1108 ++mGroupCreatingTimeoutIndex, 0), GROUP_CREATING_WAIT_TIME_MS);
1112 public boolean processMessage(Message message) {
1113 if (DBG) logd(getName() + message.toString());
1114 boolean ret = HANDLED;
1115 switch (message.what) {
1116 case GROUP_CREATING_TIMED_OUT:
1117 if (mGroupCreatingTimeoutIndex == message.arg1) {
1118 if (DBG) logd("Group negotiation timed out");
1119 handleGroupCreationFailure();
1120 transitionTo(mInactiveState);
1123 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
1124 WifiP2pDevice device = (WifiP2pDevice) message.obj;
1126 // If we lose a device during an autonomous group creation,
1127 // mSavedPeerConfig can be empty
1128 if (mSavedPeerConfig != null &&
1129 !mSavedPeerConfig.deviceAddress.equals(device.deviceAddress)) {
1131 logd("mSavedPeerConfig " + mSavedPeerConfig.deviceAddress +
1132 "device " + device.deviceAddress);
1134 // Do the regular device lost handling
1139 if (DBG) logd("Add device to lost list " + device);
1140 mPeersLostDuringConnection.update(device);
1142 case WifiP2pManager.DISCOVER_PEERS:
1143 /* Discovery will break negotiation */
1144 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
1145 WifiP2pManager.BUSY);
1147 case WifiP2pManager.CANCEL_CONNECT:
1148 //Do a supplicant p2p_cancel which only cancels an ongoing
1149 //group negotiation. This will fail for a pending provision
1150 //discovery or for a pending user action, but at the framework
1151 //level, we always treat cancel as succeeded and enter
1153 mWifiNative.p2pCancelConnect();
1154 handleGroupCreationFailure();
1155 transitionTo(mInactiveState);
1156 replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_SUCCEEDED);
1165 class UserAuthorizingInvitationState extends State {
1167 public void enter() {
1168 if (DBG) logd(getName());
1169 notifyInvitationReceived();
1173 public boolean processMessage(Message message) {
1174 if (DBG) logd(getName() + message.toString());
1175 boolean ret = HANDLED;
1176 switch (message.what) {
1177 case PEER_CONNECTION_USER_ACCEPT:
1178 if (connect(mSavedPeerConfig, TRY_REINVOCATION) == CONNECT_FAILURE) {
1179 handleGroupCreationFailure();
1180 transitionTo(mInactiveState);
1183 mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
1184 sendP2pPeersChangedBroadcast();
1185 transitionTo(mGroupNegotiationState);
1187 case PEER_CONNECTION_USER_REJECT:
1188 if (DBG) logd("User rejected invitation " + mSavedPeerConfig);
1189 mSavedPeerConfig = null;
1190 transitionTo(mInactiveState);
1199 public void exit() {
1200 //TODO: dismiss dialog if not already done
1204 class ProvisionDiscoveryState extends State {
1206 public void enter() {
1207 if (DBG) logd(getName());
1208 mWifiNative.p2pProvisionDiscovery(mSavedPeerConfig);
1212 public boolean processMessage(Message message) {
1213 if (DBG) logd(getName() + message.toString());
1214 WifiP2pProvDiscEvent provDisc;
1215 WifiP2pDevice device;
1216 switch (message.what) {
1217 case WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT:
1218 provDisc = (WifiP2pProvDiscEvent) message.obj;
1219 device = provDisc.device;
1220 if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
1222 if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
1223 if (DBG) logd("Found a match " + mSavedPeerConfig);
1224 p2pConnectWithPinDisplay(mSavedPeerConfig);
1225 transitionTo(mGroupNegotiationState);
1228 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
1229 provDisc = (WifiP2pProvDiscEvent) message.obj;
1230 device = provDisc.device;
1231 if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
1233 if (mSavedPeerConfig.wps.setup == WpsInfo.KEYPAD) {
1234 if (DBG) logd("Found a match " + mSavedPeerConfig);
1235 /* we already have the pin */
1236 if (!TextUtils.isEmpty(mSavedPeerConfig.wps.pin)) {
1237 p2pConnectWithPinDisplay(mSavedPeerConfig);
1238 transitionTo(mGroupNegotiationState);
1240 mJoinExistingGroup = false;
1241 if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress),
1242 mSavedPeerConfig)) {
1243 transitionTo(mUserAuthorizingInvitationState);
1248 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
1249 provDisc = (WifiP2pProvDiscEvent) message.obj;
1250 device = provDisc.device;
1251 if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
1253 if (mSavedPeerConfig.wps.setup == WpsInfo.DISPLAY) {
1254 if (DBG) logd("Found a match " + mSavedPeerConfig);
1255 mSavedPeerConfig.wps.pin = provDisc.pin;
1256 p2pConnectWithPinDisplay(mSavedPeerConfig);
1257 if (!sendShowPinReqToFrontApp(provDisc.pin)) {
1258 notifyInvitationSent(provDisc.pin, device.deviceAddress);
1260 transitionTo(mGroupNegotiationState);
1263 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
1264 loge("provision discovery failed");
1265 handleGroupCreationFailure();
1266 transitionTo(mInactiveState);
1275 class GroupNegotiationState extends State {
1277 public void enter() {
1278 if (DBG) logd(getName());
1282 public boolean processMessage(Message message) {
1283 if (DBG) logd(getName() + message.toString());
1284 switch (message.what) {
1285 // We ignore these right now, since we get a GROUP_STARTED notification
1287 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
1288 case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:
1289 if (DBG) logd(getName() + " go success");
1291 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
1292 mGroup = (WifiP2pGroup) message.obj;
1293 if (DBG) logd(getName() + " group started");
1295 if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) {
1297 * update cache information and set network id to mGroup.
1299 updatePersistentNetworks(NO_RELOAD);
1300 String devAddr = mGroup.getOwner().deviceAddress;
1301 mGroup.setNetworkId(mGroups.getNetworkId(devAddr,
1302 mGroup.getNetworkName()));
1305 if (mGroup.isGroupOwner()) {
1306 /* Setting an idle time out on GO causes issues with certain scenarios
1307 * on clients where it can be off-channel for longer and with the power
1310 * TODO: Verify multi-channel scenarios and supplicant behavior are
1311 * better before adding a time out in future
1313 startDhcpServer(mGroup.getInterface());
1315 mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);
1316 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(mContext,
1317 P2pStateMachine.this, mGroup.getInterface());
1318 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
1319 WifiP2pDevice groupOwner = mGroup.getOwner();
1320 /* update group owner details with the ones found at discovery */
1321 groupOwner.update(mPeers.get(groupOwner.deviceAddress));
1322 mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED);
1323 sendP2pPeersChangedBroadcast();
1325 mSavedPeerConfig = null;
1326 transitionTo(mGroupCreatedState);
1328 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
1329 P2pStatus status = (P2pStatus) message.obj;
1330 if (status == P2pStatus.NO_COMMON_CHANNEL) {
1331 transitionTo(mFrequencyConflictState);
1334 /* continue with group removal handling */
1335 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
1336 if (DBG) logd(getName() + " go failure");
1337 handleGroupCreationFailure();
1338 transitionTo(mInactiveState);
1340 // A group formation failure is always followed by
1341 // a group removed event. Flushing things at group formation
1342 // failure causes supplicant issues. Ignore right now.
1343 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
1344 status = (P2pStatus) message.obj;
1345 if (status == P2pStatus.NO_COMMON_CHANNEL) {
1346 transitionTo(mFrequencyConflictState);
1350 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
1351 status = (P2pStatus)message.obj;
1352 if (status == P2pStatus.SUCCESS) {
1353 // invocation was succeeded.
1354 // wait P2P_GROUP_STARTED_EVENT.
1356 } else if (status == P2pStatus.UNKNOWN_P2P_GROUP) {
1357 // target device has already removed the credential.
1358 // So, remove this credential accordingly.
1359 int netId = mSavedPeerConfig.netId;
1361 if (DBG) logd("Remove unknown client from the list");
1362 removeClientFromList(netId, mSavedPeerConfig.deviceAddress, true);
1365 // invocation is failed or deferred. Try another way to connect.
1366 mSavedPeerConfig.netId = WifiP2pGroup.PERSISTENT_NET_ID;
1367 if (connect(mSavedPeerConfig, NO_REINVOCATION) == CONNECT_FAILURE) {
1368 handleGroupCreationFailure();
1369 transitionTo(mInactiveState);
1371 } else if (status == P2pStatus.NO_COMMON_CHANNEL) {
1372 transitionTo(mFrequencyConflictState);
1374 handleGroupCreationFailure();
1375 transitionTo(mInactiveState);
1385 class FrequencyConflictState extends State {
1386 private AlertDialog mFrequencyConflictDialog;
1388 public void enter() {
1389 if (DBG) logd(getName());
1390 notifyFrequencyConflict();
1393 private void notifyFrequencyConflict() {
1394 logd("Notify frequency conflict");
1395 Resources r = Resources.getSystem();
1397 AlertDialog dialog = new AlertDialog.Builder(mContext)
1398 .setMessage(r.getString(R.string.wifi_p2p_frequency_conflict_message,
1399 getDeviceName(mSavedPeerConfig.deviceAddress)))
1400 .setPositiveButton(r.getString(R.string.dlg_ok), new OnClickListener() {
1402 public void onClick(DialogInterface dialog, int which) {
1403 sendMessage(DROP_WIFI_USER_ACCEPT);
1406 .setNegativeButton(r.getString(R.string.decline), new OnClickListener() {
1408 public void onClick(DialogInterface dialog, int which) {
1409 sendMessage(DROP_WIFI_USER_REJECT);
1412 .setOnCancelListener(new DialogInterface.OnCancelListener() {
1414 public void onCancel(DialogInterface arg0) {
1415 sendMessage(DROP_WIFI_USER_REJECT);
1420 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1422 mFrequencyConflictDialog = dialog;
1426 public boolean processMessage(Message message) {
1427 if (DBG) logd(getName() + message.toString());
1428 switch (message.what) {
1429 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
1430 case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:
1431 loge(getName() + "group sucess during freq conflict!");
1433 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
1434 loge(getName() + "group started after freq conflict, handle anyway");
1435 deferMessage(message);
1436 transitionTo(mGroupNegotiationState);
1438 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
1439 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
1440 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
1441 // Ignore failures since we retry again
1443 case DROP_WIFI_USER_REJECT:
1444 // User rejected dropping wifi in favour of p2p
1445 handleGroupCreationFailure();
1446 transitionTo(mInactiveState);
1448 case DROP_WIFI_USER_ACCEPT:
1449 // User accepted dropping wifi in favour of p2p
1450 mWifiChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_REQUEST, 1);
1451 mTempoarilyDisconnectedWifi = true;
1453 case DISCONNECT_WIFI_RESPONSE:
1454 // Got a response from wifistatemachine, retry p2p
1455 if (DBG) logd(getName() + "Wifi disconnected, retry p2p");
1456 transitionTo(mInactiveState);
1457 sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
1465 public void exit() {
1466 if (mFrequencyConflictDialog != null) mFrequencyConflictDialog.dismiss();
1470 class GroupCreatedState extends State {
1472 public void enter() {
1473 if (DBG) logd(getName());
1474 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
1476 updateThisDevice(WifiP2pDevice.CONNECTED);
1478 //DHCP server has already been started if I am a group owner
1479 if (mGroup.isGroupOwner()) {
1480 setWifiP2pInfoOnGroupFormation(SERVER_ADDRESS);
1483 // In case of a negotiation group, connection changed is sent
1484 // after a client joins. For autonomous, send now
1485 if (mAutonomousGroup) {
1486 sendP2pConnectionChangedBroadcast();
1491 public boolean processMessage(Message message) {
1492 if (DBG) logd(getName() + message.toString());
1493 switch (message.what) {
1494 case WifiMonitor.AP_STA_CONNECTED_EVENT:
1495 WifiP2pDevice device = (WifiP2pDevice) message.obj;
1496 String deviceAddress = device.deviceAddress;
1497 if (deviceAddress != null) {
1498 if (mSavedProvDiscDevice != null &&
1499 deviceAddress.equals(mSavedProvDiscDevice.deviceAddress)) {
1500 mSavedProvDiscDevice = null;
1502 if (mPeers.get(deviceAddress) != null) {
1503 mGroup.addClient(mPeers.get(deviceAddress));
1505 mGroup.addClient(deviceAddress);
1507 mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED);
1508 if (DBG) logd(getName() + " ap sta connected");
1509 sendP2pPeersChangedBroadcast();
1511 loge("Connect on null device address, ignore");
1513 sendP2pConnectionChangedBroadcast();
1515 case WifiMonitor.AP_STA_DISCONNECTED_EVENT:
1516 device = (WifiP2pDevice) message.obj;
1517 deviceAddress = device.deviceAddress;
1518 if (deviceAddress != null) {
1519 mPeers.updateStatus(deviceAddress, WifiP2pDevice.AVAILABLE);
1520 if (mGroup.removeClient(deviceAddress)) {
1521 if (DBG) logd("Removed client " + deviceAddress);
1522 if (!mAutonomousGroup && mGroup.isClientListEmpty()) {
1523 Slog.d(TAG, "Client list empty, remove non-persistent p2p group");
1524 mWifiNative.p2pGroupRemove(mGroup.getInterface());
1525 // We end up sending connection changed broadcast
1526 // when this happens at exit()
1528 // Notify when a client disconnects from group
1529 sendP2pConnectionChangedBroadcast();
1532 if (DBG) logd("Failed to remove client " + deviceAddress);
1533 for (WifiP2pDevice c : mGroup.getClientList()) {
1534 if (DBG) logd("client " + c.deviceAddress);
1537 sendP2pPeersChangedBroadcast();
1538 if (DBG) logd(getName() + " ap sta disconnected");
1540 loge("Disconnect on unknown device: " + device);
1543 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
1544 DhcpInfoInternal dhcpInfo = (DhcpInfoInternal) message.obj;
1545 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS &&
1547 if (DBG) logd("DhcpInfo: " + dhcpInfo);
1548 setWifiP2pInfoOnGroupFormation(dhcpInfo.serverAddress);
1549 sendP2pConnectionChangedBroadcast();
1550 //Turn on power save on client
1551 mWifiNative.setP2pPowerSave(mGroup.getInterface(), true);
1553 loge("DHCP failed");
1554 mWifiNative.p2pGroupRemove(mGroup.getInterface());
1557 case WifiP2pManager.REMOVE_GROUP:
1558 if (DBG) logd(getName() + " remove group");
1559 if (mWifiNative.p2pGroupRemove(mGroup.getInterface())) {
1560 transitionTo(mOngoingGroupRemovalState);
1561 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED);
1563 handleGroupRemoved();
1564 transitionTo(mInactiveState);
1565 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
1566 WifiP2pManager.ERROR);
1569 /* We do not listen to NETWORK_DISCONNECTION_EVENT for group removal
1570 * handling since supplicant actually tries to reconnect after a temporary
1571 * disconnect until group idle time out. Eventually, a group removal event
1572 * will come when group has been removed.
1574 * When there are connectivity issues during temporary disconnect, the application
1575 * will also just remove the group.
1577 * Treating network disconnection as group removal causes race conditions since
1578 * supplicant would still maintain the group at that stage.
1580 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
1581 if (DBG) logd(getName() + " group removed");
1582 handleGroupRemoved();
1583 transitionTo(mInactiveState);
1585 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
1586 device = (WifiP2pDevice) message.obj;
1587 //Device loss for a connected device indicates it is not in discovery any more
1588 if (mGroup.contains(device)) {
1589 if (DBG) logd("Add device to lost list " + device);
1590 mPeersLostDuringConnection.update(device);
1593 // Do the regular device lost handling
1595 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
1596 sendMessage(WifiP2pManager.REMOVE_GROUP);
1597 deferMessage(message);
1599 case WifiP2pManager.CONNECT:
1600 WifiP2pConfig config = (WifiP2pConfig) message.obj;
1601 if (config.deviceAddress == null ||
1602 (mSavedProvDiscDevice != null &&
1603 mSavedProvDiscDevice.deviceAddress.equals(
1604 config.deviceAddress))) {
1605 if (config.wps.setup == WpsInfo.PBC) {
1606 mWifiNative.startWpsPbc(mGroup.getInterface(), null);
1608 if (config.wps.pin == null) {
1609 String pin = mWifiNative.startWpsPinDisplay(mGroup.getInterface());
1611 Integer.parseInt(pin);
1612 if (!sendShowPinReqToFrontApp(pin)) {
1613 notifyInvitationSent(pin,
1614 config.deviceAddress != null ?
1615 config.deviceAddress : "any");
1617 } catch (NumberFormatException ignore) {
1618 // do nothing if pin is invalid
1621 mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
1625 if (config.deviceAddress != null) {
1626 mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED);
1627 sendP2pPeersChangedBroadcast();
1629 replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
1631 logd("Inviting device : " + config.deviceAddress);
1632 mSavedPeerConfig = config;
1633 if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) {
1634 mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED);
1635 sendP2pPeersChangedBroadcast();
1636 replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
1638 replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
1639 WifiP2pManager.ERROR);
1642 // TODO: figure out updating the status to declined when invitation is rejected
1644 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
1645 P2pStatus status = (P2pStatus)message.obj;
1646 logd("===> INVITATION RESULT EVENT : " + status);
1647 if (status == P2pStatus.SUCCESS) {
1648 // invocation was succeeded.
1650 } else if (status == P2pStatus.UNKNOWN_P2P_GROUP) {
1651 // target device has already removed the credential.
1652 // So, remove this credential accordingly.
1653 int netId = mGroup.getNetworkId();
1655 if (DBG) logd("Remove unknown client from the list");
1656 if (!removeClientFromList(netId,
1657 mSavedPeerConfig.deviceAddress, false)) {
1658 // not found the client on the list
1659 Slog.e(TAG, "Already removed the client, ignore");
1663 sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
1667 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
1668 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
1669 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
1670 WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj;
1671 mSavedProvDiscDevice = provDisc.device;
1672 mSavedPeerConfig = new WifiP2pConfig();
1673 mSavedPeerConfig.deviceAddress = provDisc.device.deviceAddress;
1674 if (message.what == WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) {
1675 mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD;
1676 } else if (message.what == WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT) {
1677 mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;
1678 mSavedPeerConfig.wps.pin = provDisc.pin;
1680 mSavedPeerConfig.wps.setup = WpsInfo.PBC;
1682 if (!sendConnectNoticeToApp(mSavedProvDiscDevice, mSavedPeerConfig)) {
1683 transitionTo(mUserAuthorizingJoinState);
1686 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
1687 Slog.e(TAG, "Duplicate group creation event notice, ignore");
1695 public void exit() {
1696 mSavedProvDiscDevice = null;
1697 updateThisDevice(WifiP2pDevice.AVAILABLE);
1699 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
1700 sendP2pConnectionChangedBroadcast();
1704 class UserAuthorizingJoinState extends State {
1706 public void enter() {
1707 if (DBG) logd(getName());
1708 notifyInvitationReceived();
1712 public boolean processMessage(Message message) {
1713 if (DBG) logd(getName() + message.toString());
1714 switch (message.what) {
1715 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
1716 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
1717 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
1718 //Ignore more client requests
1720 case PEER_CONNECTION_USER_ACCEPT:
1721 if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
1722 mWifiNative.startWpsPbc(mGroup.getInterface(), null);
1724 mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
1725 mSavedPeerConfig.wps.pin);
1727 mSavedPeerConfig = null;
1728 transitionTo(mGroupCreatedState);
1730 case PEER_CONNECTION_USER_REJECT:
1731 if (DBG) logd("User rejected incoming request");
1732 mSavedPeerConfig = null;
1733 transitionTo(mGroupCreatedState);
1742 public void exit() {
1743 //TODO: dismiss dialog if not already done
1747 class OngoingGroupRemovalState extends State {
1749 public void enter() {
1750 if (DBG) logd(getName());
1754 public boolean processMessage(Message message) {
1755 if (DBG) logd(getName() + message.toString());
1756 switch (message.what) {
1757 // Group removal ongoing. Multiple calls
1758 // end up removing persisted network. Do nothing.
1759 case WifiP2pManager.REMOVE_GROUP:
1760 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED);
1762 // Parent state will transition out of this state
1763 // when removal is complete
1771 private void sendP2pStateChangedBroadcast(boolean enabled) {
1772 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
1773 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1775 intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE,
1776 WifiP2pManager.WIFI_P2P_STATE_ENABLED);
1778 intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE,
1779 WifiP2pManager.WIFI_P2P_STATE_DISABLED);
1781 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1784 private void sendP2pDiscoveryChangedBroadcast(boolean started) {
1785 if (mDiscoveryStarted == started) return;
1786 mDiscoveryStarted = started;
1788 if (DBG) logd("discovery change broadcast " + started);
1790 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);
1791 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1792 intent.putExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE, started ?
1793 WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED :
1794 WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED);
1795 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1798 private void sendThisDeviceChangedBroadcast() {
1799 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
1800 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1801 intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE, new WifiP2pDevice(mThisDevice));
1802 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1805 private void sendP2pPeersChangedBroadcast() {
1806 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
1807 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1808 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1811 private void sendP2pConnectionChangedBroadcast() {
1812 if (DBG) logd("sending p2p connection changed broadcast");
1813 Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
1814 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1815 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
1816 intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, new WifiP2pInfo(mWifiP2pInfo));
1817 intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
1818 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1819 mWifiChannel.sendMessage(WifiP2pService.P2P_CONNECTION_CHANGED,
1820 new NetworkInfo(mNetworkInfo));
1823 private void sendP2pPersistentGroupsChangedBroadcast() {
1824 if (DBG) logd("sending p2p persistent groups changed broadcast");
1825 Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION);
1826 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1827 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1830 private void startDhcpServer(String intf) {
1831 InterfaceConfiguration ifcg = null;
1833 ifcg = mNwService.getInterfaceConfig(intf);
1834 ifcg.setLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress(
1835 SERVER_ADDRESS), 24));
1836 ifcg.setInterfaceUp();
1837 mNwService.setInterfaceConfig(intf, ifcg);
1838 /* This starts the dnsmasq server */
1839 mNwService.startTethering(DHCP_RANGE);
1840 } catch (Exception e) {
1841 loge("Error configuring interface " + intf + ", :" + e);
1845 logd("Started Dhcp server on " + intf);
1848 private void stopDhcpServer(String intf) {
1850 mNwService.stopTethering();
1851 } catch (Exception e) {
1852 loge("Error stopping Dhcp server" + e);
1856 logd("Stopped Dhcp server");
1859 private void notifyP2pEnableFailure() {
1860 Resources r = Resources.getSystem();
1861 AlertDialog dialog = new AlertDialog.Builder(mContext)
1862 .setTitle(r.getString(R.string.wifi_p2p_dialog_title))
1863 .setMessage(r.getString(R.string.wifi_p2p_failed_message))
1864 .setPositiveButton(r.getString(R.string.ok), null)
1866 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1870 private void addRowToDialog(ViewGroup group, int stringId, String value) {
1871 Resources r = Resources.getSystem();
1872 View row = LayoutInflater.from(mContext).inflate(R.layout.wifi_p2p_dialog_row,
1874 ((TextView) row.findViewById(R.id.name)).setText(r.getString(stringId));
1875 ((TextView) row.findViewById(R.id.value)).setText(value);
1879 private void notifyInvitationSent(String pin, String peerAddress) {
1880 Resources r = Resources.getSystem();
1882 final View textEntryView = LayoutInflater.from(mContext)
1883 .inflate(R.layout.wifi_p2p_dialog, null);
1885 ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info);
1886 addRowToDialog(group, R.string.wifi_p2p_to_message, getDeviceName(peerAddress));
1887 addRowToDialog(group, R.string.wifi_p2p_show_pin_message, pin);
1889 AlertDialog dialog = new AlertDialog.Builder(mContext)
1890 .setTitle(r.getString(R.string.wifi_p2p_invitation_sent_title))
1891 .setView(textEntryView)
1892 .setPositiveButton(r.getString(R.string.ok), null)
1894 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1898 private void notifyInvitationReceived() {
1899 Resources r = Resources.getSystem();
1900 final WpsInfo wps = mSavedPeerConfig.wps;
1901 final View textEntryView = LayoutInflater.from(mContext)
1902 .inflate(R.layout.wifi_p2p_dialog, null);
1904 ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info);
1905 addRowToDialog(group, R.string.wifi_p2p_from_message, getDeviceName(
1906 mSavedPeerConfig.deviceAddress));
1908 final EditText pin = (EditText) textEntryView.findViewById(R.id.wifi_p2p_wps_pin);
1910 AlertDialog dialog = new AlertDialog.Builder(mContext)
1911 .setTitle(r.getString(R.string.wifi_p2p_invitation_to_connect_title))
1912 .setView(textEntryView)
1913 .setPositiveButton(r.getString(R.string.accept), new OnClickListener() {
1914 public void onClick(DialogInterface dialog, int which) {
1915 if (wps.setup == WpsInfo.KEYPAD) {
1916 mSavedPeerConfig.wps.pin = pin.getText().toString();
1918 if (DBG) logd(getName() + " accept invitation " + mSavedPeerConfig);
1919 sendMessage(PEER_CONNECTION_USER_ACCEPT);
1922 .setNegativeButton(r.getString(R.string.decline), new OnClickListener() {
1924 public void onClick(DialogInterface dialog, int which) {
1925 if (DBG) logd(getName() + " ignore connect");
1926 sendMessage(PEER_CONNECTION_USER_REJECT);
1929 .setOnCancelListener(new DialogInterface.OnCancelListener() {
1931 public void onCancel(DialogInterface arg0) {
1932 if (DBG) logd(getName() + " ignore connect");
1933 sendMessage(PEER_CONNECTION_USER_REJECT);
1938 //make the enter pin area or the display pin area visible
1939 switch (wps.setup) {
1940 case WpsInfo.KEYPAD:
1941 if (DBG) logd("Enter pin section visible");
1942 textEntryView.findViewById(R.id.enter_pin_section).setVisibility(View.VISIBLE);
1944 case WpsInfo.DISPLAY:
1945 if (DBG) logd("Shown pin section visible");
1946 addRowToDialog(group, R.string.wifi_p2p_show_pin_message, wps.pin);
1952 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1957 * Synchronize the persistent group list between
1958 * wpa_supplicant and mGroups.
1960 private void updatePersistentNetworks(boolean reload) {
1961 String listStr = mWifiNative.listNetworks();
1962 if (listStr == null) return;
1964 boolean isSaveRequired = false;
1965 String[] lines = listStr.split("\n");
1966 if (lines == null) return;
1968 if (reload) mGroups.clear();
1970 // Skip the first line, which is a header
1971 for (int i = 1; i < lines.length; i++) {
1972 String[] result = lines[i].split("\t");
1973 if (result == null || result.length < 4) {
1976 // network-id | ssid | bssid | flags
1978 String ssid = result[1];
1979 String bssid = result[2];
1980 String flags = result[3];
1982 netId = Integer.parseInt(result[0]);
1983 } catch(NumberFormatException e) {
1984 e.printStackTrace();
1988 if (flags.indexOf("[CURRENT]") != -1) {
1991 if (flags.indexOf("[P2P-PERSISTENT]") == -1) {
1993 * The unused profile is sometimes remained when the p2p group formation is failed.
1994 * So, we clean up the p2p group here.
1996 if (DBG) logd("clean up the unused persistent group. netId=" + netId);
1997 mWifiNative.removeNetwork(netId);
1998 isSaveRequired = true;
2002 if (mGroups.contains(netId)) {
2006 WifiP2pGroup group = new WifiP2pGroup();
2007 group.setNetworkId(netId);
2008 group.setNetworkName(ssid);
2009 String mode = mWifiNative.getNetworkVariable(netId, "mode");
2010 if (mode != null && mode.equals("3")) {
2011 group.setIsGroupOwner(true);
2013 if (bssid.equalsIgnoreCase(mThisDevice.deviceAddress)) {
2014 group.setOwner(mThisDevice);
2016 WifiP2pDevice device = new WifiP2pDevice();
2017 device.deviceAddress = bssid;
2018 group.setOwner(device);
2021 isSaveRequired = true;
2024 if (reload || isSaveRequired) {
2025 mWifiNative.saveConfig();
2026 sendP2pPersistentGroupsChangedBroadcast();
2031 * Try to connect to the target device.
2033 * Use the persistent credential if it has been stored.
2036 * @param tryInvocation if true, try to invoke. Otherwise, never try to invoke.
2039 private int connect(WifiP2pConfig config, boolean tryInvocation) {
2041 if (config == null) {
2042 loge("config is null");
2043 return CONNECT_FAILURE;
2046 boolean isResp = (mSavedPeerConfig != null &&
2047 config.deviceAddress.equals(mSavedPeerConfig.deviceAddress));
2048 mSavedPeerConfig = config;
2050 WifiP2pDevice dev = mPeers.get(config.deviceAddress);
2052 loge("target device not found " + config.deviceAddress);
2053 return CONNECT_FAILURE;
2056 boolean join = dev.isGroupOwner();
2057 String ssid = mWifiNative.p2pGetSsid(dev.deviceAddress);
2058 if (DBG) logd("target ssid is " + ssid + " join:" + join);
2060 if (join && dev.isGroupLimit()) {
2061 if (DBG) logd("target device reaches group limit.");
2063 // if the target group has reached the limit,
2064 // try group formation.
2067 int netId = mGroups.getNetworkId(dev.deviceAddress, ssid);
2069 // Skip WPS and start 4way handshake immediately.
2070 if (!mWifiNative.p2pGroupAdd(netId)) {
2071 return CONNECT_FAILURE;
2073 return CONNECT_SUCCESS;
2077 if (!join && dev.isDeviceLimit()) {
2078 loge("target device reaches the device limit.");
2079 return CONNECT_FAILURE;
2082 if (!join && tryInvocation && dev.isInvitationCapable()) {
2083 int netId = WifiP2pGroup.PERSISTENT_NET_ID;
2084 if (config.netId >= 0) {
2085 if (config.deviceAddress.equals(mGroups.getOwnerAddr(config.netId))) {
2086 netId = config.netId;
2089 netId = mGroups.getNetworkId(dev.deviceAddress);
2092 netId = getNetworkIdFromClientList(dev.deviceAddress);
2094 if (DBG) logd("netId related with " + dev.deviceAddress + " = " + netId);
2096 // Invoke the persistent group.
2097 if (mWifiNative.p2pReinvoke(netId, dev.deviceAddress)) {
2098 // Save network id. It'll be used when an invitation result event is received.
2099 mSavedPeerConfig.netId = netId;
2100 return CONNECT_SUCCESS;
2102 loge("p2pReinvoke() failed, update networks");
2103 updatePersistentNetworks(RELOAD);
2104 // continue with negotiation
2109 //Stop discovery before issuing connect
2110 mWifiNative.p2pStopFind();
2113 return NEEDS_PROVISION_REQ;
2116 p2pConnectWithPinDisplay(config);
2117 return CONNECT_SUCCESS;
2121 * Return the network id of the group owner profile which has the p2p client with
2122 * the specified device address in it's client list.
2123 * If more than one persistent group of the same address is present in its client
2124 * lists, return the first one.
2126 * @param deviceAddress p2p device address.
2127 * @return the network id. if not found, return -1.
2129 private int getNetworkIdFromClientList(String deviceAddress) {
2130 if (deviceAddress == null) return -1;
2132 Collection<WifiP2pGroup> groups = mGroups.getGroupList();
2133 for (WifiP2pGroup group : groups) {
2134 int netId = group.getNetworkId();
2135 String[] p2pClientList = getClientList(netId);
2136 if (p2pClientList == null) continue;
2137 for (String client : p2pClientList) {
2138 if (deviceAddress.equalsIgnoreCase(client)) {
2147 * Return p2p client list associated with the specified network id.
2148 * @param netId network id.
2149 * @return p2p client list. if not found, return null.
2151 private String[] getClientList(int netId) {
2152 String p2pClients = mWifiNative.getNetworkVariable(netId, "p2p_client_list");
2153 if (p2pClients == null) {
2156 return p2pClients.split(" ");
2160 * Remove the specified p2p client from the specified profile.
2161 * @param netId network id of the profile.
2162 * @param addr p2p client address to be removed.
2163 * @param isRemovable if true, remove the specified profile if its client list becomes empty.
2164 * @return whether removing the specified p2p client is successful or not.
2166 private boolean removeClientFromList(int netId, String addr, boolean isRemovable) {
2167 StringBuilder modifiedClientList = new StringBuilder();
2168 String[] currentClientList = getClientList(netId);
2169 boolean isClientRemoved = false;
2170 if (currentClientList != null) {
2171 for (String client : currentClientList) {
2172 if (!client.equalsIgnoreCase(addr)) {
2173 modifiedClientList.append(" ");
2174 modifiedClientList.append(client);
2176 isClientRemoved = true;
2180 if (modifiedClientList.length() == 0 && isRemovable) {
2181 // the client list is empty. so remove it.
2182 if (DBG) logd("Remove unknown network");
2183 mGroups.remove(netId);
2187 if (!isClientRemoved) {
2188 // specified p2p client is not found. already removed.
2192 if (DBG) logd("Modified client list: " + modifiedClientList);
2193 if (modifiedClientList.length() == 0) {
2194 modifiedClientList.append("\"\"");
2196 mWifiNative.setNetworkVariable(netId,
2197 "p2p_client_list", modifiedClientList.toString());
2198 mWifiNative.saveConfig();
2202 private void setWifiP2pInfoOnGroupFormation(String serverAddress) {
2203 mWifiP2pInfo.groupFormed = true;
2204 mWifiP2pInfo.isGroupOwner = mGroup.isGroupOwner();
2205 mWifiP2pInfo.groupOwnerAddress = NetworkUtils.numericToInetAddress(serverAddress);
2208 private void resetWifiP2pInfo() {
2209 mWifiP2pInfo.groupFormed = false;
2210 mWifiP2pInfo.isGroupOwner = false;
2211 mWifiP2pInfo.groupOwnerAddress = null;
2214 private String getDeviceName(String deviceAddress) {
2215 WifiP2pDevice d = mPeers.get(deviceAddress);
2217 return d.deviceName;
2219 //Treat the address as name if there is no match
2220 return deviceAddress;
2223 private void p2pConnectWithPinDisplay(WifiP2pConfig config) {
2224 WifiP2pDevice dev = mPeers.get(config.deviceAddress);
2226 loge("target device is not found " + config.deviceAddress);
2230 String pin = mWifiNative.p2pConnect(config, dev.isGroupOwner());
2232 Integer.parseInt(pin);
2233 if (!sendShowPinReqToFrontApp(pin)) {
2234 notifyInvitationSent(pin, config.deviceAddress);
2236 } catch (NumberFormatException ignore) {
2237 // do nothing if p2pConnect did not return a pin
2241 private String getPersistedDeviceName() {
2242 String deviceName = Settings.Global.getString(mContext.getContentResolver(),
2243 Settings.Global.WIFI_P2P_DEVICE_NAME);
2244 if (deviceName == null) {
2245 /* We use the 4 digits of the ANDROID_ID to have a friendly
2246 * default that has low likelihood of collision with a peer */
2247 String id = Settings.Secure.getString(mContext.getContentResolver(),
2248 Settings.Secure.ANDROID_ID);
2249 return "Android_" + id.substring(0,4);
2254 private boolean setAndPersistDeviceName(String devName) {
2255 if (devName == null) return false;
2257 if (!mWifiNative.setDeviceName(devName)) {
2258 loge("Failed to set device name " + devName);
2262 mThisDevice.deviceName = devName;
2263 mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName);
2265 Settings.Global.putString(mContext.getContentResolver(),
2266 Settings.Global.WIFI_P2P_DEVICE_NAME, devName);
2267 sendThisDeviceChangedBroadcast();
2271 private boolean setWfdInfo(WifiP2pWfdInfo wfdInfo) {
2274 if (!wfdInfo.isWfdEnabled()) {
2275 success = mWifiNative.setWfdEnable(false);
2278 mWifiNative.setWfdEnable(true)
2279 && mWifiNative.setWfdDeviceInfo(wfdInfo.getDeviceInfoHex());
2283 loge("Failed to set wfd properties");
2287 mThisDevice.wfdInfo = wfdInfo;
2288 sendThisDeviceChangedBroadcast();
2292 private void initializeP2pSettings() {
2293 mWifiNative.setPersistentReconnect(true);
2294 mThisDevice.deviceName = getPersistedDeviceName();
2295 mWifiNative.setDeviceName(mThisDevice.deviceName);
2296 // DIRECT-XY-DEVICENAME (XY is randomly generated)
2297 mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName);
2298 mWifiNative.setDeviceType(mThisDevice.primaryDeviceType);
2299 // Supplicant defaults to using virtual display with display
2300 // which refers to a remote display. Use physical_display
2301 mWifiNative.setConfigMethods("virtual_push_button physical_display keypad");
2302 // STA has higher priority over P2P
2303 mWifiNative.setConcurrencyPriority("sta");
2305 mThisDevice.deviceAddress = mWifiNative.p2pGetDeviceAddress();
2306 updateThisDevice(WifiP2pDevice.AVAILABLE);
2307 if (DBG) Slog.d(TAG, "DeviceAddress: " + mThisDevice.deviceAddress);
2309 mClientInfoList.clear();
2310 mWifiNative.p2pFlush();
2311 mWifiNative.p2pServiceFlush();
2312 mServiceTransactionId = 0;
2313 mServiceDiscReqId = null;
2315 updatePersistentNetworks(RELOAD);
2318 private void updateThisDevice(int status) {
2319 mThisDevice.status = status;
2320 sendThisDeviceChangedBroadcast();
2323 private void handleGroupCreationFailure() {
2325 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.FAILED, null, null);
2326 sendP2pConnectionChangedBroadcast();
2327 mSavedPeerConfig = null;
2328 /* After cancelling group formation, new connections on existing peers can fail
2329 * at supplicant. Flush and restart discovery */
2330 mWifiNative.p2pFlush();
2331 if (mPeers.remove(mPeersLostDuringConnection)) sendP2pPeersChangedBroadcast();
2332 mPeersLostDuringConnection.clear();
2333 mServiceDiscReqId = null;
2334 sendMessage(WifiP2pManager.DISCOVER_PEERS);
2337 private void handleGroupRemoved() {
2338 Collection <WifiP2pDevice> devices = mGroup.getClientList();
2339 boolean changed = false;
2340 for (WifiP2pDevice d : mPeers.getDeviceList()) {
2341 if (devices.contains(d) || mGroup.getOwner().equals(d)) {
2342 d.status = WifiP2pDevice.AVAILABLE;
2347 if (mGroup.isGroupOwner()) {
2348 stopDhcpServer(mGroup.getInterface());
2350 if (DBG) logd("stop DHCP client");
2351 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
2352 mDhcpStateMachine.doQuit();
2353 mDhcpStateMachine = null;
2357 mNwService.clearInterfaceAddresses(mGroup.getInterface());
2358 } catch (Exception e) {
2359 loge("Failed to clear addresses " + e);
2361 NetworkUtils.resetConnections(mGroup.getInterface(), NetworkUtils.RESET_ALL_ADDRESSES);
2363 // Clear any timeout that was set. This is essential for devices
2364 // that reuse the main p2p interface for a created group.
2365 mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0);
2368 mWifiNative.p2pFlush();
2369 if (mPeers.remove(mPeersLostDuringConnection)) sendP2pPeersChangedBroadcast();
2370 mPeersLostDuringConnection.clear();
2371 mServiceDiscReqId = null;
2372 if (changed) sendP2pPeersChangedBroadcast();
2374 if (mTempoarilyDisconnectedWifi) {
2375 mWifiChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_REQUEST, 0);
2376 mTempoarilyDisconnectedWifi = false;
2380 //State machine initiated requests can have replyTo set to null indicating
2381 //there are no recipients, we ignore those reply actions
2382 private void replyToMessage(Message msg, int what) {
2383 if (msg.replyTo == null) return;
2384 Message dstMsg = obtainMessage(msg);
2386 mReplyChannel.replyToMessage(msg, dstMsg);
2389 private void replyToMessage(Message msg, int what, int arg1) {
2390 if (msg.replyTo == null) return;
2391 Message dstMsg = obtainMessage(msg);
2394 mReplyChannel.replyToMessage(msg, dstMsg);
2397 private void replyToMessage(Message msg, int what, Object obj) {
2398 if (msg.replyTo == null) return;
2399 Message dstMsg = obtainMessage(msg);
2402 mReplyChannel.replyToMessage(msg, dstMsg);
2405 /* arg2 on the source message has a hash code that needs to be retained in replies
2406 * see WifiP2pManager for details */
2407 private Message obtainMessage(Message srcMsg) {
2408 Message msg = Message.obtain();
2409 msg.arg2 = srcMsg.arg2;
2413 private void logd(String s) {
2417 private void loge(String s) {
2422 * Update service discovery request to wpa_supplicant.
2424 private boolean updateSupplicantServiceRequest() {
2425 clearSupplicantServiceRequest();
2427 StringBuffer sb = new StringBuffer();
2428 for (ClientInfo c: mClientInfoList.values()) {
2430 WifiP2pServiceRequest req;
2431 for (int i=0; i < c.mReqList.size(); i++) {
2432 req = c.mReqList.valueAt(i);
2434 sb.append(req.getSupplicantQuery());
2439 if (sb.length() == 0) {
2443 mServiceDiscReqId = mWifiNative.p2pServDiscReq("00:00:00:00:00:00", sb.toString());
2444 if (mServiceDiscReqId == null) {
2451 * Clear service discovery request in wpa_supplicant
2453 private void clearSupplicantServiceRequest() {
2454 if (mServiceDiscReqId == null) return;
2456 mWifiNative.p2pServDiscCancelReq(mServiceDiscReqId);
2457 mServiceDiscReqId = null;
2460 /* TODO: We could track individual service adds separately and avoid
2461 * having to do update all service requests on every new request
2463 private boolean addServiceRequest(Messenger m, WifiP2pServiceRequest req) {
2464 clearClientDeadChannels();
2465 ClientInfo clientInfo = getClientInfo(m, true);
2466 if (clientInfo == null) {
2470 ++mServiceTransactionId;
2471 //The Wi-Fi p2p spec says transaction id should be non-zero
2472 if (mServiceTransactionId == 0) ++mServiceTransactionId;
2473 req.setTransactionId(mServiceTransactionId);
2474 clientInfo.mReqList.put(mServiceTransactionId, req);
2476 if (mServiceDiscReqId == null) {
2480 return updateSupplicantServiceRequest();
2483 private void removeServiceRequest(Messenger m, WifiP2pServiceRequest req) {
2484 ClientInfo clientInfo = getClientInfo(m, false);
2485 if (clientInfo == null) {
2489 //Application does not have transaction id information
2490 //go through stored requests to remove
2491 boolean removed = false;
2492 for (int i=0; i<clientInfo.mReqList.size(); i++) {
2493 if (req.equals(clientInfo.mReqList.valueAt(i))) {
2495 clientInfo.mReqList.removeAt(i);
2500 if (!removed) return;
2502 if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) {
2503 if (DBG) logd("remove client information from framework");
2504 mClientInfoList.remove(clientInfo.mMessenger);
2507 if (mServiceDiscReqId == null) {
2511 updateSupplicantServiceRequest();
2514 private void clearServiceRequests(Messenger m) {
2516 ClientInfo clientInfo = getClientInfo(m, false);
2517 if (clientInfo == null) {
2521 if (clientInfo.mReqList.size() == 0) {
2525 clientInfo.mReqList.clear();
2527 if (clientInfo.mServList.size() == 0) {
2528 if (DBG) logd("remove channel information from framework");
2529 mClientInfoList.remove(clientInfo.mMessenger);
2532 if (mServiceDiscReqId == null) {
2536 updateSupplicantServiceRequest();
2539 private boolean addLocalService(Messenger m, WifiP2pServiceInfo servInfo) {
2540 clearClientDeadChannels();
2541 ClientInfo clientInfo = getClientInfo(m, true);
2542 if (clientInfo == null) {
2546 if (!clientInfo.mServList.add(servInfo)) {
2550 if (!mWifiNative.p2pServiceAdd(servInfo)) {
2551 clientInfo.mServList.remove(servInfo);
2558 private void removeLocalService(Messenger m, WifiP2pServiceInfo servInfo) {
2559 ClientInfo clientInfo = getClientInfo(m, false);
2560 if (clientInfo == null) {
2564 mWifiNative.p2pServiceDel(servInfo);
2566 clientInfo.mServList.remove(servInfo);
2567 if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) {
2568 if (DBG) logd("remove client information from framework");
2569 mClientInfoList.remove(clientInfo.mMessenger);
2573 private void clearLocalServices(Messenger m) {
2574 ClientInfo clientInfo = getClientInfo(m, false);
2575 if (clientInfo == null) {
2579 for (WifiP2pServiceInfo servInfo: clientInfo.mServList) {
2580 mWifiNative.p2pServiceDel(servInfo);
2583 clientInfo.mServList.clear();
2584 if (clientInfo.mReqList.size() == 0) {
2585 if (DBG) logd("remove client information from framework");
2586 mClientInfoList.remove(clientInfo.mMessenger);
2590 private void clearClientInfo(Messenger m) {
2591 clearLocalServices(m);
2592 clearServiceRequests(m);
2596 * Send the service response to the WifiP2pManager.Channel.
2600 private void sendServiceResponse(WifiP2pServiceResponse resp) {
2601 for (ClientInfo c : mClientInfoList.values()) {
2602 WifiP2pServiceRequest req = c.mReqList.get(resp.getTransactionId());
2604 Message msg = Message.obtain();
2605 msg.what = WifiP2pManager.RESPONSE_SERVICE;
2610 c.mMessenger.send(msg);
2611 } catch (RemoteException e) {
2612 if (DBG) logd("detect dead channel");
2613 clearClientInfo(c.mMessenger);
2621 * We dont get notifications of clients that have gone away.
2622 * We detect this actively when services are added and throw
2625 * TODO: This can be done better with full async channels.
2627 private void clearClientDeadChannels() {
2628 ArrayList<Messenger> deadClients = new ArrayList<Messenger>();
2630 for (ClientInfo c : mClientInfoList.values()) {
2631 Message msg = Message.obtain();
2632 msg.what = WifiP2pManager.PING;
2637 c.mMessenger.send(msg);
2638 } catch (RemoteException e) {
2639 if (DBG) logd("detect dead channel");
2640 deadClients.add(c.mMessenger);
2644 for (Messenger m : deadClients) {
2650 * Return the specified ClientInfo.
2651 * @param m Messenger
2652 * @param createIfNotExist if true and the specified channel info does not exist,
2653 * create new client info.
2654 * @return the specified ClientInfo.
2656 private ClientInfo getClientInfo(Messenger m, boolean createIfNotExist) {
2657 ClientInfo clientInfo = mClientInfoList.get(m);
2659 if (clientInfo == null && createIfNotExist) {
2660 if (DBG) logd("add a new client");
2661 clientInfo = new ClientInfo(m);
2662 mClientInfoList.put(m, clientInfo);
2669 * Send detached message to dialog listener in the foreground application.
2672 private void sendDetachedMsg(int reason) {
2673 if (mForegroundAppMessenger == null) return;
2675 Message msg = Message.obtain();
2676 msg.what = WifiP2pManager.DIALOG_LISTENER_DETACHED;
2679 mForegroundAppMessenger.send(msg);
2680 } catch (RemoteException e) {
2682 mForegroundAppMessenger = null;
2683 mForegroundAppPkgName = null;
2687 * Send a request to show wps pin to dialog listener in the foreground application.
2688 * @param pin WPS pin
2691 private boolean sendShowPinReqToFrontApp(String pin) {
2692 if (!isForegroundApp(mForegroundAppPkgName)) {
2693 sendDetachedMsg(WifiP2pManager.NOT_IN_FOREGROUND);
2696 Message msg = Message.obtain();
2697 msg.what = WifiP2pManager.SHOW_PIN_REQUESTED;
2698 Bundle bundle = new Bundle();
2699 bundle.putString(WifiP2pManager.WPS_PIN_BUNDLE_KEY, pin);
2700 msg.setData(bundle);
2701 return sendDialogMsgToFrontApp(msg);
2705 * Send a request to establish the connection to dialog listener in the foreground
2707 * @param dev source device
2711 private boolean sendConnectNoticeToApp(WifiP2pDevice dev, WifiP2pConfig config) {
2713 dev = new WifiP2pDevice(config.deviceAddress);
2716 if (!isForegroundApp(mForegroundAppPkgName)) {
2717 if (DBG) logd("application is NOT foreground");
2718 sendDetachedMsg(WifiP2pManager.NOT_IN_FOREGROUND);
2722 Message msg = Message.obtain();
2723 msg.what = WifiP2pManager.CONNECTION_REQUESTED;
2724 Bundle bundle = new Bundle();
2725 bundle.putParcelable(WifiP2pManager.P2P_DEV_BUNDLE_KEY, dev);
2726 bundle.putParcelable(WifiP2pManager.P2P_CONFIG_BUNDLE_KEY, config);
2727 msg.setData(bundle);
2728 return sendDialogMsgToFrontApp(msg);
2732 * Send dialog event message to front application's dialog listener.
2734 * @return true if success.
2736 private boolean sendDialogMsgToFrontApp(Message msg) {
2738 mForegroundAppMessenger.send(msg);
2739 } catch (RemoteException e) {
2740 mForegroundAppMessenger = null;
2741 mForegroundAppPkgName = null;
2748 * Set dialog listener application.
2750 * @param appPkgName if null, reset the listener.
2751 * @param isReset if true, try to reset.
2754 private boolean setDialogListenerApp(Messenger m,
2755 String appPkgName, boolean isReset) {
2757 if (mForegroundAppPkgName != null && !mForegroundAppPkgName.equals(appPkgName)) {
2758 if (isForegroundApp(mForegroundAppPkgName)) {
2759 // The current dialog listener is foreground app's.
2760 if (DBG) logd("application is NOT foreground");
2763 // detach an old listener.
2764 sendDetachedMsg(WifiP2pManager.NOT_IN_FOREGROUND);
2768 if (DBG) logd("reset dialog listener");
2769 mForegroundAppMessenger = null;
2770 mForegroundAppPkgName = null;
2774 if (!isForegroundApp(appPkgName)) {
2778 mForegroundAppMessenger = m;
2779 mForegroundAppPkgName = appPkgName;
2780 if (DBG) logd("set dialog listener. app=" + appPkgName);
2785 * Return true if the specified package name is foreground app's.
2787 * @param pkgName application package name.
2790 private boolean isForegroundApp(String pkgName) {
2791 if (pkgName == null) return false;
2793 List<RunningTaskInfo> tasks = mActivityMgr.getRunningTasks(1);
2794 if (tasks.size() == 0) {
2798 return pkgName.equals(tasks.get(0).baseActivity.getPackageName());
2804 * Information about a particular client and we track the service discovery requests
2805 * and the local services registered by the client.
2807 private class ClientInfo {
2810 * A reference to WifiP2pManager.Channel handler.
2811 * The response of this request is notified to WifiP2pManager.Channel handler
2813 private Messenger mMessenger;
2816 * A service discovery request list.
2818 private SparseArray<WifiP2pServiceRequest> mReqList;
2821 * A local service information list.
2823 private List<WifiP2pServiceInfo> mServList;
2825 private ClientInfo(Messenger m) {
2827 mReqList = new SparseArray();
2828 mServList = new ArrayList<WifiP2pServiceInfo>();