OSDN Git Service

Merge "add Toshiba usb driver link delete Fujitsu-Toshiba bug: 9755017" into jb-mr1...
[android-x86/frameworks-base.git] / wifi / java / android / net / wifi / p2p / WifiP2pService.java
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package android.net.wifi.p2p;
18
19 import android.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;
77
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;
84
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;
91
92 /**
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.
97  *
98  * Note that the term Wifi when used without a p2p suffix refers to the client mode
99  * of Wifi operation
100  * @hide
101  */
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";
106
107     private Context mContext;
108     private String mInterface;
109     private Notification mNotification;
110
111     INetworkManagementService mNwService;
112     private DhcpStateMachine mDhcpStateMachine;
113
114     private ActivityManager mActivityMgr;
115
116     private P2pStateMachine mP2pStateMachine;
117     private AsyncChannel mReplyChannel = new AsyncChannel();
118     private AsyncChannel mWifiChannel;
119
120     private static final Boolean JOIN_GROUP = true;
121     private static final Boolean FORM_GROUP = false;
122
123     private static final Boolean TRY_REINVOCATION = true;;
124     private static final Boolean NO_REINVOCATION = false;
125
126     private static final Boolean RELOAD = true;
127     private static final Boolean NO_RELOAD = false;
128
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;
132
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;
136
137     private static final int DISABLE_P2P_WAIT_TIME_MS = 5 * 1000;
138     private static int mDisableP2pTimeoutIndex = 0;
139
140     /* Set a two minute discover timeout to avoid STA scans from being blocked */
141     private static final int DISCOVER_TIMEOUT_S = 120;
142
143     /* Idle time after a peer is gone when the group is torn down */
144     private static final int GROUP_IDLE_TIME_S = 10;
145
146     private static final int BASE = Protocol.BASE_WIFI_P2P_SERVICE;
147
148     /* Delayed message to timeout group creation */
149     public static final int GROUP_CREATING_TIMED_OUT        =   BASE + 1;
150
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;
161
162
163     /* Commands to the WifiStateMachine */
164     public static final int P2P_CONNECTION_CHANGED          =   BASE + 11;
165
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.
169      *
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
172      * bring back wifi up
173      *
174      * DISCONNECT_WIFI_REQUEST
175      *      msg.arg1 = 1 enables temporary disconnect and 0 disables it.
176      */
177     public static final int DISCONNECT_WIFI_REQUEST         =   BASE + 12;
178     public static final int DISCONNECT_WIFI_RESPONSE        =   BASE + 13;
179
180     private final boolean mP2pSupported;
181
182     private WifiP2pDevice mThisDevice = new WifiP2pDevice();
183
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
186      * is invoked */
187     private boolean mAutonomousGroup;
188
189     /* Invitation to join an existing p2p group */
190     private boolean mJoinExistingGroup;
191
192     /* Track whether we are in p2p discovery. This is used to avoid sending duplicate
193      * broadcasts
194      */
195     private boolean mDiscoveryStarted;
196
197     private NetworkInfo mNetworkInfo;
198
199     private boolean mTempoarilyDisconnectedWifi = false;
200
201     /* The transaction Id of service discovery request */
202     private byte mServiceTransactionId = 0;
203
204     /* Service discovery request ID of wpa_supplicant.
205      * null means it's not set yet. */
206     private String mServiceDiscReqId;
207
208     /* clients(application) information list. */
209     private HashMap<Messenger, ClientInfo> mClientInfoList = new HashMap<Messenger, ClientInfo>();
210
211     /* The foreground application's messenger.
212      * The connection request is notified only to foreground application  */
213     private Messenger mForegroundAppMessenger;
214
215     /* the package name of foreground application. */
216     private String mForegroundAppPkgName;
217
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";
222
223     /**
224      * Error code definition.
225      * see the Table.8 in the WiFi Direct specification for the detail.
226      */
227     public static enum P2pStatus {
228         /* Success. */
229         SUCCESS,
230
231         /* The target device is currently unavailable. */
232         INFORMATION_IS_CURRENTLY_UNAVAILABLE,
233
234         /* Protocol error. */
235         INCOMPATIBLE_PARAMETERS,
236
237         /* The target device reached the limit of the number of the connectable device.
238          * For example, device limit or group limit is set. */
239         LIMIT_REACHED,
240
241         /* Protocol error. */
242         INVALID_PARAMETER,
243
244         /* Unable to accommodate request. */
245         UNABLE_TO_ACCOMMODATE_REQUEST,
246
247         /* Previous protocol error, or disruptive behavior. */
248         PREVIOUS_PROTOCOL_ERROR,
249
250         /* There is no common channels the both devices can use. */
251         NO_COMMON_CHANNEL,
252
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. */
255         UNKNOWN_P2P_GROUP,
256
257         /* Both p2p devices indicated an intent of 15 in group owner negotiation. */
258         BOTH_GO_INTENT_15,
259
260         /* Incompatible provisioning method. */
261         INCOMPATIBLE_PROVISIONING_METHOD,
262
263         /* Rejected by user */
264         REJECTED_BY_USER,
265
266         /* Unknown error */
267         UNKNOWN;
268
269         public static P2pStatus valueOf(int error) {
270             switch(error) {
271             case 0 :
272                 return SUCCESS;
273             case 1:
274                 return INFORMATION_IS_CURRENTLY_UNAVAILABLE;
275             case 2:
276                 return INCOMPATIBLE_PARAMETERS;
277             case 3:
278                 return LIMIT_REACHED;
279             case 4:
280                 return INVALID_PARAMETER;
281             case 5:
282                 return UNABLE_TO_ACCOMMODATE_REQUEST;
283             case 6:
284                 return PREVIOUS_PROTOCOL_ERROR;
285             case 7:
286                 return NO_COMMON_CHANNEL;
287             case 8:
288                 return UNKNOWN_P2P_GROUP;
289             case 9:
290                 return BOTH_GO_INTENT_15;
291             case 10:
292                 return INCOMPATIBLE_PROVISIONING_METHOD;
293             case 11:
294                 return REJECTED_BY_USER;
295             default:
296                 return UNKNOWN;
297             }
298         }
299     }
300
301     public WifiP2pService(Context context) {
302         mContext = context;
303
304         //STOPSHIP: get this from native side
305         mInterface = "p2p0";
306         mActivityMgr = (ActivityManager)context.getSystemService(Activity.ACTIVITY_SERVICE);
307
308         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, "");
309
310         mP2pSupported = mContext.getPackageManager().hasSystemFeature(
311                 PackageManager.FEATURE_WIFI_DIRECT);
312
313         mThisDevice.primaryDeviceType = mContext.getResources().getString(
314                 com.android.internal.R.string.config_wifi_p2p_device_type);
315
316         mP2pStateMachine = new P2pStateMachine(TAG, mP2pSupported);
317         mP2pStateMachine.start();
318     }
319
320     public void connectivityServiceReady() {
321         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
322         mNwService = INetworkManagementService.Stub.asInterface(b);
323     }
324
325     private void enforceAccessPermission() {
326         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
327                 "WifiP2pService");
328     }
329
330     private void enforceChangePermission() {
331         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
332                 "WifiP2pService");
333     }
334
335     /**
336      * Get a reference to handler. This is used by a client to establish
337      * an AsyncChannel communication with WifiP2pService
338      */
339     public Messenger getMessenger() {
340         enforceAccessPermission();
341         enforceChangePermission();
342         return new Messenger(mP2pStateMachine.getHandler());
343     }
344
345     @Override
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());
352             return;
353         }
354     }
355
356
357     /**
358      * Handles interaction with WifiStateMachine
359      */
360     private class P2pStateMachine extends StateMachine {
361
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();
376
377         private GroupCreatedState mGroupCreatedState = new GroupCreatedState();
378         private UserAuthorizingJoinState mUserAuthorizingJoinState = new UserAuthorizingJoinState();
379         private OngoingGroupRemovalState mOngoingGroupRemovalState = new OngoingGroupRemovalState();
380
381         private WifiNative mWifiNative = new WifiNative(mInterface);
382         private WifiMonitor mWifiMonitor = new WifiMonitor(this, mWifiNative);
383
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.
388          *
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
392          */
393         private final WifiP2pDeviceList mPeersLostDuringConnection = new WifiP2pDeviceList();
394         private final WifiP2pGroupList mGroups = new WifiP2pGroupList(null,
395                 new GroupDeleteListener() {
396             @Override
397             public void onDeleteGroup(int netId) {
398                 if (DBG) logd("called onDeleteGroup() netId=" + netId);
399                 mWifiNative.removeNetwork(netId);
400                 mWifiNative.saveConfig();
401                 sendP2pPersistentGroupsChangedBroadcast();
402             }
403         });
404         private final WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo();
405         private WifiP2pGroup mGroup;
406
407         // Saved WifiP2pConfig for a peer connection
408         private WifiP2pConfig mSavedPeerConfig;
409
410         // Saved WifiP2pGroup from invitation request
411         private WifiP2pGroup mSavedP2pGroup;
412
413         // Saved WifiP2pDevice from provisioning request
414         private WifiP2pDevice mSavedProvDiscDevice;
415
416         P2pStateMachine(String name, boolean p2pSupported) {
417             super(name);
418
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);
434
435             if (p2pSupported) {
436                 setInitialState(mP2pDisabledState);
437             } else {
438                 setInitialState(mP2pNotSupportedState);
439             }
440         }
441
442     class DefaultState extends State {
443         @Override
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;
451                     } else {
452                         loge("Full connection failure, error = " + message.arg1);
453                         mWifiChannel = null;
454                     }
455                     break;
456
457                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
458                     if (message.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
459                         loge("Send failed, client connection lost");
460                     } else {
461                         loge("Client connection lost with reason: " + message.arg1);
462                     }
463                     mWifiChannel = null;
464                     break;
465
466                 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
467                     AsyncChannel ac = new AsyncChannel();
468                     ac.connect(mContext, getHandler(), message.replyTo);
469                     break;
470                 case WifiP2pManager.DISCOVER_PEERS:
471                     replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
472                             WifiP2pManager.BUSY);
473                     break;
474                 case WifiP2pManager.STOP_DISCOVERY:
475                     replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
476                             WifiP2pManager.BUSY);
477                     break;
478                 case WifiP2pManager.DISCOVER_SERVICES:
479                     replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
480                             WifiP2pManager.BUSY);
481                     break;
482                 case WifiP2pManager.CONNECT:
483                     replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
484                             WifiP2pManager.BUSY);
485                     break;
486                 case WifiP2pManager.CANCEL_CONNECT:
487                     replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
488                             WifiP2pManager.BUSY);
489                     break;
490                 case WifiP2pManager.CREATE_GROUP:
491                     replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
492                             WifiP2pManager.BUSY);
493                     break;
494                 case WifiP2pManager.REMOVE_GROUP:
495                     replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
496                             WifiP2pManager.BUSY);
497                     break;
498                 case WifiP2pManager.ADD_LOCAL_SERVICE:
499                     replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED,
500                             WifiP2pManager.BUSY);
501                     break;
502                 case WifiP2pManager.REMOVE_LOCAL_SERVICE:
503                     replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED,
504                             WifiP2pManager.BUSY);
505                     break;
506                 case WifiP2pManager.CLEAR_LOCAL_SERVICES:
507                     replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED,
508                             WifiP2pManager.BUSY);
509                     break;
510                 case WifiP2pManager.ADD_SERVICE_REQUEST:
511                     replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED,
512                             WifiP2pManager.BUSY);
513                     break;
514                 case WifiP2pManager.REMOVE_SERVICE_REQUEST:
515                     replyToMessage(message,
516                             WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED,
517                             WifiP2pManager.BUSY);
518                     break;
519                 case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
520                     replyToMessage(message,
521                             WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED,
522                             WifiP2pManager.BUSY);
523                     break;
524                 case WifiP2pManager.SET_DEVICE_NAME:
525                     replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
526                             WifiP2pManager.BUSY);
527                     break;
528                 case WifiP2pManager.DELETE_PERSISTENT_GROUP:
529                     replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP,
530                             WifiP2pManager.BUSY);
531                     break;
532                 case WifiP2pManager.SET_WFD_INFO:
533                     replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
534                             WifiP2pManager.BUSY);
535                     break;
536                 case WifiP2pManager.REQUEST_PEERS:
537                     replyToMessage(message, WifiP2pManager.RESPONSE_PEERS,
538                             new WifiP2pDeviceList(mPeers));
539                     break;
540                 case WifiP2pManager.REQUEST_CONNECTION_INFO:
541                     replyToMessage(message, WifiP2pManager.RESPONSE_CONNECTION_INFO,
542                             new WifiP2pInfo(mWifiP2pInfo));
543                     break;
544                 case WifiP2pManager.REQUEST_GROUP_INFO:
545                     replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO,
546                             mGroup != null ? new WifiP2pGroup(mGroup) : null);
547                     break;
548                 case WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO:
549                     replyToMessage(message, WifiP2pManager.RESPONSE_PERSISTENT_GROUP_INFO,
550                             new WifiP2pGroupList(mGroups, null));
551                     break;
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);
559                     } else {
560                         replyToMessage(message, WifiP2pManager.DIALOG_LISTENER_DETACHED,
561                                 WifiP2pManager.NOT_IN_FOREGROUND);
562                     }
563                     break;
564                     // Ignore
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:
593                     break;
594                 case WifiStateMachine.CMD_ENABLE_P2P:
595                     // Enable is lazy and has no response
596                     break;
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);
600                     break;
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());
606                     break;
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:
611                     break;
612                 default:
613                     loge("Unhandled message " + message);
614                     return NOT_HANDLED;
615             }
616             return HANDLED;
617         }
618     }
619
620     class P2pNotSupportedState extends State {
621         @Override
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);
627                     break;
628                 case WifiP2pManager.STOP_DISCOVERY:
629                     replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
630                             WifiP2pManager.P2P_UNSUPPORTED);
631                     break;
632                 case WifiP2pManager.DISCOVER_SERVICES:
633                     replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
634                             WifiP2pManager.P2P_UNSUPPORTED);
635                     break;
636                 case WifiP2pManager.CONNECT:
637                     replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
638                             WifiP2pManager.P2P_UNSUPPORTED);
639                     break;
640                 case WifiP2pManager.CANCEL_CONNECT:
641                     replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
642                             WifiP2pManager.P2P_UNSUPPORTED);
643                     break;
644                case WifiP2pManager.CREATE_GROUP:
645                     replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
646                             WifiP2pManager.P2P_UNSUPPORTED);
647                     break;
648                 case WifiP2pManager.REMOVE_GROUP:
649                     replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
650                             WifiP2pManager.P2P_UNSUPPORTED);
651                     break;
652                 case WifiP2pManager.ADD_LOCAL_SERVICE:
653                     replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED,
654                             WifiP2pManager.P2P_UNSUPPORTED);
655                     break;
656                 case WifiP2pManager.SET_DIALOG_LISTENER:
657                     replyToMessage(message, WifiP2pManager.DIALOG_LISTENER_DETACHED,
658                             WifiP2pManager.P2P_UNSUPPORTED);
659                     break;
660                 case WifiP2pManager.REMOVE_LOCAL_SERVICE:
661                     replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED,
662                             WifiP2pManager.P2P_UNSUPPORTED);
663                     break;
664                 case WifiP2pManager.CLEAR_LOCAL_SERVICES:
665                     replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED,
666                             WifiP2pManager.P2P_UNSUPPORTED);
667                     break;
668                 case WifiP2pManager.ADD_SERVICE_REQUEST:
669                     replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED,
670                             WifiP2pManager.P2P_UNSUPPORTED);
671                     break;
672                 case WifiP2pManager.REMOVE_SERVICE_REQUEST:
673                     replyToMessage(message,
674                             WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED,
675                             WifiP2pManager.P2P_UNSUPPORTED);
676                     break;
677                 case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
678                     replyToMessage(message,
679                             WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED,
680                             WifiP2pManager.P2P_UNSUPPORTED);
681                     break;
682                 case WifiP2pManager.SET_DEVICE_NAME:
683                     replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
684                             WifiP2pManager.P2P_UNSUPPORTED);
685                     break;
686                 case WifiP2pManager.DELETE_PERSISTENT_GROUP:
687                     replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP,
688                             WifiP2pManager.P2P_UNSUPPORTED);
689                     break;
690                 case WifiP2pManager.SET_WFD_INFO:
691                     replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
692                             WifiP2pManager.P2P_UNSUPPORTED);
693                     break;
694                default:
695                     return NOT_HANDLED;
696             }
697             return HANDLED;
698         }
699     }
700
701     class P2pDisablingState extends State {
702         @Override
703         public void enter() {
704             if (DBG) logd(getName());
705             sendMessageDelayed(obtainMessage(DISABLE_P2P_TIMED_OUT,
706                     ++mDisableP2pTimeoutIndex, 0), DISABLE_P2P_WAIT_TIME_MS);
707         }
708
709         @Override
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);
716                     break;
717                 case WifiStateMachine.CMD_ENABLE_P2P:
718                 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
719                     deferMessage(message);
720                     break;
721                 case DISABLE_P2P_TIMED_OUT:
722                     if (mGroupCreatingTimeoutIndex == message.arg1) {
723                         loge("P2p disable timed out");
724                         transitionTo(mP2pDisabledState);
725                     }
726                     break;
727                 default:
728                     return NOT_HANDLED;
729             }
730             return HANDLED;
731         }
732
733         @Override
734         public void exit() {
735             mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP);
736         }
737     }
738
739     class P2pDisabledState extends State {
740        @Override
741         public void enter() {
742             if (DBG) logd(getName());
743         }
744
745         @Override
746         public boolean processMessage(Message message) {
747             if (DBG) logd(getName() + message.toString());
748             switch (message.what) {
749                 case WifiStateMachine.CMD_ENABLE_P2P:
750                     try {
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);
756                     }
757                     mWifiMonitor.startMonitoring();
758                     transitionTo(mP2pEnablingState);
759                     break;
760                 default:
761                     return NOT_HANDLED;
762             }
763             return HANDLED;
764         }
765     }
766
767     class P2pEnablingState extends State {
768         @Override
769         public void enter() {
770             if (DBG) logd(getName());
771         }
772
773         @Override
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);
780                     break;
781                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
782                     loge("P2p socket connection failed");
783                     transitionTo(mP2pDisabledState);
784                     break;
785                 case WifiStateMachine.CMD_ENABLE_P2P:
786                 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
787                     deferMessage(message);
788                     break;
789                 default:
790                     return NOT_HANDLED;
791             }
792             return HANDLED;
793         }
794     }
795
796     class P2pEnabledState extends State {
797         @Override
798         public void enter() {
799             if (DBG) logd(getName());
800             sendP2pStateChangedBroadcast(true);
801             mNetworkInfo.setIsAvailable(true);
802             sendP2pConnectionChangedBroadcast();
803             initializeP2pSettings();
804         }
805
806         @Override
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);
813                     break;
814                 case WifiStateMachine.CMD_ENABLE_P2P:
815                     //Nothing to do
816                     break;
817                 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
818                     if (mPeers.clear()) sendP2pPeersChangedBroadcast();
819                     if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast();
820
821                     mWifiNative.closeSupplicantConnection();
822                     transitionTo(mP2pDisablingState);
823                     break;
824                 case WifiP2pManager.SET_DEVICE_NAME:
825                 {
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);
830                     } else {
831                         replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
832                                 WifiP2pManager.ERROR);
833                     }
834                     break;
835                 }
836                 case WifiP2pManager.SET_WFD_INFO:
837                 {
838                     WifiP2pWfdInfo d = (WifiP2pWfdInfo) message.obj;
839                     if (d != null && setWfdInfo(d)) {
840                         replyToMessage(message, WifiP2pManager.SET_WFD_INFO_SUCCEEDED);
841                     } else {
842                         replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
843                                 WifiP2pManager.ERROR);
844                     }
845                     break;
846                 }
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);
853                     } else {
854                         replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
855                                 WifiP2pManager.ERROR);
856                     }
857                     break;
858                 case WifiMonitor.P2P_FIND_STOPPED_EVENT:
859                     sendP2pDiscoveryChangedBroadcast(false);
860                     break;
861                 case WifiP2pManager.STOP_DISCOVERY:
862                     if (mWifiNative.p2pStopFind()) {
863                         replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED);
864                     } else {
865                         replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
866                                 WifiP2pManager.ERROR);
867                     }
868                     break;
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);
874                         break;
875                     }
876                     if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {
877                         replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_SUCCEEDED);
878                     } else {
879                         replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
880                                 WifiP2pManager.ERROR);
881                     }
882                     break;
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();
888                     break;
889                 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
890                     device = (WifiP2pDevice) message.obj;
891                     if (mPeers.remove(device)) sendP2pPeersChangedBroadcast();
892                     break;
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);
898                     } else {
899                         replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED);
900                     }
901                     break;
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);
907                     break;
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);
912                     break;
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);
917                         break;
918                     }
919                     replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_SUCCEEDED);
920                     break;
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);
925                     break;
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);
930                     break;
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) {
936                         WifiP2pDevice dev =
937                             mPeers.get(resp.getSrcDevice().deviceAddress);
938                         resp.setSrcDevice(dev);
939                         sendServiceResponse(resp);
940                     }
941                     break;
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);
946                    break;
947                 default:
948                     return NOT_HANDLED;
949             }
950             return HANDLED;
951         }
952
953         @Override
954         public void exit() {
955             sendP2pStateChangedBroadcast(false);
956             mNetworkInfo.setIsAvailable(false);
957         }
958     }
959
960     class InactiveState extends State {
961         @Override
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();
967         }
968
969         @Override
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;
977
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);
984                         break;
985                     }
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);
992                         break;
993                     }
994                     transitionTo(mGroupNegotiationState);
995                     break;
996                 case WifiP2pManager.STOP_DISCOVERY:
997                     if (mWifiNative.p2pStopFind()) {
998                         // When discovery stops in inactive state, flush to clear
999                         // state peer data
1000                         mWifiNative.p2pFlush();
1001                         mServiceDiscReqId = null;
1002                         replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED);
1003                     } else {
1004                         replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
1005                                 WifiP2pManager.ERROR);
1006                     }
1007                     break;
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);
1015                     }
1016                     break;
1017                 case WifiMonitor.P2P_INVITATION_RECEIVED_EVENT:
1018                     WifiP2pGroup group = (WifiP2pGroup) message.obj;
1019                     WifiP2pDevice owner = group.getOwner();
1020
1021                     if (owner == null) {
1022                         if (DBG) loge("Ignored invitation from null owner");
1023                         break;
1024                     }
1025
1026                     mSavedPeerConfig = new WifiP2pConfig();
1027                     mSavedPeerConfig.deviceAddress = group.getOwner().deviceAddress;
1028
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;
1038                         }
1039                     }
1040
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);
1047                     }
1048                     break;
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
1056                    break;
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);
1064                        if (netId != -1) {
1065                            ret = mWifiNative.p2pGroupAdd(netId);
1066                        } else {
1067                            ret = mWifiNative.p2pGroupAdd(true);
1068                        }
1069                    } else {
1070                        ret = mWifiNative.p2pGroupAdd(false);
1071                    }
1072
1073                    if (ret) {
1074                        replyToMessage(message, WifiP2pManager.CREATE_GROUP_SUCCEEDED);
1075                        transitionTo(mGroupNegotiationState);
1076                    } else {
1077                        replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
1078                                WifiP2pManager.ERROR);
1079                        // remain at this state.
1080                    }
1081                    break;
1082                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
1083                    mGroup = (WifiP2pGroup) message.obj;
1084                    if (DBG) logd(getName() + " group started");
1085
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);
1091                    } else {
1092                        loge("Unexpected group creation, remove " + mGroup);
1093                        mWifiNative.p2pGroupRemove(mGroup.getInterface());
1094                    }
1095                    break;
1096                 default:
1097                    return NOT_HANDLED;
1098             }
1099             return HANDLED;
1100         }
1101     }
1102
1103     class GroupCreatingState extends State {
1104         @Override
1105         public void enter() {
1106             if (DBG) logd(getName());
1107             sendMessageDelayed(obtainMessage(GROUP_CREATING_TIMED_OUT,
1108                     ++mGroupCreatingTimeoutIndex, 0), GROUP_CREATING_WAIT_TIME_MS);
1109         }
1110
1111         @Override
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);
1121                     }
1122                     break;
1123                 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
1124                     WifiP2pDevice device = (WifiP2pDevice) message.obj;
1125
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)) {
1130                         if (DBG) {
1131                             logd("mSavedPeerConfig " + mSavedPeerConfig.deviceAddress +
1132                                 "device " + device.deviceAddress);
1133                         }
1134                         // Do the regular device lost handling
1135                         ret = NOT_HANDLED;
1136                         break;
1137                     }
1138                     // Do nothing
1139                     if (DBG) logd("Add device to lost list " + device);
1140                     mPeersLostDuringConnection.update(device);
1141                     break;
1142                 case WifiP2pManager.DISCOVER_PEERS:
1143                     /* Discovery will break negotiation */
1144                     replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
1145                             WifiP2pManager.BUSY);
1146                     break;
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
1152                     //an inactive state
1153                     mWifiNative.p2pCancelConnect();
1154                     handleGroupCreationFailure();
1155                     transitionTo(mInactiveState);
1156                     replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_SUCCEEDED);
1157                     break;
1158                 default:
1159                     ret = NOT_HANDLED;
1160             }
1161             return ret;
1162         }
1163     }
1164
1165     class UserAuthorizingInvitationState extends State {
1166         @Override
1167         public void enter() {
1168             if (DBG) logd(getName());
1169             notifyInvitationReceived();
1170         }
1171
1172         @Override
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);
1181                         break;
1182                     }
1183                     mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
1184                     sendP2pPeersChangedBroadcast();
1185                     transitionTo(mGroupNegotiationState);
1186                     break;
1187                 case PEER_CONNECTION_USER_REJECT:
1188                     if (DBG) logd("User rejected invitation " + mSavedPeerConfig);
1189                     mSavedPeerConfig = null;
1190                     transitionTo(mInactiveState);
1191                     break;
1192                 default:
1193                     return NOT_HANDLED;
1194             }
1195             return ret;
1196         }
1197
1198         @Override
1199         public void exit() {
1200             //TODO: dismiss dialog if not already done
1201         }
1202     }
1203
1204     class ProvisionDiscoveryState extends State {
1205         @Override
1206         public void enter() {
1207             if (DBG) logd(getName());
1208             mWifiNative.p2pProvisionDiscovery(mSavedPeerConfig);
1209         }
1210
1211         @Override
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;
1221
1222                     if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
1223                         if (DBG) logd("Found a match " + mSavedPeerConfig);
1224                         p2pConnectWithPinDisplay(mSavedPeerConfig);
1225                         transitionTo(mGroupNegotiationState);
1226                     }
1227                     break;
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;
1232
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);
1239                         } else {
1240                             mJoinExistingGroup = false;
1241                             if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress),
1242                                     mSavedPeerConfig)) {
1243                                 transitionTo(mUserAuthorizingInvitationState);
1244                             }
1245                         }
1246                     }
1247                     break;
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;
1252
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);
1259                         }
1260                         transitionTo(mGroupNegotiationState);
1261                     }
1262                     break;
1263                 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
1264                     loge("provision discovery failed");
1265                     handleGroupCreationFailure();
1266                     transitionTo(mInactiveState);
1267                     break;
1268                 default:
1269                     return NOT_HANDLED;
1270             }
1271             return HANDLED;
1272         }
1273     }
1274
1275     class GroupNegotiationState extends State {
1276         @Override
1277         public void enter() {
1278             if (DBG) logd(getName());
1279         }
1280
1281         @Override
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
1286                 // afterwards
1287                 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
1288                 case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:
1289                     if (DBG) logd(getName() + " go success");
1290                     break;
1291                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
1292                     mGroup = (WifiP2pGroup) message.obj;
1293                     if (DBG) logd(getName() + " group started");
1294
1295                     if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) {
1296                         /*
1297                          * update cache information and set network id to mGroup.
1298                          */
1299                         updatePersistentNetworks(NO_RELOAD);
1300                         String devAddr = mGroup.getOwner().deviceAddress;
1301                         mGroup.setNetworkId(mGroups.getNetworkId(devAddr,
1302                                 mGroup.getNetworkName()));
1303                     }
1304
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
1308                          * save modes used.
1309                          *
1310                          * TODO: Verify multi-channel scenarios and supplicant behavior are
1311                          * better before adding a time out in future
1312                          */
1313                         startDhcpServer(mGroup.getInterface());
1314                     } else {
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();
1324                     }
1325                     mSavedPeerConfig = null;
1326                     transitionTo(mGroupCreatedState);
1327                     break;
1328                 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
1329                     P2pStatus status = (P2pStatus) message.obj;
1330                     if (status == P2pStatus.NO_COMMON_CHANNEL) {
1331                         transitionTo(mFrequencyConflictState);
1332                         break;
1333                     }
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);
1339                     break;
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);
1347                         break;
1348                     }
1349                     break;
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.
1355                         break;
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;
1360                         if (netId >= 0) {
1361                             if (DBG) logd("Remove unknown client from the list");
1362                             removeClientFromList(netId, mSavedPeerConfig.deviceAddress, true);
1363                         }
1364
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);
1370                         }
1371                     } else if (status == P2pStatus.NO_COMMON_CHANNEL) {
1372                         transitionTo(mFrequencyConflictState);
1373                     } else {
1374                         handleGroupCreationFailure();
1375                         transitionTo(mInactiveState);
1376                     }
1377                     break;
1378                 default:
1379                     return NOT_HANDLED;
1380             }
1381             return HANDLED;
1382         }
1383     }
1384
1385     class FrequencyConflictState extends State {
1386         private AlertDialog mFrequencyConflictDialog;
1387         @Override
1388         public void enter() {
1389             if (DBG) logd(getName());
1390             notifyFrequencyConflict();
1391         }
1392
1393         private void notifyFrequencyConflict() {
1394             logd("Notify frequency conflict");
1395             Resources r = Resources.getSystem();
1396
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() {
1401                         @Override
1402                         public void onClick(DialogInterface dialog, int which) {
1403                             sendMessage(DROP_WIFI_USER_ACCEPT);
1404                         }
1405                     })
1406                 .setNegativeButton(r.getString(R.string.decline), new OnClickListener() {
1407                         @Override
1408                         public void onClick(DialogInterface dialog, int which) {
1409                             sendMessage(DROP_WIFI_USER_REJECT);
1410                         }
1411                     })
1412                 .setOnCancelListener(new DialogInterface.OnCancelListener() {
1413                         @Override
1414                         public void onCancel(DialogInterface arg0) {
1415                             sendMessage(DROP_WIFI_USER_REJECT);
1416                         }
1417                     })
1418                 .create();
1419
1420             dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1421             dialog.show();
1422             mFrequencyConflictDialog = dialog;
1423         }
1424
1425         @Override
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!");
1432                     break;
1433                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
1434                     loge(getName() + "group started after freq conflict, handle anyway");
1435                     deferMessage(message);
1436                     transitionTo(mGroupNegotiationState);
1437                     break;
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
1442                     break;
1443                 case DROP_WIFI_USER_REJECT:
1444                     // User rejected dropping wifi in favour of p2p
1445                     handleGroupCreationFailure();
1446                     transitionTo(mInactiveState);
1447                     break;
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;
1452                     break;
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);
1458                     break;
1459                 default:
1460                     return NOT_HANDLED;
1461             }
1462             return HANDLED;
1463         }
1464
1465         public void exit() {
1466             if (mFrequencyConflictDialog != null) mFrequencyConflictDialog.dismiss();
1467         }
1468     }
1469
1470     class GroupCreatedState extends State {
1471         @Override
1472         public void enter() {
1473             if (DBG) logd(getName());
1474             mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
1475
1476             updateThisDevice(WifiP2pDevice.CONNECTED);
1477
1478             //DHCP server has already been started if I am a group owner
1479             if (mGroup.isGroupOwner()) {
1480                 setWifiP2pInfoOnGroupFormation(SERVER_ADDRESS);
1481             }
1482
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();
1487             }
1488         }
1489
1490         @Override
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;
1501                         }
1502                         if (mPeers.get(deviceAddress) != null) {
1503                             mGroup.addClient(mPeers.get(deviceAddress));
1504                         } else {
1505                             mGroup.addClient(deviceAddress);
1506                         }
1507                         mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED);
1508                         if (DBG) logd(getName() + " ap sta connected");
1509                         sendP2pPeersChangedBroadcast();
1510                     } else {
1511                         loge("Connect on null device address, ignore");
1512                     }
1513                     sendP2pConnectionChangedBroadcast();
1514                     break;
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()
1527                             } else {
1528                                 // Notify when a client disconnects from group
1529                                 sendP2pConnectionChangedBroadcast();
1530                             }
1531                         } else {
1532                             if (DBG) logd("Failed to remove client " + deviceAddress);
1533                             for (WifiP2pDevice c : mGroup.getClientList()) {
1534                                 if (DBG) logd("client " + c.deviceAddress);
1535                             }
1536                         }
1537                         sendP2pPeersChangedBroadcast();
1538                         if (DBG) logd(getName() + " ap sta disconnected");
1539                     } else {
1540                         loge("Disconnect on unknown device: " + device);
1541                     }
1542                     break;
1543                 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
1544                     DhcpInfoInternal dhcpInfo = (DhcpInfoInternal) message.obj;
1545                     if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS &&
1546                             dhcpInfo != null) {
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);
1552                     } else {
1553                         loge("DHCP failed");
1554                         mWifiNative.p2pGroupRemove(mGroup.getInterface());
1555                     }
1556                     break;
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);
1562                     } else {
1563                         handleGroupRemoved();
1564                         transitionTo(mInactiveState);
1565                         replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
1566                                 WifiP2pManager.ERROR);
1567                     }
1568                     break;
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.
1573                  *
1574                  * When there are connectivity issues during temporary disconnect, the application
1575                  * will also just remove the group.
1576                  *
1577                  * Treating network disconnection as group removal causes race conditions since
1578                  * supplicant would still maintain the group at that stage.
1579                  */
1580                 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
1581                     if (DBG) logd(getName() + " group removed");
1582                     handleGroupRemoved();
1583                     transitionTo(mInactiveState);
1584                     break;
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);
1591                         return HANDLED;
1592                     }
1593                     // Do the regular device lost handling
1594                     return NOT_HANDLED;
1595                 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
1596                     sendMessage(WifiP2pManager.REMOVE_GROUP);
1597                     deferMessage(message);
1598                     break;
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);
1607                         } else {
1608                             if (config.wps.pin == null) {
1609                                 String pin = mWifiNative.startWpsPinDisplay(mGroup.getInterface());
1610                                 try {
1611                                     Integer.parseInt(pin);
1612                                     if (!sendShowPinReqToFrontApp(pin)) {
1613                                         notifyInvitationSent(pin,
1614                                                 config.deviceAddress != null ?
1615                                                         config.deviceAddress : "any");
1616                                     }
1617                                 } catch (NumberFormatException ignore) {
1618                                     // do nothing if pin is invalid
1619                                 }
1620                             } else {
1621                                 mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
1622                                         config.wps.pin);
1623                             }
1624                         }
1625                         if (config.deviceAddress != null) {
1626                             mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED);
1627                             sendP2pPeersChangedBroadcast();
1628                         }
1629                         replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
1630                     } else {
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);
1637                         } else {
1638                             replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
1639                                     WifiP2pManager.ERROR);
1640                         }
1641                     }
1642                     // TODO: figure out updating the status to declined when invitation is rejected
1643                     break;
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.
1649                         break;
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();
1654                         if (netId >= 0) {
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");
1660                                 break;
1661                             }
1662                             // try invitation.
1663                             sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
1664                         }
1665                     }
1666                     break;
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;
1679                     } else {
1680                         mSavedPeerConfig.wps.setup = WpsInfo.PBC;
1681                     }
1682                     if (!sendConnectNoticeToApp(mSavedProvDiscDevice, mSavedPeerConfig)) {
1683                         transitionTo(mUserAuthorizingJoinState);
1684                     }
1685                     break;
1686                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
1687                     Slog.e(TAG, "Duplicate group creation event notice, ignore");
1688                     break;
1689                 default:
1690                     return NOT_HANDLED;
1691             }
1692             return HANDLED;
1693         }
1694
1695         public void exit() {
1696             mSavedProvDiscDevice = null;
1697             updateThisDevice(WifiP2pDevice.AVAILABLE);
1698             resetWifiP2pInfo();
1699             mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
1700             sendP2pConnectionChangedBroadcast();
1701         }
1702     }
1703
1704     class UserAuthorizingJoinState extends State {
1705         @Override
1706         public void enter() {
1707             if (DBG) logd(getName());
1708             notifyInvitationReceived();
1709         }
1710
1711         @Override
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
1719                     break;
1720                 case PEER_CONNECTION_USER_ACCEPT:
1721                     if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
1722                         mWifiNative.startWpsPbc(mGroup.getInterface(), null);
1723                     } else {
1724                         mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
1725                                 mSavedPeerConfig.wps.pin);
1726                     }
1727                     mSavedPeerConfig = null;
1728                     transitionTo(mGroupCreatedState);
1729                     break;
1730                 case PEER_CONNECTION_USER_REJECT:
1731                     if (DBG) logd("User rejected incoming request");
1732                     mSavedPeerConfig = null;
1733                     transitionTo(mGroupCreatedState);
1734                     break;
1735                 default:
1736                     return NOT_HANDLED;
1737             }
1738             return HANDLED;
1739         }
1740
1741         @Override
1742         public void exit() {
1743             //TODO: dismiss dialog if not already done
1744         }
1745     }
1746
1747     class OngoingGroupRemovalState extends State {
1748         @Override
1749         public void enter() {
1750             if (DBG) logd(getName());
1751         }
1752
1753         @Override
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);
1761                     break;
1762                 // Parent state will transition out of this state
1763                 // when removal is complete
1764                 default:
1765                     return NOT_HANDLED;
1766             }
1767             return HANDLED;
1768         }
1769     }
1770
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);
1774         if (enabled) {
1775             intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE,
1776                     WifiP2pManager.WIFI_P2P_STATE_ENABLED);
1777         } else {
1778             intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE,
1779                     WifiP2pManager.WIFI_P2P_STATE_DISABLED);
1780         }
1781         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1782     }
1783
1784     private void sendP2pDiscoveryChangedBroadcast(boolean started) {
1785         if (mDiscoveryStarted == started) return;
1786         mDiscoveryStarted = started;
1787
1788         if (DBG) logd("discovery change broadcast " + started);
1789
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);
1796     }
1797
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);
1803     }
1804
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);
1809     }
1810
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));
1821     }
1822
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);
1828     }
1829
1830     private void startDhcpServer(String intf) {
1831         InterfaceConfiguration ifcg = null;
1832         try {
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);
1842             return;
1843         }
1844
1845         logd("Started Dhcp server on " + intf);
1846    }
1847
1848     private void stopDhcpServer(String intf) {
1849         try {
1850             mNwService.stopTethering();
1851         } catch (Exception e) {
1852             loge("Error stopping Dhcp server" + e);
1853             return;
1854         }
1855
1856         logd("Stopped Dhcp server");
1857     }
1858
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)
1865             .create();
1866         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1867         dialog.show();
1868     }
1869
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,
1873                 group, false);
1874         ((TextView) row.findViewById(R.id.name)).setText(r.getString(stringId));
1875         ((TextView) row.findViewById(R.id.value)).setText(value);
1876         group.addView(row);
1877     }
1878
1879     private void notifyInvitationSent(String pin, String peerAddress) {
1880         Resources r = Resources.getSystem();
1881
1882         final View textEntryView = LayoutInflater.from(mContext)
1883                 .inflate(R.layout.wifi_p2p_dialog, null);
1884
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);
1888
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)
1893             .create();
1894         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1895         dialog.show();
1896     }
1897
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);
1903
1904         ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info);
1905         addRowToDialog(group, R.string.wifi_p2p_from_message, getDeviceName(
1906                 mSavedPeerConfig.deviceAddress));
1907
1908         final EditText pin = (EditText) textEntryView.findViewById(R.id.wifi_p2p_wps_pin);
1909
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();
1917                             }
1918                             if (DBG) logd(getName() + " accept invitation " + mSavedPeerConfig);
1919                             sendMessage(PEER_CONNECTION_USER_ACCEPT);
1920                         }
1921                     })
1922             .setNegativeButton(r.getString(R.string.decline), new OnClickListener() {
1923                         @Override
1924                         public void onClick(DialogInterface dialog, int which) {
1925                             if (DBG) logd(getName() + " ignore connect");
1926                             sendMessage(PEER_CONNECTION_USER_REJECT);
1927                         }
1928                     })
1929             .setOnCancelListener(new DialogInterface.OnCancelListener() {
1930                         @Override
1931                         public void onCancel(DialogInterface arg0) {
1932                             if (DBG) logd(getName() + " ignore connect");
1933                             sendMessage(PEER_CONNECTION_USER_REJECT);
1934                         }
1935                     })
1936             .create();
1937
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);
1943                 break;
1944             case WpsInfo.DISPLAY:
1945                 if (DBG) logd("Shown pin section visible");
1946                 addRowToDialog(group, R.string.wifi_p2p_show_pin_message, wps.pin);
1947                 break;
1948             default:
1949                 break;
1950         }
1951
1952         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1953         dialog.show();
1954     }
1955
1956     /**
1957      * Synchronize the persistent group list between
1958      * wpa_supplicant and mGroups.
1959      */
1960     private void updatePersistentNetworks(boolean reload) {
1961         String listStr = mWifiNative.listNetworks();
1962         if (listStr == null) return;
1963
1964         boolean isSaveRequired = false;
1965         String[] lines = listStr.split("\n");
1966         if (lines == null) return;
1967
1968         if (reload) mGroups.clear();
1969
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) {
1974                 continue;
1975             }
1976             // network-id | ssid | bssid | flags
1977             int netId = -1;
1978             String ssid = result[1];
1979             String bssid = result[2];
1980             String flags = result[3];
1981             try {
1982                 netId = Integer.parseInt(result[0]);
1983             } catch(NumberFormatException e) {
1984                 e.printStackTrace();
1985                 continue;
1986             }
1987
1988             if (flags.indexOf("[CURRENT]") != -1) {
1989                 continue;
1990             }
1991             if (flags.indexOf("[P2P-PERSISTENT]") == -1) {
1992                 /*
1993                  * The unused profile is sometimes remained when the p2p group formation is failed.
1994                  * So, we clean up the p2p group here.
1995                  */
1996                 if (DBG) logd("clean up the unused persistent group. netId=" + netId);
1997                 mWifiNative.removeNetwork(netId);
1998                 isSaveRequired = true;
1999                 continue;
2000             }
2001
2002             if (mGroups.contains(netId)) {
2003                 continue;
2004             }
2005
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);
2012             }
2013             if (bssid.equalsIgnoreCase(mThisDevice.deviceAddress)) {
2014                 group.setOwner(mThisDevice);
2015             } else {
2016                 WifiP2pDevice device = new WifiP2pDevice();
2017                 device.deviceAddress = bssid;
2018                 group.setOwner(device);
2019             }
2020             mGroups.add(group);
2021             isSaveRequired = true;
2022         }
2023
2024         if (reload || isSaveRequired) {
2025             mWifiNative.saveConfig();
2026             sendP2pPersistentGroupsChangedBroadcast();
2027         }
2028     }
2029
2030     /**
2031      * Try to connect to the target device.
2032      *
2033      * Use the persistent credential if it has been stored.
2034      *
2035      * @param config
2036      * @param tryInvocation if true, try to invoke. Otherwise, never try to invoke.
2037      * @return
2038      */
2039     private int connect(WifiP2pConfig config, boolean tryInvocation) {
2040
2041         if (config == null) {
2042             loge("config is null");
2043             return CONNECT_FAILURE;
2044         }
2045
2046         boolean isResp = (mSavedPeerConfig != null &&
2047                 config.deviceAddress.equals(mSavedPeerConfig.deviceAddress));
2048         mSavedPeerConfig = config;
2049
2050         WifiP2pDevice dev = mPeers.get(config.deviceAddress);
2051         if (dev == null) {
2052             loge("target device not found " + config.deviceAddress);
2053             return CONNECT_FAILURE;
2054         }
2055
2056         boolean join = dev.isGroupOwner();
2057         String ssid = mWifiNative.p2pGetSsid(dev.deviceAddress);
2058         if (DBG) logd("target ssid is " + ssid + " join:" + join);
2059
2060         if (join && dev.isGroupLimit()) {
2061             if (DBG) logd("target device reaches group limit.");
2062
2063             // if the target group has reached the limit,
2064             // try group formation.
2065             join = false;
2066         } else if (join) {
2067             int netId = mGroups.getNetworkId(dev.deviceAddress, ssid);
2068             if (netId >= 0) {
2069                 // Skip WPS and start 4way handshake immediately.
2070                 if (!mWifiNative.p2pGroupAdd(netId)) {
2071                     return CONNECT_FAILURE;
2072                 }
2073                 return CONNECT_SUCCESS;
2074             }
2075         }
2076
2077         if (!join && dev.isDeviceLimit()) {
2078             loge("target device reaches the device limit.");
2079             return CONNECT_FAILURE;
2080         }
2081
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;
2087                 }
2088             } else {
2089                 netId = mGroups.getNetworkId(dev.deviceAddress);
2090             }
2091             if (netId < 0) {
2092                 netId = getNetworkIdFromClientList(dev.deviceAddress);
2093             }
2094             if (DBG) logd("netId related with " + dev.deviceAddress + " = " + netId);
2095             if (netId >= 0) {
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;
2101                 } else {
2102                     loge("p2pReinvoke() failed, update networks");
2103                     updatePersistentNetworks(RELOAD);
2104                     // continue with negotiation
2105                 }
2106             }
2107         }
2108
2109         //Stop discovery before issuing connect
2110         mWifiNative.p2pStopFind();
2111
2112         if (!isResp) {
2113             return NEEDS_PROVISION_REQ;
2114         }
2115
2116         p2pConnectWithPinDisplay(config);
2117         return CONNECT_SUCCESS;
2118     }
2119
2120     /**
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.
2125      *
2126      * @param deviceAddress p2p device address.
2127      * @return the network id. if not found, return -1.
2128      */
2129     private int getNetworkIdFromClientList(String deviceAddress) {
2130         if (deviceAddress == null) return -1;
2131
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)) {
2139                     return netId;
2140                 }
2141             }
2142         }
2143         return -1;
2144     }
2145
2146     /**
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.
2150      */
2151     private String[] getClientList(int netId) {
2152         String p2pClients = mWifiNative.getNetworkVariable(netId, "p2p_client_list");
2153         if (p2pClients == null) {
2154             return null;
2155         }
2156         return p2pClients.split(" ");
2157     }
2158
2159     /**
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.
2165      */
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);
2175                 } else {
2176                     isClientRemoved = true;
2177                 }
2178             }
2179         }
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);
2184             return true;
2185         }
2186
2187         if (!isClientRemoved) {
2188             // specified p2p client is not found. already removed.
2189             return false;
2190         }
2191
2192         if (DBG) logd("Modified client list: " + modifiedClientList);
2193         if (modifiedClientList.length() == 0) {
2194             modifiedClientList.append("\"\"");
2195         }
2196         mWifiNative.setNetworkVariable(netId,
2197                 "p2p_client_list", modifiedClientList.toString());
2198         mWifiNative.saveConfig();
2199         return true;
2200     }
2201
2202     private void setWifiP2pInfoOnGroupFormation(String serverAddress) {
2203         mWifiP2pInfo.groupFormed = true;
2204         mWifiP2pInfo.isGroupOwner = mGroup.isGroupOwner();
2205         mWifiP2pInfo.groupOwnerAddress = NetworkUtils.numericToInetAddress(serverAddress);
2206     }
2207
2208     private void resetWifiP2pInfo() {
2209         mWifiP2pInfo.groupFormed = false;
2210         mWifiP2pInfo.isGroupOwner = false;
2211         mWifiP2pInfo.groupOwnerAddress = null;
2212     }
2213
2214     private String getDeviceName(String deviceAddress) {
2215         WifiP2pDevice d = mPeers.get(deviceAddress);
2216         if (d != null) {
2217                 return d.deviceName;
2218         }
2219         //Treat the address as name if there is no match
2220         return deviceAddress;
2221     }
2222
2223     private void p2pConnectWithPinDisplay(WifiP2pConfig config) {
2224         WifiP2pDevice dev = mPeers.get(config.deviceAddress);
2225         if (dev == null) {
2226             loge("target device is not found " + config.deviceAddress);
2227             return;
2228         }
2229
2230         String pin = mWifiNative.p2pConnect(config, dev.isGroupOwner());
2231         try {
2232             Integer.parseInt(pin);
2233             if (!sendShowPinReqToFrontApp(pin)) {
2234                 notifyInvitationSent(pin, config.deviceAddress);
2235             }
2236         } catch (NumberFormatException ignore) {
2237             // do nothing if p2pConnect did not return a pin
2238         }
2239     }
2240
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);
2250         }
2251         return deviceName;
2252     }
2253
2254     private boolean setAndPersistDeviceName(String devName) {
2255         if (devName == null) return false;
2256
2257         if (!mWifiNative.setDeviceName(devName)) {
2258             loge("Failed to set device name " + devName);
2259             return false;
2260         }
2261
2262         mThisDevice.deviceName = devName;
2263         mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName);
2264
2265         Settings.Global.putString(mContext.getContentResolver(),
2266                 Settings.Global.WIFI_P2P_DEVICE_NAME, devName);
2267         sendThisDeviceChangedBroadcast();
2268         return true;
2269     }
2270
2271     private boolean setWfdInfo(WifiP2pWfdInfo wfdInfo) {
2272         boolean success;
2273
2274         if (!wfdInfo.isWfdEnabled()) {
2275             success = mWifiNative.setWfdEnable(false);
2276         } else {
2277             success =
2278                 mWifiNative.setWfdEnable(true)
2279                 && mWifiNative.setWfdDeviceInfo(wfdInfo.getDeviceInfoHex());
2280         }
2281
2282         if (!success) {
2283             loge("Failed to set wfd properties");
2284             return false;
2285         }
2286
2287         mThisDevice.wfdInfo = wfdInfo;
2288         sendThisDeviceChangedBroadcast();
2289         return true;
2290     }
2291
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");
2304
2305         mThisDevice.deviceAddress = mWifiNative.p2pGetDeviceAddress();
2306         updateThisDevice(WifiP2pDevice.AVAILABLE);
2307         if (DBG) Slog.d(TAG, "DeviceAddress: " + mThisDevice.deviceAddress);
2308
2309         mClientInfoList.clear();
2310         mWifiNative.p2pFlush();
2311         mWifiNative.p2pServiceFlush();
2312         mServiceTransactionId = 0;
2313         mServiceDiscReqId = null;
2314
2315         updatePersistentNetworks(RELOAD);
2316     }
2317
2318     private void updateThisDevice(int status) {
2319         mThisDevice.status = status;
2320         sendThisDeviceChangedBroadcast();
2321     }
2322
2323     private void handleGroupCreationFailure() {
2324         resetWifiP2pInfo();
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);
2335     }
2336
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;
2343                 changed = true;
2344             }
2345         }
2346
2347         if (mGroup.isGroupOwner()) {
2348             stopDhcpServer(mGroup.getInterface());
2349         } else {
2350             if (DBG) logd("stop DHCP client");
2351             mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
2352             mDhcpStateMachine.doQuit();
2353             mDhcpStateMachine = null;
2354         }
2355
2356         try {
2357             mNwService.clearInterfaceAddresses(mGroup.getInterface());
2358         } catch (Exception e) {
2359             loge("Failed to clear addresses " + e);
2360         }
2361         NetworkUtils.resetConnections(mGroup.getInterface(), NetworkUtils.RESET_ALL_ADDRESSES);
2362
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);
2366
2367         mGroup = null;
2368         mWifiNative.p2pFlush();
2369         if (mPeers.remove(mPeersLostDuringConnection)) sendP2pPeersChangedBroadcast();
2370         mPeersLostDuringConnection.clear();
2371         mServiceDiscReqId = null;
2372         if (changed) sendP2pPeersChangedBroadcast();
2373
2374         if (mTempoarilyDisconnectedWifi) {
2375             mWifiChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_REQUEST, 0);
2376             mTempoarilyDisconnectedWifi = false;
2377         }
2378    }
2379
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);
2385         dstMsg.what = what;
2386         mReplyChannel.replyToMessage(msg, dstMsg);
2387     }
2388
2389     private void replyToMessage(Message msg, int what, int arg1) {
2390         if (msg.replyTo == null) return;
2391         Message dstMsg = obtainMessage(msg);
2392         dstMsg.what = what;
2393         dstMsg.arg1 = arg1;
2394         mReplyChannel.replyToMessage(msg, dstMsg);
2395     }
2396
2397     private void replyToMessage(Message msg, int what, Object obj) {
2398         if (msg.replyTo == null) return;
2399         Message dstMsg = obtainMessage(msg);
2400         dstMsg.what = what;
2401         dstMsg.obj = obj;
2402         mReplyChannel.replyToMessage(msg, dstMsg);
2403     }
2404
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;
2410         return msg;
2411     }
2412
2413     private void logd(String s) {
2414         Slog.d(TAG, s);
2415     }
2416
2417     private void loge(String s) {
2418         Slog.e(TAG, s);
2419     }
2420
2421     /**
2422      * Update service discovery request to wpa_supplicant.
2423      */
2424     private boolean updateSupplicantServiceRequest() {
2425         clearSupplicantServiceRequest();
2426
2427         StringBuffer sb = new StringBuffer();
2428         for (ClientInfo c: mClientInfoList.values()) {
2429             int key;
2430             WifiP2pServiceRequest req;
2431             for (int i=0; i < c.mReqList.size(); i++) {
2432                 req = c.mReqList.valueAt(i);
2433                 if (req != null) {
2434                     sb.append(req.getSupplicantQuery());
2435                 }
2436             }
2437         }
2438
2439         if (sb.length() == 0) {
2440             return false;
2441         }
2442
2443         mServiceDiscReqId = mWifiNative.p2pServDiscReq("00:00:00:00:00:00", sb.toString());
2444         if (mServiceDiscReqId == null) {
2445             return false;
2446         }
2447         return true;
2448     }
2449
2450     /**
2451      * Clear service discovery request in wpa_supplicant
2452      */
2453     private void clearSupplicantServiceRequest() {
2454         if (mServiceDiscReqId == null) return;
2455
2456         mWifiNative.p2pServDiscCancelReq(mServiceDiscReqId);
2457         mServiceDiscReqId = null;
2458     }
2459
2460     /* TODO: We could track individual service adds separately and avoid
2461      * having to do update all service requests on every new request
2462      */
2463     private boolean addServiceRequest(Messenger m, WifiP2pServiceRequest req) {
2464         clearClientDeadChannels();
2465         ClientInfo clientInfo = getClientInfo(m, true);
2466         if (clientInfo == null) {
2467             return false;
2468         }
2469
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);
2475
2476         if (mServiceDiscReqId == null) {
2477             return true;
2478         }
2479
2480         return updateSupplicantServiceRequest();
2481     }
2482
2483     private void removeServiceRequest(Messenger m, WifiP2pServiceRequest req) {
2484         ClientInfo clientInfo = getClientInfo(m, false);
2485         if (clientInfo == null) {
2486             return;
2487         }
2488
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))) {
2494                 removed = true;
2495                 clientInfo.mReqList.removeAt(i);
2496                 break;
2497             }
2498         }
2499
2500         if (!removed) return;
2501
2502         if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) {
2503             if (DBG) logd("remove client information from framework");
2504             mClientInfoList.remove(clientInfo.mMessenger);
2505         }
2506
2507         if (mServiceDiscReqId == null) {
2508             return;
2509         }
2510
2511         updateSupplicantServiceRequest();
2512     }
2513
2514     private void clearServiceRequests(Messenger m) {
2515
2516         ClientInfo clientInfo = getClientInfo(m, false);
2517         if (clientInfo == null) {
2518             return;
2519         }
2520
2521         if (clientInfo.mReqList.size() == 0) {
2522             return;
2523         }
2524
2525         clientInfo.mReqList.clear();
2526
2527         if (clientInfo.mServList.size() == 0) {
2528             if (DBG) logd("remove channel information from framework");
2529             mClientInfoList.remove(clientInfo.mMessenger);
2530         }
2531
2532         if (mServiceDiscReqId == null) {
2533             return;
2534         }
2535
2536         updateSupplicantServiceRequest();
2537     }
2538
2539     private boolean addLocalService(Messenger m, WifiP2pServiceInfo servInfo) {
2540         clearClientDeadChannels();
2541         ClientInfo clientInfo = getClientInfo(m, true);
2542         if (clientInfo == null) {
2543             return false;
2544         }
2545
2546         if (!clientInfo.mServList.add(servInfo)) {
2547             return false;
2548         }
2549
2550         if (!mWifiNative.p2pServiceAdd(servInfo)) {
2551             clientInfo.mServList.remove(servInfo);
2552             return false;
2553         }
2554
2555         return true;
2556     }
2557
2558     private void removeLocalService(Messenger m, WifiP2pServiceInfo servInfo) {
2559         ClientInfo clientInfo = getClientInfo(m, false);
2560         if (clientInfo == null) {
2561             return;
2562         }
2563
2564         mWifiNative.p2pServiceDel(servInfo);
2565
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);
2570         }
2571     }
2572
2573     private void clearLocalServices(Messenger m) {
2574         ClientInfo clientInfo = getClientInfo(m, false);
2575         if (clientInfo == null) {
2576             return;
2577         }
2578
2579         for (WifiP2pServiceInfo servInfo: clientInfo.mServList) {
2580             mWifiNative.p2pServiceDel(servInfo);
2581         }
2582
2583         clientInfo.mServList.clear();
2584         if (clientInfo.mReqList.size() == 0) {
2585             if (DBG) logd("remove client information from framework");
2586             mClientInfoList.remove(clientInfo.mMessenger);
2587         }
2588     }
2589
2590     private void clearClientInfo(Messenger m) {
2591         clearLocalServices(m);
2592         clearServiceRequests(m);
2593     }
2594
2595     /**
2596      * Send the service response to the WifiP2pManager.Channel.
2597      *
2598      * @param resp
2599      */
2600     private void sendServiceResponse(WifiP2pServiceResponse resp) {
2601         for (ClientInfo c : mClientInfoList.values()) {
2602             WifiP2pServiceRequest req = c.mReqList.get(resp.getTransactionId());
2603             if (req != null) {
2604                 Message msg = Message.obtain();
2605                 msg.what = WifiP2pManager.RESPONSE_SERVICE;
2606                 msg.arg1 = 0;
2607                 msg.arg2 = 0;
2608                 msg.obj = resp;
2609                 try {
2610                     c.mMessenger.send(msg);
2611                 } catch (RemoteException e) {
2612                     if (DBG) logd("detect dead channel");
2613                     clearClientInfo(c.mMessenger);
2614                     return;
2615                 }
2616             }
2617         }
2618     }
2619
2620     /**
2621      * We dont get notifications of clients that have gone away.
2622      * We detect this actively when services are added and throw
2623      * them away.
2624      *
2625      * TODO: This can be done better with full async channels.
2626      */
2627     private void clearClientDeadChannels() {
2628         ArrayList<Messenger> deadClients = new ArrayList<Messenger>();
2629
2630         for (ClientInfo c : mClientInfoList.values()) {
2631             Message msg = Message.obtain();
2632             msg.what = WifiP2pManager.PING;
2633             msg.arg1 = 0;
2634             msg.arg2 = 0;
2635             msg.obj = null;
2636             try {
2637                 c.mMessenger.send(msg);
2638             } catch (RemoteException e) {
2639                 if (DBG) logd("detect dead channel");
2640                 deadClients.add(c.mMessenger);
2641             }
2642         }
2643
2644         for (Messenger m : deadClients) {
2645             clearClientInfo(m);
2646         }
2647     }
2648
2649     /**
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.
2655      */
2656     private ClientInfo getClientInfo(Messenger m, boolean createIfNotExist) {
2657         ClientInfo clientInfo = mClientInfoList.get(m);
2658
2659         if (clientInfo == null && createIfNotExist) {
2660             if (DBG) logd("add a new client");
2661             clientInfo = new ClientInfo(m);
2662             mClientInfoList.put(m, clientInfo);
2663         }
2664
2665         return clientInfo;
2666     }
2667
2668     /**
2669      * Send detached message to dialog listener in the foreground application.
2670      * @param reason
2671      */
2672     private void sendDetachedMsg(int reason) {
2673         if (mForegroundAppMessenger == null) return;
2674
2675         Message msg = Message.obtain();
2676         msg.what = WifiP2pManager.DIALOG_LISTENER_DETACHED;
2677         msg.arg1 = reason;
2678         try {
2679             mForegroundAppMessenger.send(msg);
2680         } catch (RemoteException e) {
2681         }
2682         mForegroundAppMessenger = null;
2683         mForegroundAppPkgName = null;
2684     }
2685
2686     /**
2687      * Send a request to show wps pin to dialog listener in the foreground application.
2688      * @param pin WPS pin
2689      * @return
2690      */
2691     private boolean sendShowPinReqToFrontApp(String pin) {
2692         if (!isForegroundApp(mForegroundAppPkgName)) {
2693             sendDetachedMsg(WifiP2pManager.NOT_IN_FOREGROUND);
2694             return false;
2695         }
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);
2702     }
2703
2704     /**
2705      * Send a request to establish the connection to dialog listener in the foreground
2706      * application.
2707      * @param dev source device
2708      * @param config
2709      * @return
2710      */
2711     private boolean sendConnectNoticeToApp(WifiP2pDevice dev, WifiP2pConfig config) {
2712         if (dev == null) {
2713             dev = new WifiP2pDevice(config.deviceAddress);
2714         }
2715
2716         if (!isForegroundApp(mForegroundAppPkgName)) {
2717             if (DBG) logd("application is NOT foreground");
2718             sendDetachedMsg(WifiP2pManager.NOT_IN_FOREGROUND);
2719             return false;
2720         }
2721
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);
2729     }
2730
2731     /**
2732      * Send dialog event message to front application's dialog listener.
2733      * @param msg
2734      * @return true if success.
2735      */
2736     private boolean sendDialogMsgToFrontApp(Message msg) {
2737         try {
2738             mForegroundAppMessenger.send(msg);
2739         } catch (RemoteException e) {
2740             mForegroundAppMessenger = null;
2741             mForegroundAppPkgName = null;
2742             return false;
2743         }
2744         return true;
2745     }
2746
2747     /**
2748      * Set dialog listener application.
2749      * @param m
2750      * @param appPkgName if null, reset the listener.
2751      * @param isReset if true, try to reset.
2752      * @return
2753      */
2754     private boolean setDialogListenerApp(Messenger m,
2755             String appPkgName, boolean isReset) {
2756
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");
2761                 return false;
2762             }
2763             // detach an old listener.
2764             sendDetachedMsg(WifiP2pManager.NOT_IN_FOREGROUND);
2765         }
2766
2767         if (isReset) {
2768             if (DBG) logd("reset dialog listener");
2769             mForegroundAppMessenger = null;
2770             mForegroundAppPkgName = null;
2771             return true;
2772         }
2773
2774         if (!isForegroundApp(appPkgName)) {
2775             return false;
2776         }
2777
2778         mForegroundAppMessenger = m;
2779         mForegroundAppPkgName = appPkgName;
2780         if (DBG) logd("set dialog listener. app=" + appPkgName);
2781         return true;
2782     }
2783
2784     /**
2785      * Return true if the specified package name is foreground app's.
2786      *
2787      * @param pkgName application package name.
2788      * @return
2789      */
2790     private boolean isForegroundApp(String pkgName) {
2791         if (pkgName == null) return false;
2792
2793         List<RunningTaskInfo> tasks = mActivityMgr.getRunningTasks(1);
2794         if (tasks.size() == 0) {
2795             return false;
2796         }
2797
2798         return pkgName.equals(tasks.get(0).baseActivity.getPackageName());
2799     }
2800
2801     }
2802
2803     /**
2804      * Information about a particular client and we track the service discovery requests
2805      * and the local services registered by the client.
2806      */
2807     private class ClientInfo {
2808
2809         /*
2810          * A reference to WifiP2pManager.Channel handler.
2811          * The response of this request is notified to WifiP2pManager.Channel handler
2812          */
2813         private Messenger mMessenger;
2814
2815         /*
2816          * A service discovery request list.
2817          */
2818         private SparseArray<WifiP2pServiceRequest> mReqList;
2819
2820         /*
2821          * A local service information list.
2822          */
2823         private List<WifiP2pServiceInfo> mServList;
2824
2825         private ClientInfo(Messenger m) {
2826             mMessenger = m;
2827             mReqList = new SparseArray();
2828             mServList = new ArrayList<WifiP2pServiceInfo>();
2829         }
2830     }
2831 }