blob: a00882dca9d4d2ff280eb1f70709bd4f988020b8 [file] [log] [blame]
repo sync55bc5f32011-06-24 14:23:07 -07001/*
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
Vinit Deshapndeffadfb92013-12-06 15:12:41 -080017package com.android.server.wifi.p2p;
repo sync55bc5f32011-06-24 14:23:07 -070018
19import android.app.AlertDialog;
Irfan Sheriffdaf57e52011-09-06 10:56:53 -070020import android.app.Notification;
repo sync55bc5f32011-06-24 14:23:07 -070021import android.content.Context;
22import android.content.DialogInterface;
23import android.content.DialogInterface.OnClickListener;
24import android.content.Intent;
repo sync55bc5f32011-06-24 14:23:07 -070025import android.content.pm.PackageManager;
Justin Koh8f38f3c2012-10-17 11:33:15 -070026import android.content.res.Configuration;
repo sync55bc5f32011-06-24 14:23:07 -070027import android.content.res.Resources;
repo syncaea743a2011-07-29 23:55:49 -070028import android.net.ConnectivityManager;
Robert Greenwalt4717c262012-10-31 14:32:53 -070029import android.net.DhcpResults;
repo syncaea743a2011-07-29 23:55:49 -070030import android.net.DhcpStateMachine;
31import android.net.InterfaceConfiguration;
32import android.net.LinkAddress;
repo syncaea743a2011-07-29 23:55:49 -070033import android.net.NetworkInfo;
34import android.net.NetworkUtils;
Irfan Sheriff651cdfc2011-09-07 00:31:20 -070035import android.net.wifi.WpsInfo;
Vinit Deshapndeffadfb92013-12-06 15:12:41 -080036import android.net.wifi.p2p.IWifiP2pManager;
37import android.net.wifi.p2p.WifiP2pConfig;
38import android.net.wifi.p2p.WifiP2pDevice;
39import android.net.wifi.p2p.WifiP2pDeviceList;
40import android.net.wifi.p2p.WifiP2pGroup;
41import android.net.wifi.p2p.WifiP2pGroupList;
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +090042import android.net.wifi.p2p.WifiP2pGroupList.GroupDeleteListener;
Vinit Deshapndeffadfb92013-12-06 15:12:41 -080043import android.net.wifi.p2p.WifiP2pInfo;
44import android.net.wifi.p2p.WifiP2pManager;
45import android.net.wifi.p2p.WifiP2pProvDiscEvent;
46import android.net.wifi.p2p.WifiP2pWfdInfo;
Irfan Sheriff21ba8152012-04-04 16:22:21 -070047import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
48import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
49import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
repo sync55bc5f32011-06-24 14:23:07 -070050import android.os.Binder;
Chong Zhang1f3ecaa2013-05-03 15:55:36 -070051import android.os.Bundle;
repo sync55bc5f32011-06-24 14:23:07 -070052import android.os.IBinder;
Irfan Sheriffcb30b222011-07-29 20:54:52 -070053import android.os.INetworkManagementService;
repo sync55bc5f32011-06-24 14:23:07 -070054import android.os.Message;
Irfan Sherifff6d09842011-08-03 15:37:08 -070055import android.os.Messenger;
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -080056import android.os.RemoteException;
Irfan Sheriffcb30b222011-07-29 20:54:52 -070057import android.os.ServiceManager;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070058import android.os.UserHandle;
Irfan Sheriff93226872011-08-29 10:36:05 -070059import android.provider.Settings;
Irfan Sheriff618455f2011-11-18 14:33:09 -080060import android.text.TextUtils;
repo sync55bc5f32011-06-24 14:23:07 -070061import android.util.Slog;
Irfan Sheriff21ba8152012-04-04 16:22:21 -070062import android.util.SparseArray;
Justin Koh8f38f3c2012-10-17 11:33:15 -070063import android.view.KeyEvent;
repo sync55bc5f32011-06-24 14:23:07 -070064import android.view.LayoutInflater;
65import android.view.View;
Irfan Sheriff618455f2011-11-18 14:33:09 -080066import android.view.ViewGroup;
repo sync55bc5f32011-06-24 14:23:07 -070067import android.view.WindowManager;
68import android.widget.EditText;
Irfan Sheriff618455f2011-11-18 14:33:09 -080069import android.widget.TextView;
repo sync55bc5f32011-06-24 14:23:07 -070070
Irfan Sherifff6d09842011-08-03 15:37:08 -070071import com.android.internal.R;
repo sync55bc5f32011-06-24 14:23:07 -070072import com.android.internal.util.AsyncChannel;
73import com.android.internal.util.Protocol;
repo sync55bc5f32011-06-24 14:23:07 -070074import com.android.internal.util.State;
75import com.android.internal.util.StateMachine;
Vinit Deshapndeffadfb92013-12-06 15:12:41 -080076import com.android.server.wifi.WifiMonitor;
77import com.android.server.wifi.WifiNative;
78import com.android.server.wifi.WifiStateMachine;
repo sync55bc5f32011-06-24 14:23:07 -070079
repo syncaea743a2011-07-29 23:55:49 -070080import java.io.FileDescriptor;
81import java.io.PrintWriter;
Robert Greenwalt4717c262012-10-31 14:32:53 -070082import java.net.InetAddress;
Irfan Sheriff21ba8152012-04-04 16:22:21 -070083import java.util.ArrayList;
repo syncaea743a2011-07-29 23:55:49 -070084import java.util.Collection;
Irfan Sheriff21ba8152012-04-04 16:22:21 -070085import java.util.HashMap;
86import java.util.List;
Vinit Deshapndeda40d922013-10-21 11:58:40 -070087import java.util.Locale;
88
repo syncaea743a2011-07-29 23:55:49 -070089
repo sync55bc5f32011-06-24 14:23:07 -070090/**
Irfan Sheriffde1e9fa92012-05-01 16:15:23 -070091 * WifiP2pService includes a state machine to perform Wi-Fi p2p operations. Applications
repo sync55bc5f32011-06-24 14:23:07 -070092 * communicate with this service to issue device discovery and connectivity requests
93 * through the WifiP2pManager interface. The state machine communicates with the wifi
94 * driver through wpa_supplicant and handles the event responses through WifiMonitor.
95 *
96 * Note that the term Wifi when used without a p2p suffix refers to the client mode
97 * of Wifi operation
98 * @hide
99 */
100public class WifiP2pService extends IWifiP2pManager.Stub {
101 private static final String TAG = "WifiP2pService";
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800102 private static final boolean DBG = false;
repo syncaea743a2011-07-29 23:55:49 -0700103 private static final String NETWORKTYPE = "WIFI_P2P";
repo sync55bc5f32011-06-24 14:23:07 -0700104
105 private Context mContext;
Irfan Sheriffcb30b222011-07-29 20:54:52 -0700106 private String mInterface;
Irfan Sheriffdaf57e52011-09-06 10:56:53 -0700107 private Notification mNotification;
Irfan Sheriffcb30b222011-07-29 20:54:52 -0700108
109 INetworkManagementService mNwService;
repo syncaea743a2011-07-29 23:55:49 -0700110 private DhcpStateMachine mDhcpStateMachine;
repo sync55bc5f32011-06-24 14:23:07 -0700111
repo sync55bc5f32011-06-24 14:23:07 -0700112 private P2pStateMachine mP2pStateMachine;
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700113 private AsyncChannel mReplyChannel = new AsyncChannel();
repo sync55bc5f32011-06-24 14:23:07 -0700114 private AsyncChannel mWifiChannel;
115
Irfan Sheriff618455f2011-11-18 14:33:09 -0800116 private static final Boolean JOIN_GROUP = true;
117 private static final Boolean FORM_GROUP = false;
118
Irfan Sheriffca1269f2012-09-27 17:01:41 -0700119 private static final Boolean RELOAD = true;
120 private static final Boolean NO_RELOAD = false;
121
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700122 /* Two minutes comes from the wpa_supplicant setting */
Irfan Sheriff618455f2011-11-18 14:33:09 -0800123 private static final int GROUP_CREATING_WAIT_TIME_MS = 120 * 1000;
124 private static int mGroupCreatingTimeoutIndex = 0;
repo syncaea743a2011-07-29 23:55:49 -0700125
Irfan Sheriff62fa6de2012-10-18 12:39:22 -0700126 private static final int DISABLE_P2P_WAIT_TIME_MS = 5 * 1000;
127 private static int mDisableP2pTimeoutIndex = 0;
128
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800129 /* Set a two minute discover timeout to avoid STA scans from being blocked */
130 private static final int DISCOVER_TIMEOUT_S = 120;
131
Irfan Sheriff55bfa422012-04-06 15:25:41 -0700132 /* Idle time after a peer is gone when the group is torn down */
Irfan Sheriffca1269f2012-09-27 17:01:41 -0700133 private static final int GROUP_IDLE_TIME_S = 10;
Irfan Sheriff55bfa422012-04-06 15:25:41 -0700134
repo sync55bc5f32011-06-24 14:23:07 -0700135 private static final int BASE = Protocol.BASE_WIFI_P2P_SERVICE;
136
Irfan Sheriff618455f2011-11-18 14:33:09 -0800137 /* Delayed message to timeout group creation */
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800138 public static final int GROUP_CREATING_TIMED_OUT = BASE + 1;
repo sync55bc5f32011-06-24 14:23:07 -0700139
Irfan Sheriff618455f2011-11-18 14:33:09 -0800140 /* User accepted a peer request */
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800141 private static final int PEER_CONNECTION_USER_ACCEPT = BASE + 2;
Irfan Sheriff618455f2011-11-18 14:33:09 -0800142 /* User rejected a peer request */
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800143 private static final int PEER_CONNECTION_USER_REJECT = BASE + 3;
Irfan Sheriff9f452d02012-10-15 12:00:29 -0700144 /* User wants to disconnect wifi in favour of p2p */
145 private static final int DROP_WIFI_USER_ACCEPT = BASE + 4;
146 /* User wants to keep his wifi connection and drop p2p */
147 private static final int DROP_WIFI_USER_REJECT = BASE + 5;
Irfan Sheriff62fa6de2012-10-18 12:39:22 -0700148 /* Delayed message to timeout p2p disable */
149 public static final int DISABLE_P2P_TIMED_OUT = BASE + 6;
Irfan Sheriff9f452d02012-10-15 12:00:29 -0700150
Irfan Sheriff295da732011-09-09 14:10:15 -0700151
Irfan Sheriff3809f502012-09-17 16:04:57 -0700152 /* Commands to the WifiStateMachine */
Irfan Sheriff9f452d02012-10-15 12:00:29 -0700153 public static final int P2P_CONNECTION_CHANGED = BASE + 11;
154
Yoshihiko Ikenaga7d9cf112012-11-16 16:58:10 +0900155 /* These commands are used to temporarily disconnect wifi when we detect
Irfan Sheriff9f452d02012-10-15 12:00:29 -0700156 * a frequency conflict which would make it impossible to have with p2p
157 * and wifi active at the same time.
158 *
Yoshihiko Ikenaga7d9cf112012-11-16 16:58:10 +0900159 * If the user chooses to disable wifi temporarily, we keep wifi disconnected
Irfan Sheriff9f452d02012-10-15 12:00:29 -0700160 * until the p2p connection is done and terminated at which point we will
161 * bring back wifi up
162 *
163 * DISCONNECT_WIFI_REQUEST
164 * msg.arg1 = 1 enables temporary disconnect and 0 disables it.
165 */
166 public static final int DISCONNECT_WIFI_REQUEST = BASE + 12;
167 public static final int DISCONNECT_WIFI_RESPONSE = BASE + 13;
Irfan Sheriff3809f502012-09-17 16:04:57 -0700168
Irfan Sheriff8b485ad2013-03-28 10:15:44 -0700169 public static final int SET_MIRACAST_MODE = BASE + 14;
170
Robert Greenwalt6433ef22013-06-28 15:55:28 -0700171 // During dhcp (and perhaps other times) we can't afford to drop packets
172 // but Discovery will switch our channel enough we will.
173 // msg.arg1 = ENABLED for blocking, DISABLED for resumed.
174 // msg.arg2 = msg to send when blocked
175 // msg.obj = StateMachine to send to when blocked
176 public static final int BLOCK_DISCOVERY = BASE + 15;
177
Vinit Deshapnde2c385ec2013-09-09 16:28:31 -0700178 // set country code
179 public static final int SET_COUNTRY_CODE = BASE + 16;
180
Robert Greenwalt6433ef22013-06-28 15:55:28 -0700181 public static final int ENABLED = 1;
182 public static final int DISABLED = 0;
183
repo sync55bc5f32011-06-24 14:23:07 -0700184 private final boolean mP2pSupported;
Irfan Sheriff651cdfc2011-09-07 00:31:20 -0700185
186 private WifiP2pDevice mThisDevice = new WifiP2pDevice();
Irfan Sheriff4be4d312011-09-03 11:03:23 -0700187
188 /* When a group has been explicitly created by an app, we persist the group
189 * even after all clients have been disconnected until an explicit remove
190 * is invoked */
Yoshihiko Ikenagabfb27bb2012-02-14 11:28:35 +0900191 private boolean mAutonomousGroup;
repo sync55bc5f32011-06-24 14:23:07 -0700192
Irfan Sheriff10ca8702012-05-10 16:52:49 -0700193 /* Invitation to join an existing p2p group */
194 private boolean mJoinExistingGroup;
195
Irfan Sheriffc111d1c2012-03-28 15:59:30 -0700196 /* Track whether we are in p2p discovery. This is used to avoid sending duplicate
197 * broadcasts
198 */
199 private boolean mDiscoveryStarted;
Robert Greenwalt6433ef22013-06-28 15:55:28 -0700200 /* Track whether servcice/peer discovery is blocked in favor of other wifi actions
201 * (notably dhcp)
202 */
203 private boolean mDiscoveryBlocked;
204
Vinit Deshapndeda40d922013-10-21 11:58:40 -0700205 // Supplicant doesn't like setting the same country code multiple times (it may drop
206 // current connected network), so we save the country code here to avoid redundency
207 private String mLastSetCountryCode;
208
Robert Greenwalt6433ef22013-06-28 15:55:28 -0700209 /*
210 * remember if we were in a scan when it had to be stopped
211 */
212 private boolean mDiscoveryPostponed = false;
Irfan Sheriffc111d1c2012-03-28 15:59:30 -0700213
repo syncaea743a2011-07-29 23:55:49 -0700214 private NetworkInfo mNetworkInfo;
repo syncaea743a2011-07-29 23:55:49 -0700215
Irfan Sheriff9f452d02012-10-15 12:00:29 -0700216 private boolean mTempoarilyDisconnectedWifi = false;
217
Irfan Sheriff21ba8152012-04-04 16:22:21 -0700218 /* The transaction Id of service discovery request */
219 private byte mServiceTransactionId = 0;
220
221 /* Service discovery request ID of wpa_supplicant.
222 * null means it's not set yet. */
223 private String mServiceDiscReqId;
224
225 /* clients(application) information list. */
226 private HashMap<Messenger, ClientInfo> mClientInfoList = new HashMap<Messenger, ClientInfo>();
227
Irfan Sheriff859e7de2011-08-25 13:58:25 -0700228 /* Is chosen as a unique range to avoid conflict with
229 the range defined in Tethering.java */
230 private static final String[] DHCP_RANGE = {"192.168.49.2", "192.168.49.254"};
231 private static final String SERVER_ADDRESS = "192.168.49.1";
232
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +0900233 /**
234 * Error code definition.
235 * see the Table.8 in the WiFi Direct specification for the detail.
236 */
237 public static enum P2pStatus {
238 /* Success. */
239 SUCCESS,
240
241 /* The target device is currently unavailable. */
242 INFORMATION_IS_CURRENTLY_UNAVAILABLE,
243
244 /* Protocol error. */
245 INCOMPATIBLE_PARAMETERS,
246
247 /* The target device reached the limit of the number of the connectable device.
248 * For example, device limit or group limit is set. */
249 LIMIT_REACHED,
250
251 /* Protocol error. */
252 INVALID_PARAMETER,
253
254 /* Unable to accommodate request. */
255 UNABLE_TO_ACCOMMODATE_REQUEST,
256
257 /* Previous protocol error, or disruptive behavior. */
258 PREVIOUS_PROTOCOL_ERROR,
259
260 /* There is no common channels the both devices can use. */
Irfan Sheriff9f452d02012-10-15 12:00:29 -0700261 NO_COMMON_CHANNEL,
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +0900262
263 /* Unknown p2p group. For example, Device A tries to invoke the previous persistent group,
264 * but device B has removed the specified credential already. */
265 UNKNOWN_P2P_GROUP,
266
267 /* Both p2p devices indicated an intent of 15 in group owner negotiation. */
268 BOTH_GO_INTENT_15,
269
270 /* Incompatible provisioning method. */
271 INCOMPATIBLE_PROVISIONING_METHOD,
272
273 /* Rejected by user */
274 REJECTED_BY_USER,
275
276 /* Unknown error */
277 UNKNOWN;
278
279 public static P2pStatus valueOf(int error) {
280 switch(error) {
281 case 0 :
282 return SUCCESS;
283 case 1:
284 return INFORMATION_IS_CURRENTLY_UNAVAILABLE;
285 case 2:
286 return INCOMPATIBLE_PARAMETERS;
287 case 3:
288 return LIMIT_REACHED;
289 case 4:
290 return INVALID_PARAMETER;
291 case 5:
292 return UNABLE_TO_ACCOMMODATE_REQUEST;
293 case 6:
294 return PREVIOUS_PROTOCOL_ERROR;
295 case 7:
Irfan Sheriff9f452d02012-10-15 12:00:29 -0700296 return NO_COMMON_CHANNEL;
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +0900297 case 8:
298 return UNKNOWN_P2P_GROUP;
299 case 9:
300 return BOTH_GO_INTENT_15;
301 case 10:
302 return INCOMPATIBLE_PROVISIONING_METHOD;
303 case 11:
304 return REJECTED_BY_USER;
305 default:
306 return UNKNOWN;
307 }
308 }
309 }
310
repo sync55bc5f32011-06-24 14:23:07 -0700311 public WifiP2pService(Context context) {
312 mContext = context;
313
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800314 //STOPSHIP: get this from native side
Irfan Sherifffc7f95a2012-01-04 14:50:09 -0800315 mInterface = "p2p0";
repo syncaea743a2011-07-29 23:55:49 -0700316 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, "");
repo syncaea743a2011-07-29 23:55:49 -0700317
Irfan Sheriffa8f63a32011-09-07 14:35:25 -0700318 mP2pSupported = mContext.getPackageManager().hasSystemFeature(
319 PackageManager.FEATURE_WIFI_DIRECT);
320
Irfan Sheriff651cdfc2011-09-07 00:31:20 -0700321 mThisDevice.primaryDeviceType = mContext.getResources().getString(
Irfan Sheriff93226872011-08-29 10:36:05 -0700322 com.android.internal.R.string.config_wifi_p2p_device_type);
repo sync55bc5f32011-06-24 14:23:07 -0700323
324 mP2pStateMachine = new P2pStateMachine(TAG, mP2pSupported);
325 mP2pStateMachine.start();
repo syncaea743a2011-07-29 23:55:49 -0700326 }
repo sync55bc5f32011-06-24 14:23:07 -0700327
Irfan Sheriffcb30b222011-07-29 20:54:52 -0700328 public void connectivityServiceReady() {
329 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
330 mNwService = INetworkManagementService.Stub.asInterface(b);
331 }
332
repo sync55bc5f32011-06-24 14:23:07 -0700333 private void enforceAccessPermission() {
334 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
335 "WifiP2pService");
336 }
337
338 private void enforceChangePermission() {
339 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
340 "WifiP2pService");
341 }
342
Irfan Sheriff8b485ad2013-03-28 10:15:44 -0700343 private void enforceConnectivityInternalPermission() {
344 mContext.enforceCallingOrSelfPermission(
345 android.Manifest.permission.CONNECTIVITY_INTERNAL,
346 "WifiP2pService");
347 }
348
repo sync55bc5f32011-06-24 14:23:07 -0700349 /**
350 * Get a reference to handler. This is used by a client to establish
351 * an AsyncChannel communication with WifiP2pService
352 */
353 public Messenger getMessenger() {
354 enforceAccessPermission();
355 enforceChangePermission();
356 return new Messenger(mP2pStateMachine.getHandler());
357 }
358
Irfan Sheriff8b485ad2013-03-28 10:15:44 -0700359 /** This is used to provide information to drivers to optimize performance depending
360 * on the current mode of operation.
361 * 0 - disabled
362 * 1 - source operation
363 * 2 - sink operation
364 *
365 * As an example, the driver could reduce the channel dwell time during scanning
366 * when acting as a source or sink to minimize impact on miracast.
367 */
368 public void setMiracastMode(int mode) {
369 enforceConnectivityInternalPermission();
370 mP2pStateMachine.sendMessage(SET_MIRACAST_MODE, mode);
371 }
372
repo sync55bc5f32011-06-24 14:23:07 -0700373 @Override
374 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
375 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
376 != PackageManager.PERMISSION_GRANTED) {
377 pw.println("Permission Denial: can't dump WifiP2pService from from pid="
378 + Binder.getCallingPid()
379 + ", uid=" + Binder.getCallingUid());
380 return;
381 }
Irfan Sherifff0afe412012-11-30 14:07:44 -0800382 mP2pStateMachine.dump(fd, pw, args);
383 pw.println("mAutonomousGroup " + mAutonomousGroup);
384 pw.println("mJoinExistingGroup " + mJoinExistingGroup);
385 pw.println("mDiscoveryStarted " + mDiscoveryStarted);
386 pw.println("mNetworkInfo " + mNetworkInfo);
387 pw.println("mTempoarilyDisconnectedWifi " + mTempoarilyDisconnectedWifi);
388 pw.println("mServiceDiscReqId " + mServiceDiscReqId);
389 pw.println();
repo sync55bc5f32011-06-24 14:23:07 -0700390 }
391
392
393 /**
394 * Handles interaction with WifiStateMachine
395 */
396 private class P2pStateMachine extends StateMachine {
397
398 private DefaultState mDefaultState = new DefaultState();
399 private P2pNotSupportedState mP2pNotSupportedState = new P2pNotSupportedState();
400 private P2pDisablingState mP2pDisablingState = new P2pDisablingState();
401 private P2pDisabledState mP2pDisabledState = new P2pDisabledState();
repo sync55bc5f32011-06-24 14:23:07 -0700402 private P2pEnablingState mP2pEnablingState = new P2pEnablingState();
403 private P2pEnabledState mP2pEnabledState = new P2pEnabledState();
404 // Inactive is when p2p is enabled with no connectivity
405 private InactiveState mInactiveState = new InactiveState();
Irfan Sheriff618455f2011-11-18 14:33:09 -0800406 private GroupCreatingState mGroupCreatingState = new GroupCreatingState();
Irfan Sherifff1180432012-12-13 12:33:42 -0800407 private UserAuthorizingInviteRequestState mUserAuthorizingInviteRequestState
408 = new UserAuthorizingInviteRequestState();
409 private UserAuthorizingNegotiationRequestState mUserAuthorizingNegotiationRequestState
410 = new UserAuthorizingNegotiationRequestState();
Irfan Sheriff618455f2011-11-18 14:33:09 -0800411 private ProvisionDiscoveryState mProvisionDiscoveryState = new ProvisionDiscoveryState();
repo sync55bc5f32011-06-24 14:23:07 -0700412 private GroupNegotiationState mGroupNegotiationState = new GroupNegotiationState();
Irfan Sheriff9f452d02012-10-15 12:00:29 -0700413 private FrequencyConflictState mFrequencyConflictState =new FrequencyConflictState();
Irfan Sheriff618455f2011-11-18 14:33:09 -0800414
repo sync55bc5f32011-06-24 14:23:07 -0700415 private GroupCreatedState mGroupCreatedState = new GroupCreatedState();
Irfan Sheriff618455f2011-11-18 14:33:09 -0800416 private UserAuthorizingJoinState mUserAuthorizingJoinState = new UserAuthorizingJoinState();
Irfan Sheriffc41096e2012-09-24 14:21:54 -0700417 private OngoingGroupRemovalState mOngoingGroupRemovalState = new OngoingGroupRemovalState();
repo sync55bc5f32011-06-24 14:23:07 -0700418
Irfan Sherifffc7f95a2012-01-04 14:50:09 -0800419 private WifiNative mWifiNative = new WifiNative(mInterface);
420 private WifiMonitor mWifiMonitor = new WifiMonitor(this, mWifiNative);
repo sync55bc5f32011-06-24 14:23:07 -0700421
Jeff Brownd8544a52012-09-09 13:56:17 -0700422 private final WifiP2pDeviceList mPeers = new WifiP2pDeviceList();
Irfan Sheriff41de2402012-10-12 15:52:13 -0700423 /* During a connection, supplicant can tell us that a device was lost. From a supplicant's
424 * perspective, the discovery stops during connection and it purges device since it does
425 * not get latest updates about the device without being in discovery state.
426 *
427 * From the framework perspective, the device is still there since we are connecting or
Yoshihiko Ikenaga7d9cf112012-11-16 16:58:10 +0900428 * connected to it. so we keep these devices in a separate list, so that they are removed
Irfan Sheriff41de2402012-10-12 15:52:13 -0700429 * when connection is cancelled or lost
430 */
431 private final WifiP2pDeviceList mPeersLostDuringConnection = new WifiP2pDeviceList();
Jeff Brownd8544a52012-09-09 13:56:17 -0700432 private final WifiP2pGroupList mGroups = new WifiP2pGroupList(null,
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +0900433 new GroupDeleteListener() {
434 @Override
435 public void onDeleteGroup(int netId) {
436 if (DBG) logd("called onDeleteGroup() netId=" + netId);
437 mWifiNative.removeNetwork(netId);
438 mWifiNative.saveConfig();
439 sendP2pPersistentGroupsChangedBroadcast();
440 }
441 });
Jeff Brownd8544a52012-09-09 13:56:17 -0700442 private final WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo();
repo sync55bc5f32011-06-24 14:23:07 -0700443 private WifiP2pGroup mGroup;
444
Irfan Sherifff1180432012-12-13 12:33:42 -0800445 // Saved WifiP2pConfig for an ongoing peer connection. This will never be null.
446 // The deviceAddress will be an empty string when the device is inactive
447 // or if it is connected without any ongoing join request
448 private WifiP2pConfig mSavedPeerConfig = new WifiP2pConfig();
repo sync55bc5f32011-06-24 14:23:07 -0700449
450 // Saved WifiP2pGroup from invitation request
451 private WifiP2pGroup mSavedP2pGroup;
452
453 P2pStateMachine(String name, boolean p2pSupported) {
454 super(name);
455
456 addState(mDefaultState);
457 addState(mP2pNotSupportedState, mDefaultState);
458 addState(mP2pDisablingState, mDefaultState);
459 addState(mP2pDisabledState, mDefaultState);
repo sync55bc5f32011-06-24 14:23:07 -0700460 addState(mP2pEnablingState, mDefaultState);
461 addState(mP2pEnabledState, mDefaultState);
462 addState(mInactiveState, mP2pEnabledState);
Irfan Sheriff618455f2011-11-18 14:33:09 -0800463 addState(mGroupCreatingState, mP2pEnabledState);
Irfan Sherifff1180432012-12-13 12:33:42 -0800464 addState(mUserAuthorizingInviteRequestState, mGroupCreatingState);
465 addState(mUserAuthorizingNegotiationRequestState, mGroupCreatingState);
Irfan Sheriff618455f2011-11-18 14:33:09 -0800466 addState(mProvisionDiscoveryState, mGroupCreatingState);
467 addState(mGroupNegotiationState, mGroupCreatingState);
Irfan Sheriff9f452d02012-10-15 12:00:29 -0700468 addState(mFrequencyConflictState, mGroupCreatingState);
repo sync55bc5f32011-06-24 14:23:07 -0700469 addState(mGroupCreatedState, mP2pEnabledState);
Irfan Sheriff618455f2011-11-18 14:33:09 -0800470 addState(mUserAuthorizingJoinState, mGroupCreatedState);
Irfan Sheriffc41096e2012-09-24 14:21:54 -0700471 addState(mOngoingGroupRemovalState, mGroupCreatedState);
repo sync55bc5f32011-06-24 14:23:07 -0700472
473 if (p2pSupported) {
474 setInitialState(mP2pDisabledState);
475 } else {
476 setInitialState(mP2pNotSupportedState);
477 }
Irfan Sherifff0afe412012-11-30 14:07:44 -0800478 setLogRecSize(50);
479 setLogOnlyTransitions(true);
repo sync55bc5f32011-06-24 14:23:07 -0700480 }
481
repo sync55bc5f32011-06-24 14:23:07 -0700482 class DefaultState extends State {
483 @Override
484 public boolean processMessage(Message message) {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700485 if (DBG) logd(getName() + message.toString());
repo sync55bc5f32011-06-24 14:23:07 -0700486 switch (message.what) {
487 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
488 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700489 if (DBG) logd("Full connection with WifiStateMachine established");
repo sync55bc5f32011-06-24 14:23:07 -0700490 mWifiChannel = (AsyncChannel) message.obj;
491 } else {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700492 loge("Full connection failure, error = " + message.arg1);
repo sync55bc5f32011-06-24 14:23:07 -0700493 mWifiChannel = null;
494 }
495 break;
496
497 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
498 if (message.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700499 loge("Send failed, client connection lost");
repo sync55bc5f32011-06-24 14:23:07 -0700500 } else {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700501 loge("Client connection lost with reason: " + message.arg1);
repo sync55bc5f32011-06-24 14:23:07 -0700502 }
503 mWifiChannel = null;
504 break;
505
506 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
507 AsyncChannel ac = new AsyncChannel();
508 ac.connect(mContext, getHandler(), message.replyTo);
509 break;
Robert Greenwalt6433ef22013-06-28 15:55:28 -0700510 case BLOCK_DISCOVERY:
511 mDiscoveryBlocked = (message.arg1 == ENABLED ? true : false);
512 // always reset this - we went to a state that doesn't support discovery so
513 // it would have stopped regardless
514 mDiscoveryPostponed = false;
515 if (mDiscoveryBlocked) {
516 try {
517 StateMachine m = (StateMachine)message.obj;
518 m.sendMessage(message.arg2);
519 } catch (Exception e) {
520 loge("unable to send BLOCK_DISCOVERY response: " + e);
521 }
522 }
523 break;
repo sync55bc5f32011-06-24 14:23:07 -0700524 case WifiP2pManager.DISCOVER_PEERS:
Irfan Sheriff4be4d312011-09-03 11:03:23 -0700525 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
526 WifiP2pManager.BUSY);
repo sync55bc5f32011-06-24 14:23:07 -0700527 break;
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800528 case WifiP2pManager.STOP_DISCOVERY:
529 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
530 WifiP2pManager.BUSY);
531 break;
Irfan Sheriff21ba8152012-04-04 16:22:21 -0700532 case WifiP2pManager.DISCOVER_SERVICES:
533 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
534 WifiP2pManager.BUSY);
535 break;
repo sync55bc5f32011-06-24 14:23:07 -0700536 case WifiP2pManager.CONNECT:
Irfan Sheriff4be4d312011-09-03 11:03:23 -0700537 replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
538 WifiP2pManager.BUSY);
repo sync55bc5f32011-06-24 14:23:07 -0700539 break;
Irfan Sheriff651cdfc2011-09-07 00:31:20 -0700540 case WifiP2pManager.CANCEL_CONNECT:
541 replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
542 WifiP2pManager.BUSY);
543 break;
repo sync55bc5f32011-06-24 14:23:07 -0700544 case WifiP2pManager.CREATE_GROUP:
Irfan Sheriff4be4d312011-09-03 11:03:23 -0700545 replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
546 WifiP2pManager.BUSY);
repo sync55bc5f32011-06-24 14:23:07 -0700547 break;
548 case WifiP2pManager.REMOVE_GROUP:
Irfan Sheriff4be4d312011-09-03 11:03:23 -0700549 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
550 WifiP2pManager.BUSY);
repo sync55bc5f32011-06-24 14:23:07 -0700551 break;
Irfan Sheriff21ba8152012-04-04 16:22:21 -0700552 case WifiP2pManager.ADD_LOCAL_SERVICE:
553 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED,
554 WifiP2pManager.BUSY);
555 break;
556 case WifiP2pManager.REMOVE_LOCAL_SERVICE:
557 replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED,
558 WifiP2pManager.BUSY);
559 break;
560 case WifiP2pManager.CLEAR_LOCAL_SERVICES:
561 replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED,
562 WifiP2pManager.BUSY);
563 break;
564 case WifiP2pManager.ADD_SERVICE_REQUEST:
565 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED,
566 WifiP2pManager.BUSY);
567 break;
568 case WifiP2pManager.REMOVE_SERVICE_REQUEST:
569 replyToMessage(message,
570 WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED,
571 WifiP2pManager.BUSY);
572 break;
573 case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
574 replyToMessage(message,
575 WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED,
576 WifiP2pManager.BUSY);
577 break;
Irfan Sheriff2bdefca2012-04-25 16:40:14 -0700578 case WifiP2pManager.SET_DEVICE_NAME:
579 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
580 WifiP2pManager.BUSY);
581 break;
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +0900582 case WifiP2pManager.DELETE_PERSISTENT_GROUP:
583 replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP,
584 WifiP2pManager.BUSY);
585 break;
Andreas Huberab4cd452012-08-15 16:16:31 -0700586 case WifiP2pManager.SET_WFD_INFO:
587 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
588 WifiP2pManager.BUSY);
589 break;
repo sync55bc5f32011-06-24 14:23:07 -0700590 case WifiP2pManager.REQUEST_PEERS:
Jeff Brownd8544a52012-09-09 13:56:17 -0700591 replyToMessage(message, WifiP2pManager.RESPONSE_PEERS,
592 new WifiP2pDeviceList(mPeers));
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700593 break;
594 case WifiP2pManager.REQUEST_CONNECTION_INFO:
Jeff Brownd8544a52012-09-09 13:56:17 -0700595 replyToMessage(message, WifiP2pManager.RESPONSE_CONNECTION_INFO,
596 new WifiP2pInfo(mWifiP2pInfo));
repo sync55bc5f32011-06-24 14:23:07 -0700597 break;
Irfan Sheriff4be4d312011-09-03 11:03:23 -0700598 case WifiP2pManager.REQUEST_GROUP_INFO:
Jeff Brownd8544a52012-09-09 13:56:17 -0700599 replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO,
600 mGroup != null ? new WifiP2pGroup(mGroup) : null);
Irfan Sheriff4be4d312011-09-03 11:03:23 -0700601 break;
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +0900602 case WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO:
603 replyToMessage(message, WifiP2pManager.RESPONSE_PERSISTENT_GROUP_INFO,
Jeff Brownd8544a52012-09-09 13:56:17 -0700604 new WifiP2pGroupList(mGroups, null));
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +0900605 break;
Irfan Sherifff1180432012-12-13 12:33:42 -0800606 case WifiP2pManager.START_WPS:
607 replyToMessage(message, WifiP2pManager.START_WPS_FAILED,
608 WifiP2pManager.BUSY);
609 break;
Irfan Sheriff295da732011-09-09 14:10:15 -0700610 // Ignore
Irfan Sheriff618455f2011-11-18 14:33:09 -0800611 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800612 case WifiMonitor.SCAN_RESULTS_EVENT:
613 case WifiMonitor.SUP_CONNECTION_EVENT:
614 case WifiMonitor.SUP_DISCONNECTION_EVENT:
615 case WifiMonitor.NETWORK_CONNECTION_EVENT:
616 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
617 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
Irfan Sheriffd36adc32012-09-23 15:27:50 -0700618 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
619 case WifiMonitor.WPS_SUCCESS_EVENT:
620 case WifiMonitor.WPS_FAIL_EVENT:
621 case WifiMonitor.WPS_OVERLAP_EVENT:
622 case WifiMonitor.WPS_TIMEOUT_EVENT:
Irfan Sheriff55bfa422012-04-06 15:25:41 -0700623 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
Irfan Sheriff9cb98042012-05-24 17:16:50 -0700624 case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
625 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
626 case WifiMonitor.P2P_FIND_STOPPED_EVENT:
627 case WifiMonitor.P2P_SERV_DISC_RESP_EVENT:
Irfan Sheriff618455f2011-11-18 14:33:09 -0800628 case PEER_CONNECTION_USER_ACCEPT:
629 case PEER_CONNECTION_USER_REJECT:
Irfan Sheriff9f452d02012-10-15 12:00:29 -0700630 case DISCONNECT_WIFI_RESPONSE:
631 case DROP_WIFI_USER_ACCEPT:
632 case DROP_WIFI_USER_REJECT:
Irfan Sheriff618455f2011-11-18 14:33:09 -0800633 case GROUP_CREATING_TIMED_OUT:
Irfan Sheriff62fa6de2012-10-18 12:39:22 -0700634 case DISABLE_P2P_TIMED_OUT:
Irfan Sheriffd36adc32012-09-23 15:27:50 -0700635 case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
636 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
637 case DhcpStateMachine.CMD_ON_QUIT:
Irfan Sheriffc41096e2012-09-24 14:21:54 -0700638 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
Irfan Sheriff8b485ad2013-03-28 10:15:44 -0700639 case SET_MIRACAST_MODE:
Chong Zhang1f3ecaa2013-05-03 15:55:36 -0700640 case WifiP2pManager.START_LISTEN:
641 case WifiP2pManager.STOP_LISTEN:
642 case WifiP2pManager.SET_CHANNEL:
Vinit Deshapnde2c385ec2013-09-09 16:28:31 -0700643 case SET_COUNTRY_CODE:
repo sync55bc5f32011-06-24 14:23:07 -0700644 break;
Irfan Sheriff62fa6de2012-10-18 12:39:22 -0700645 case WifiStateMachine.CMD_ENABLE_P2P:
646 // Enable is lazy and has no response
647 break;
648 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
649 // If we end up handling in default, p2p is not enabled
650 mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP);
651 break;
Yoshihiko Ikenagabfb27bb2012-02-14 11:28:35 +0900652 /* unexpected group created, remove */
Irfan Sheriff55bfa422012-04-06 15:25:41 -0700653 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
654 mGroup = (WifiP2pGroup) message.obj;
655 loge("Unexpected group creation, remove " + mGroup);
656 mWifiNative.p2pGroupRemove(mGroup.getInterface());
657 break;
Irfan Sheriffde1e9fa92012-05-01 16:15:23 -0700658 // A group formation failure is always followed by
659 // a group removed event. Flushing things at group formation
660 // failure causes supplicant issues. Ignore right now.
Irfan Sheriff55bfa422012-04-06 15:25:41 -0700661 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
Irfan Sheriff55bfa422012-04-06 15:25:41 -0700662 break;
repo sync55bc5f32011-06-24 14:23:07 -0700663 default:
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700664 loge("Unhandled message " + message);
repo sync55bc5f32011-06-24 14:23:07 -0700665 return NOT_HANDLED;
666 }
667 return HANDLED;
668 }
669 }
670
671 class P2pNotSupportedState extends State {
672 @Override
673 public boolean processMessage(Message message) {
674 switch (message.what) {
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800675 case WifiP2pManager.DISCOVER_PEERS:
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700676 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
677 WifiP2pManager.P2P_UNSUPPORTED);
678 break;
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800679 case WifiP2pManager.STOP_DISCOVERY:
680 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
681 WifiP2pManager.P2P_UNSUPPORTED);
682 break;
Irfan Sheriff21ba8152012-04-04 16:22:21 -0700683 case WifiP2pManager.DISCOVER_SERVICES:
684 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
685 WifiP2pManager.P2P_UNSUPPORTED);
686 break;
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700687 case WifiP2pManager.CONNECT:
688 replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
689 WifiP2pManager.P2P_UNSUPPORTED);
690 break;
Irfan Sheriff651cdfc2011-09-07 00:31:20 -0700691 case WifiP2pManager.CANCEL_CONNECT:
692 replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
693 WifiP2pManager.P2P_UNSUPPORTED);
694 break;
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800695 case WifiP2pManager.CREATE_GROUP:
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700696 replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
697 WifiP2pManager.P2P_UNSUPPORTED);
698 break;
699 case WifiP2pManager.REMOVE_GROUP:
700 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
701 WifiP2pManager.P2P_UNSUPPORTED);
702 break;
Irfan Sheriff21ba8152012-04-04 16:22:21 -0700703 case WifiP2pManager.ADD_LOCAL_SERVICE:
704 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED,
705 WifiP2pManager.P2P_UNSUPPORTED);
706 break;
707 case WifiP2pManager.REMOVE_LOCAL_SERVICE:
708 replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED,
709 WifiP2pManager.P2P_UNSUPPORTED);
710 break;
711 case WifiP2pManager.CLEAR_LOCAL_SERVICES:
712 replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED,
713 WifiP2pManager.P2P_UNSUPPORTED);
714 break;
715 case WifiP2pManager.ADD_SERVICE_REQUEST:
716 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED,
717 WifiP2pManager.P2P_UNSUPPORTED);
718 break;
719 case WifiP2pManager.REMOVE_SERVICE_REQUEST:
720 replyToMessage(message,
721 WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED,
722 WifiP2pManager.P2P_UNSUPPORTED);
723 break;
724 case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
725 replyToMessage(message,
726 WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED,
727 WifiP2pManager.P2P_UNSUPPORTED);
728 break;
Irfan Sheriff2bdefca2012-04-25 16:40:14 -0700729 case WifiP2pManager.SET_DEVICE_NAME:
730 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
731 WifiP2pManager.P2P_UNSUPPORTED);
732 break;
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +0900733 case WifiP2pManager.DELETE_PERSISTENT_GROUP:
734 replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP,
735 WifiP2pManager.P2P_UNSUPPORTED);
736 break;
Andreas Huberab4cd452012-08-15 16:16:31 -0700737 case WifiP2pManager.SET_WFD_INFO:
738 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
739 WifiP2pManager.P2P_UNSUPPORTED);
740 break;
Irfan Sherifff1180432012-12-13 12:33:42 -0800741 case WifiP2pManager.START_WPS:
742 replyToMessage(message, WifiP2pManager.START_WPS_FAILED,
743 WifiP2pManager.P2P_UNSUPPORTED);
744 break;
Chong Zhang1f3ecaa2013-05-03 15:55:36 -0700745 case WifiP2pManager.START_LISTEN:
746 replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED,
747 WifiP2pManager.P2P_UNSUPPORTED);
748 break;
749 case WifiP2pManager.STOP_LISTEN:
750 replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED,
751 WifiP2pManager.P2P_UNSUPPORTED);
752 break;
753
754 default:
repo sync55bc5f32011-06-24 14:23:07 -0700755 return NOT_HANDLED;
756 }
757 return HANDLED;
758 }
759 }
760
761 class P2pDisablingState extends State {
762 @Override
Irfan Sheriff62fa6de2012-10-18 12:39:22 -0700763 public void enter() {
764 if (DBG) logd(getName());
765 sendMessageDelayed(obtainMessage(DISABLE_P2P_TIMED_OUT,
766 ++mDisableP2pTimeoutIndex, 0), DISABLE_P2P_WAIT_TIME_MS);
767 }
768
769 @Override
repo sync55bc5f32011-06-24 14:23:07 -0700770 public boolean processMessage(Message message) {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700771 if (DBG) logd(getName() + message.toString());
repo sync55bc5f32011-06-24 14:23:07 -0700772 switch (message.what) {
773 case WifiMonitor.SUP_DISCONNECTION_EVENT:
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800774 if (DBG) logd("p2p socket connection lost");
repo sync55bc5f32011-06-24 14:23:07 -0700775 transitionTo(mP2pDisabledState);
776 break;
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800777 case WifiStateMachine.CMD_ENABLE_P2P:
Irfan Sheriff62fa6de2012-10-18 12:39:22 -0700778 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700779 deferMessage(message);
780 break;
Irfan Sheriff62fa6de2012-10-18 12:39:22 -0700781 case DISABLE_P2P_TIMED_OUT:
782 if (mGroupCreatingTimeoutIndex == message.arg1) {
783 loge("P2p disable timed out");
784 transitionTo(mP2pDisabledState);
785 }
786 break;
repo sync55bc5f32011-06-24 14:23:07 -0700787 default:
788 return NOT_HANDLED;
789 }
790 return HANDLED;
791 }
Irfan Sheriff62fa6de2012-10-18 12:39:22 -0700792
793 @Override
794 public void exit() {
795 mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP);
796 }
repo sync55bc5f32011-06-24 14:23:07 -0700797 }
798
repo sync55bc5f32011-06-24 14:23:07 -0700799 class P2pDisabledState extends State {
800 @Override
801 public void enter() {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700802 if (DBG) logd(getName());
repo sync55bc5f32011-06-24 14:23:07 -0700803 }
804
805 @Override
806 public boolean processMessage(Message message) {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700807 if (DBG) logd(getName() + message.toString());
repo sync55bc5f32011-06-24 14:23:07 -0700808 switch (message.what) {
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800809 case WifiStateMachine.CMD_ENABLE_P2P:
Irfan Sheriffcb30b222011-07-29 20:54:52 -0700810 try {
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800811 mNwService.setInterfaceUp(mInterface);
812 } catch (RemoteException re) {
813 loge("Unable to change interface settings: " + re);
814 } catch (IllegalStateException ie) {
815 loge("Unable to change interface settings: " + ie);
Irfan Sheriffcb30b222011-07-29 20:54:52 -0700816 }
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800817 mWifiMonitor.startMonitoring();
818 transitionTo(mP2pEnablingState);
repo sync55bc5f32011-06-24 14:23:07 -0700819 break;
820 default:
821 return NOT_HANDLED;
822 }
823 return HANDLED;
824 }
825 }
826
827 class P2pEnablingState extends State {
828 @Override
829 public void enter() {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700830 if (DBG) logd(getName());
repo sync55bc5f32011-06-24 14:23:07 -0700831 }
832
833 @Override
834 public boolean processMessage(Message message) {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700835 if (DBG) logd(getName() + message.toString());
repo sync55bc5f32011-06-24 14:23:07 -0700836 switch (message.what) {
837 case WifiMonitor.SUP_CONNECTION_EVENT:
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800838 if (DBG) logd("P2p socket connection successful");
repo sync55bc5f32011-06-24 14:23:07 -0700839 transitionTo(mInactiveState);
840 break;
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700841 case WifiMonitor.SUP_DISCONNECTION_EVENT:
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800842 loge("P2p socket connection failed");
repo syncaea743a2011-07-29 23:55:49 -0700843 transitionTo(mP2pDisabledState);
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700844 break;
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800845 case WifiStateMachine.CMD_ENABLE_P2P:
Irfan Sheriff62fa6de2012-10-18 12:39:22 -0700846 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700847 deferMessage(message);
848 break;
repo sync55bc5f32011-06-24 14:23:07 -0700849 default:
850 return NOT_HANDLED;
851 }
852 return HANDLED;
853 }
854 }
855
856 class P2pEnabledState extends State {
857 @Override
858 public void enter() {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700859 if (DBG) logd(getName());
repo sync55bc5f32011-06-24 14:23:07 -0700860 sendP2pStateChangedBroadcast(true);
repo syncaea743a2011-07-29 23:55:49 -0700861 mNetworkInfo.setIsAvailable(true);
Irfan Sheriff55bfa422012-04-06 15:25:41 -0700862 sendP2pConnectionChangedBroadcast();
Irfan Sheriff93226872011-08-29 10:36:05 -0700863 initializeP2pSettings();
repo sync55bc5f32011-06-24 14:23:07 -0700864 }
865
866 @Override
867 public boolean processMessage(Message message) {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700868 if (DBG) logd(getName() + message.toString());
repo sync55bc5f32011-06-24 14:23:07 -0700869 switch (message.what) {
Irfan Sheriff41de2402012-10-12 15:52:13 -0700870 case WifiMonitor.SUP_DISCONNECTION_EVENT:
871 loge("Unexpected loss of p2p socket connection");
872 transitionTo(mP2pDisabledState);
873 break;
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800874 case WifiStateMachine.CMD_ENABLE_P2P:
875 //Nothing to do
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700876 break;
Irfan Sheriff62fa6de2012-10-18 12:39:22 -0700877 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
Irfan Sheriff3a67e252012-12-07 15:51:34 -0800878 if (mPeers.clear()) {
879 sendPeersChangedBroadcast();
880 }
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +0900881 if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast();
882
Vinit Deshapndec249c2c2013-08-08 10:38:53 -0700883 mWifiMonitor.stopMonitoring();
repo sync55bc5f32011-06-24 14:23:07 -0700884 transitionTo(mP2pDisablingState);
885 break;
Irfan Sheriff2bdefca2012-04-25 16:40:14 -0700886 case WifiP2pManager.SET_DEVICE_NAME:
Andreas Huberab4cd452012-08-15 16:16:31 -0700887 {
Irfan Sheriff2bdefca2012-04-25 16:40:14 -0700888 WifiP2pDevice d = (WifiP2pDevice) message.obj;
889 if (d != null && setAndPersistDeviceName(d.deviceName)) {
890 if (DBG) logd("set device name " + d.deviceName);
891 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_SUCCEEDED);
892 } else {
893 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
894 WifiP2pManager.ERROR);
895 }
896 break;
Andreas Huberab4cd452012-08-15 16:16:31 -0700897 }
898 case WifiP2pManager.SET_WFD_INFO:
899 {
900 WifiP2pWfdInfo d = (WifiP2pWfdInfo) message.obj;
901 if (d != null && setWfdInfo(d)) {
902 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_SUCCEEDED);
903 } else {
904 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
905 WifiP2pManager.ERROR);
906 }
907 break;
908 }
Robert Greenwalt6433ef22013-06-28 15:55:28 -0700909 case BLOCK_DISCOVERY:
910 boolean blocked = (message.arg1 == ENABLED ? true : false);
911 if (mDiscoveryBlocked == blocked) break;
912 mDiscoveryBlocked = blocked;
913 if (blocked && mDiscoveryStarted) {
914 mWifiNative.p2pStopFind();
915 mDiscoveryPostponed = true;
916 }
917 if (!blocked && mDiscoveryPostponed) {
918 mDiscoveryPostponed = false;
919 mWifiNative.p2pFind(DISCOVER_TIMEOUT_S);
920 }
921 if (blocked) {
922 try {
923 StateMachine m = (StateMachine)message.obj;
924 m.sendMessage(message.arg2);
925 } catch (Exception e) {
926 loge("unable to send BLOCK_DISCOVERY response: " + e);
927 }
928 }
929 break;
repo sync55bc5f32011-06-24 14:23:07 -0700930 case WifiP2pManager.DISCOVER_PEERS:
Robert Greenwalt6433ef22013-06-28 15:55:28 -0700931 if (mDiscoveryBlocked) {
932 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
933 WifiP2pManager.BUSY);
934 break;
935 }
Irfan Sheriff21ba8152012-04-04 16:22:21 -0700936 // do not send service discovery request while normal find operation.
937 clearSupplicantServiceRequest();
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800938 if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700939 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED);
Irfan Sheriffc111d1c2012-03-28 15:59:30 -0700940 sendP2pDiscoveryChangedBroadcast(true);
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700941 } else {
Irfan Sheriff4be4d312011-09-03 11:03:23 -0700942 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
943 WifiP2pManager.ERROR);
Irfan Sheriffea5b16a2011-08-24 12:30:20 -0700944 }
repo sync55bc5f32011-06-24 14:23:07 -0700945 break;
Irfan Sheriffc111d1c2012-03-28 15:59:30 -0700946 case WifiMonitor.P2P_FIND_STOPPED_EVENT:
947 sendP2pDiscoveryChangedBroadcast(false);
948 break;
Irfan Sheriff7d6d9c02012-01-10 15:50:45 -0800949 case WifiP2pManager.STOP_DISCOVERY:
950 if (mWifiNative.p2pStopFind()) {
951 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED);
952 } else {
953 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
954 WifiP2pManager.ERROR);
955 }
956 break;
Irfan Sheriff21ba8152012-04-04 16:22:21 -0700957 case WifiP2pManager.DISCOVER_SERVICES:
Robert Greenwalt6433ef22013-06-28 15:55:28 -0700958 if (mDiscoveryBlocked) {
959 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
960 WifiP2pManager.BUSY);
961 break;
962 }
Irfan Sheriff21ba8152012-04-04 16:22:21 -0700963 if (DBG) logd(getName() + " discover services");
964 if (!updateSupplicantServiceRequest()) {
965 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
966 WifiP2pManager.NO_SERVICE_REQUESTS);
967 break;
968 }
969 if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {
970 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_SUCCEEDED);
971 } else {
972 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
973 WifiP2pManager.ERROR);
974 }
975 break;
repo sync55bc5f32011-06-24 14:23:07 -0700976 case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
977 WifiP2pDevice device = (WifiP2pDevice) message.obj;
Irfan Sheriff651cdfc2011-09-07 00:31:20 -0700978 if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break;
Irfan Sheriff3a67e252012-12-07 15:51:34 -0800979 mPeers.updateSupplicantDetails(device);
980 sendPeersChangedBroadcast();
repo sync55bc5f32011-06-24 14:23:07 -0700981 break;
982 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
983 device = (WifiP2pDevice) message.obj;
Irfan Sheriff3a67e252012-12-07 15:51:34 -0800984 // Gets current details for the one removed
985 device = mPeers.remove(device.deviceAddress);
986 if (device != null) {
987 sendPeersChangedBroadcast();
988 }
repo sync55bc5f32011-06-24 14:23:07 -0700989 break;
Irfan Sheriff8b485ad2013-03-28 10:15:44 -0700990 case WifiP2pManager.ADD_LOCAL_SERVICE:
Irfan Sheriff21ba8152012-04-04 16:22:21 -0700991 if (DBG) logd(getName() + " add service");
992 WifiP2pServiceInfo servInfo = (WifiP2pServiceInfo)message.obj;
993 if (addLocalService(message.replyTo, servInfo)) {
994 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_SUCCEEDED);
995 } else {
996 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED);
997 }
998 break;
999 case WifiP2pManager.REMOVE_LOCAL_SERVICE:
1000 if (DBG) logd(getName() + " remove service");
1001 servInfo = (WifiP2pServiceInfo)message.obj;
1002 removeLocalService(message.replyTo, servInfo);
1003 replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_SUCCEEDED);
1004 break;
1005 case WifiP2pManager.CLEAR_LOCAL_SERVICES:
1006 if (DBG) logd(getName() + " clear service");
1007 clearLocalServices(message.replyTo);
Irfan Sheriff96aa0db2012-06-08 09:24:33 -07001008 replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_SUCCEEDED);
Irfan Sheriff21ba8152012-04-04 16:22:21 -07001009 break;
1010 case WifiP2pManager.ADD_SERVICE_REQUEST:
1011 if (DBG) logd(getName() + " add service request");
1012 if (!addServiceRequest(message.replyTo, (WifiP2pServiceRequest)message.obj)) {
1013 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED);
1014 break;
1015 }
1016 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_SUCCEEDED);
1017 break;
1018 case WifiP2pManager.REMOVE_SERVICE_REQUEST:
1019 if (DBG) logd(getName() + " remove service request");
1020 removeServiceRequest(message.replyTo, (WifiP2pServiceRequest)message.obj);
1021 replyToMessage(message, WifiP2pManager.REMOVE_SERVICE_REQUEST_SUCCEEDED);
1022 break;
1023 case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
1024 if (DBG) logd(getName() + " clear service request");
1025 clearServiceRequests(message.replyTo);
1026 replyToMessage(message, WifiP2pManager.CLEAR_SERVICE_REQUESTS_SUCCEEDED);
1027 break;
Irfan Sheriff8b485ad2013-03-28 10:15:44 -07001028 case WifiMonitor.P2P_SERV_DISC_RESP_EVENT:
Irfan Sheriff21ba8152012-04-04 16:22:21 -07001029 if (DBG) logd(getName() + " receive service response");
1030 List<WifiP2pServiceResponse> sdRespList =
1031 (List<WifiP2pServiceResponse>) message.obj;
1032 for (WifiP2pServiceResponse resp : sdRespList) {
1033 WifiP2pDevice dev =
1034 mPeers.get(resp.getSrcDevice().deviceAddress);
1035 resp.setSrcDevice(dev);
1036 sendServiceResponse(resp);
1037 }
1038 break;
Irfan Sheriff8b485ad2013-03-28 10:15:44 -07001039 case WifiP2pManager.DELETE_PERSISTENT_GROUP:
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001040 if (DBG) logd(getName() + " delete persistent group");
1041 mGroups.remove(message.arg1);
1042 replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP_SUCCEEDED);
1043 break;
Irfan Sheriff8b485ad2013-03-28 10:15:44 -07001044 case SET_MIRACAST_MODE:
1045 mWifiNative.setMiracastMode(message.arg1);
1046 break;
Chong Zhang1f3ecaa2013-05-03 15:55:36 -07001047 case WifiP2pManager.START_LISTEN:
1048 if (DBG) logd(getName() + " start listen mode");
1049 mWifiNative.p2pFlush();
1050 if (mWifiNative.p2pExtListen(true, 500, 500)) {
1051 replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED);
1052 } else {
1053 replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED);
1054 }
1055 break;
1056 case WifiP2pManager.STOP_LISTEN:
1057 if (DBG) logd(getName() + " stop listen mode");
1058 if (mWifiNative.p2pExtListen(false, 0, 0)) {
1059 replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED);
1060 } else {
1061 replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED);
1062 }
1063 mWifiNative.p2pFlush();
1064 break;
1065 case WifiP2pManager.SET_CHANNEL:
1066 Bundle p2pChannels = (Bundle) message.obj;
1067 int lc = p2pChannels.getInt("lc", 0);
1068 int oc = p2pChannels.getInt("oc", 0);
1069 if (DBG) logd(getName() + " set listen and operating channel");
1070 if (mWifiNative.p2pSetChannel(lc, oc)) {
1071 replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED);
1072 } else {
1073 replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED);
1074 }
1075 break;
Vinit Deshapnde2c385ec2013-09-09 16:28:31 -07001076 case SET_COUNTRY_CODE:
1077 String countryCode = (String) message.obj;
Vinit Deshapndeda40d922013-10-21 11:58:40 -07001078 countryCode = countryCode.toUpperCase(Locale.ROOT);
1079 if (mLastSetCountryCode == null ||
1080 countryCode.equals(mLastSetCountryCode) == false) {
1081 if (mWifiNative.setCountryCode(countryCode)) {
1082 mLastSetCountryCode = countryCode;
1083 }
1084 }
Vinit Deshapnde2c385ec2013-09-09 16:28:31 -07001085 break;
Irfan Sheriff21ba8152012-04-04 16:22:21 -07001086 default:
Irfan Sheriff8b485ad2013-03-28 10:15:44 -07001087 return NOT_HANDLED;
repo sync55bc5f32011-06-24 14:23:07 -07001088 }
1089 return HANDLED;
1090 }
1091
1092 @Override
1093 public void exit() {
Yuhao Zheng8b033d32013-10-09 11:53:51 -07001094 sendP2pDiscoveryChangedBroadcast(false);
repo sync55bc5f32011-06-24 14:23:07 -07001095 sendP2pStateChangedBroadcast(false);
repo syncaea743a2011-07-29 23:55:49 -07001096 mNetworkInfo.setIsAvailable(false);
Vinit Deshapndeda40d922013-10-21 11:58:40 -07001097
1098 mLastSetCountryCode = null;
repo sync55bc5f32011-06-24 14:23:07 -07001099 }
1100 }
1101
1102 class InactiveState extends State {
Irfan Sheriff4be4d312011-09-03 11:03:23 -07001103 @Override
1104 public void enter() {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07001105 if (DBG) logd(getName());
Irfan Sherifff1180432012-12-13 12:33:42 -08001106 mSavedPeerConfig.invalidate();
repo sync55bc5f32011-06-24 14:23:07 -07001107 }
1108
1109 @Override
1110 public boolean processMessage(Message message) {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07001111 if (DBG) logd(getName() + message.toString());
repo sync55bc5f32011-06-24 14:23:07 -07001112 switch (message.what) {
Irfan Sheriff618455f2011-11-18 14:33:09 -08001113 case WifiP2pManager.CONNECT:
1114 if (DBG) logd(getName() + " sending connect");
Yoshihiko Ikenagabfb27bb2012-02-14 11:28:35 +09001115 WifiP2pConfig config = (WifiP2pConfig) message.obj;
Irfan Sherifff1180432012-12-13 12:33:42 -08001116 if (isConfigInvalid(config)) {
1117 loge("Dropping connect requeset " + config);
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001118 replyToMessage(message, WifiP2pManager.CONNECT_FAILED);
1119 break;
Irfan Sheriff618455f2011-11-18 14:33:09 -08001120 }
Irfan Sherifff1180432012-12-13 12:33:42 -08001121
1122 mAutonomousGroup = false;
1123 mWifiNative.p2pStopFind();
1124 if (reinvokePersistentGroup(config)) {
1125 transitionTo(mGroupNegotiationState);
1126 } else {
1127 transitionTo(mProvisionDiscoveryState);
1128 }
1129 mSavedPeerConfig = config;
Yoshihiko Ikenagabfb27bb2012-02-14 11:28:35 +09001130 mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
Irfan Sheriff3a67e252012-12-07 15:51:34 -08001131 sendPeersChangedBroadcast();
Irfan Sheriff618455f2011-11-18 14:33:09 -08001132 replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001133 break;
1134 case WifiP2pManager.STOP_DISCOVERY:
1135 if (mWifiNative.p2pStopFind()) {
1136 // When discovery stops in inactive state, flush to clear
1137 // state peer data
1138 mWifiNative.p2pFlush();
1139 mServiceDiscReqId = null;
1140 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED);
1141 } else {
1142 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
1143 WifiP2pManager.ERROR);
1144 }
Irfan Sheriff618455f2011-11-18 14:33:09 -08001145 break;
repo sync55bc5f32011-06-24 14:23:07 -07001146 case WifiMonitor.P2P_GO_NEGOTIATION_REQUEST_EVENT:
Irfan Sherifff1180432012-12-13 12:33:42 -08001147 config = (WifiP2pConfig) message.obj;
1148 if (isConfigInvalid(config)) {
1149 loge("Dropping GO neg request " + config);
1150 break;
1151 }
1152 mSavedPeerConfig = config;
Irfan Sheriff10ca8702012-05-10 16:52:49 -07001153 mAutonomousGroup = false;
1154 mJoinExistingGroup = false;
Irfan Sherifff1180432012-12-13 12:33:42 -08001155 transitionTo(mUserAuthorizingNegotiationRequestState);
Irfan Sheriff618455f2011-11-18 14:33:09 -08001156 break;
1157 case WifiMonitor.P2P_INVITATION_RECEIVED_EVENT:
1158 WifiP2pGroup group = (WifiP2pGroup) message.obj;
Irfan Sheriffbfed2d62011-12-09 12:40:04 -08001159 WifiP2pDevice owner = group.getOwner();
1160
1161 if (owner == null) {
Irfan Sherifff1180432012-12-13 12:33:42 -08001162 loge("Ignored invitation from null owner");
Irfan Sheriffbfed2d62011-12-09 12:40:04 -08001163 break;
1164 }
1165
Irfan Sherifff1180432012-12-13 12:33:42 -08001166 config = new WifiP2pConfig();
1167 config.deviceAddress = group.getOwner().deviceAddress;
1168
1169 if (isConfigInvalid(config)) {
1170 loge("Dropping invitation request " + config);
1171 break;
1172 }
1173 mSavedPeerConfig = config;
Irfan Sheriffbfed2d62011-12-09 12:40:04 -08001174
1175 //Check if we have the owner in peer list and use appropriate
1176 //wps method. Default is to use PBC.
Yoshihiko Ikenagabfb27bb2012-02-14 11:28:35 +09001177 if ((owner = mPeers.get(owner.deviceAddress)) != null) {
Irfan Sheriffbfed2d62011-12-09 12:40:04 -08001178 if (owner.wpsPbcSupported()) {
1179 mSavedPeerConfig.wps.setup = WpsInfo.PBC;
1180 } else if (owner.wpsKeypadSupported()) {
1181 mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD;
1182 } else if (owner.wpsDisplaySupported()) {
1183 mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;
1184 }
1185 }
Yoshihiko Ikenagabfb27bb2012-02-14 11:28:35 +09001186
Irfan Sheriff10ca8702012-05-10 16:52:49 -07001187 mAutonomousGroup = false;
1188 mJoinExistingGroup = true;
Irfan Sherifff1180432012-12-13 12:33:42 -08001189 transitionTo(mUserAuthorizingInviteRequestState);
Irfan Sheriff618455f2011-11-18 14:33:09 -08001190 break;
1191 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
1192 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
1193 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
Yoshihiko Ikenagabfb27bb2012-02-14 11:28:35 +09001194 //We let the supplicant handle the provision discovery response
1195 //and wait instead for the GO_NEGOTIATION_REQUEST_EVENT.
1196 //Handling provision discovery and issuing a p2p_connect before
1197 //group negotiation comes through causes issues
Yoshihiko Ikenaga7d9cf112012-11-16 16:58:10 +09001198 break;
repo sync55bc5f32011-06-24 14:23:07 -07001199 case WifiP2pManager.CREATE_GROUP:
Yoshihiko Ikenaga7d9cf112012-11-16 16:58:10 +09001200 mAutonomousGroup = true;
1201 int netId = message.arg1;
1202 boolean ret = false;
1203 if (netId == WifiP2pGroup.PERSISTENT_NET_ID) {
1204 // check if the go persistent group is present.
1205 netId = mGroups.getNetworkId(mThisDevice.deviceAddress);
1206 if (netId != -1) {
1207 ret = mWifiNative.p2pGroupAdd(netId);
1208 } else {
1209 ret = mWifiNative.p2pGroupAdd(true);
1210 }
1211 } else {
1212 ret = mWifiNative.p2pGroupAdd(false);
1213 }
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001214
Yoshihiko Ikenaga7d9cf112012-11-16 16:58:10 +09001215 if (ret) {
1216 replyToMessage(message, WifiP2pManager.CREATE_GROUP_SUCCEEDED);
1217 transitionTo(mGroupNegotiationState);
1218 } else {
1219 replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
1220 WifiP2pManager.ERROR);
1221 // remain at this state.
1222 }
1223 break;
Irfan Sheriff51aec5e2012-10-22 16:28:02 -07001224 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
Yoshihiko Ikenaga7d9cf112012-11-16 16:58:10 +09001225 mGroup = (WifiP2pGroup) message.obj;
1226 if (DBG) logd(getName() + " group started");
Irfan Sheriff51aec5e2012-10-22 16:28:02 -07001227
1228 // We hit this scenario when a persistent group is reinvoked
Yoshihiko Ikenaga7d9cf112012-11-16 16:58:10 +09001229 if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) {
1230 mAutonomousGroup = false;
1231 deferMessage(message);
1232 transitionTo(mGroupNegotiationState);
1233 } else {
1234 loge("Unexpected group creation, remove " + mGroup);
1235 mWifiNative.p2pGroupRemove(mGroup.getInterface());
1236 }
1237 break;
Chong Zhang1f3ecaa2013-05-03 15:55:36 -07001238 case WifiP2pManager.START_LISTEN:
1239 if (DBG) logd(getName() + " start listen mode");
1240 mWifiNative.p2pFlush();
1241 if (mWifiNative.p2pExtListen(true, 500, 500)) {
1242 replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED);
1243 } else {
1244 replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED);
1245 }
1246 break;
1247 case WifiP2pManager.STOP_LISTEN:
1248 if (DBG) logd(getName() + " stop listen mode");
1249 if (mWifiNative.p2pExtListen(false, 0, 0)) {
1250 replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED);
1251 } else {
1252 replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED);
1253 }
1254 mWifiNative.p2pFlush();
1255 break;
1256 case WifiP2pManager.SET_CHANNEL:
1257 Bundle p2pChannels = (Bundle) message.obj;
1258 int lc = p2pChannels.getInt("lc", 0);
1259 int oc = p2pChannels.getInt("oc", 0);
1260 if (DBG) logd(getName() + " set listen and operating channel");
1261 if (mWifiNative.p2pSetChannel(lc, oc)) {
1262 replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED);
1263 } else {
1264 replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED);
1265 }
1266 break;
Irfan Sheriff51aec5e2012-10-22 16:28:02 -07001267 default:
Yoshihiko Ikenaga7d9cf112012-11-16 16:58:10 +09001268 return NOT_HANDLED;
repo sync55bc5f32011-06-24 14:23:07 -07001269 }
1270 return HANDLED;
1271 }
1272 }
1273
Irfan Sheriff618455f2011-11-18 14:33:09 -08001274 class GroupCreatingState extends State {
Irfan Sheriffbbe77ca2011-11-01 11:49:21 -07001275 @Override
1276 public void enter() {
1277 if (DBG) logd(getName());
Irfan Sheriff618455f2011-11-18 14:33:09 -08001278 sendMessageDelayed(obtainMessage(GROUP_CREATING_TIMED_OUT,
1279 ++mGroupCreatingTimeoutIndex, 0), GROUP_CREATING_WAIT_TIME_MS);
Irfan Sheriffbbe77ca2011-11-01 11:49:21 -07001280 }
1281
1282 @Override
1283 public boolean processMessage(Message message) {
1284 if (DBG) logd(getName() + message.toString());
Irfan Sheriff9cb98042012-05-24 17:16:50 -07001285 boolean ret = HANDLED;
Irfan Sheriffbbe77ca2011-11-01 11:49:21 -07001286 switch (message.what) {
Irfan Sheriff618455f2011-11-18 14:33:09 -08001287 case GROUP_CREATING_TIMED_OUT:
1288 if (mGroupCreatingTimeoutIndex == message.arg1) {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07001289 if (DBG) logd("Group negotiation timed out");
Irfan Sheriff55bfa422012-04-06 15:25:41 -07001290 handleGroupCreationFailure();
repo syncaea743a2011-07-29 23:55:49 -07001291 transitionTo(mInactiveState);
1292 }
1293 break;
Irfan Sheriff9cb98042012-05-24 17:16:50 -07001294 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
1295 WifiP2pDevice device = (WifiP2pDevice) message.obj;
Irfan Sherifff1180432012-12-13 12:33:42 -08001296 if (!mSavedPeerConfig.deviceAddress.equals(device.deviceAddress)) {
Irfan Sheriff9f452d02012-10-15 12:00:29 -07001297 if (DBG) {
1298 logd("mSavedPeerConfig " + mSavedPeerConfig.deviceAddress +
1299 "device " + device.deviceAddress);
1300 }
Irfan Sheriff9cb98042012-05-24 17:16:50 -07001301 // Do the regular device lost handling
1302 ret = NOT_HANDLED;
1303 break;
1304 }
1305 // Do nothing
Irfan Sheriff41de2402012-10-12 15:52:13 -07001306 if (DBG) logd("Add device to lost list " + device);
Irfan Sheriff3a67e252012-12-07 15:51:34 -08001307 mPeersLostDuringConnection.updateSupplicantDetails(device);
Irfan Sheriff9cb98042012-05-24 17:16:50 -07001308 break;
Irfan Sheriff4be4d312011-09-03 11:03:23 -07001309 case WifiP2pManager.DISCOVER_PEERS:
1310 /* Discovery will break negotiation */
1311 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
1312 WifiP2pManager.BUSY);
1313 break;
Irfan Sheriff651cdfc2011-09-07 00:31:20 -07001314 case WifiP2pManager.CANCEL_CONNECT:
Irfan Sheriff55bfa422012-04-06 15:25:41 -07001315 //Do a supplicant p2p_cancel which only cancels an ongoing
1316 //group negotiation. This will fail for a pending provision
1317 //discovery or for a pending user action, but at the framework
Irfan Sheriffde1e9fa92012-05-01 16:15:23 -07001318 //level, we always treat cancel as succeeded and enter
Irfan Sheriff55bfa422012-04-06 15:25:41 -07001319 //an inactive state
1320 mWifiNative.p2pCancelConnect();
1321 handleGroupCreationFailure();
1322 transitionTo(mInactiveState);
1323 replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_SUCCEEDED);
Irfan Sheriff651cdfc2011-09-07 00:31:20 -07001324 break;
repo sync55bc5f32011-06-24 14:23:07 -07001325 default:
Irfan Sheriff9cb98042012-05-24 17:16:50 -07001326 ret = NOT_HANDLED;
repo sync55bc5f32011-06-24 14:23:07 -07001327 }
Irfan Sheriff9cb98042012-05-24 17:16:50 -07001328 return ret;
repo sync55bc5f32011-06-24 14:23:07 -07001329 }
1330 }
1331
Irfan Sherifff1180432012-12-13 12:33:42 -08001332 class UserAuthorizingNegotiationRequestState extends State {
Irfan Sheriff618455f2011-11-18 14:33:09 -08001333 @Override
1334 public void enter() {
1335 if (DBG) logd(getName());
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001336 notifyInvitationReceived();
Irfan Sheriff618455f2011-11-18 14:33:09 -08001337 }
1338
1339 @Override
1340 public boolean processMessage(Message message) {
1341 if (DBG) logd(getName() + message.toString());
Yoshihiko Ikenagabfb27bb2012-02-14 11:28:35 +09001342 boolean ret = HANDLED;
Irfan Sheriff618455f2011-11-18 14:33:09 -08001343 switch (message.what) {
1344 case PEER_CONNECTION_USER_ACCEPT:
Irfan Sherifff1180432012-12-13 12:33:42 -08001345 mWifiNative.p2pStopFind();
1346 p2pConnectWithPinDisplay(mSavedPeerConfig);
Yoshihiko Ikenagabfb27bb2012-02-14 11:28:35 +09001347 mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
Irfan Sheriff3a67e252012-12-07 15:51:34 -08001348 sendPeersChangedBroadcast();
Irfan Sheriff618455f2011-11-18 14:33:09 -08001349 transitionTo(mGroupNegotiationState);
Irfan Sherifff1180432012-12-13 12:33:42 -08001350 break;
Irfan Sheriff618455f2011-11-18 14:33:09 -08001351 case PEER_CONNECTION_USER_REJECT:
Irfan Sherifff1180432012-12-13 12:33:42 -08001352 if (DBG) logd("User rejected negotiation " + mSavedPeerConfig);
Irfan Sheriff618455f2011-11-18 14:33:09 -08001353 transitionTo(mInactiveState);
1354 break;
1355 default:
1356 return NOT_HANDLED;
1357 }
Yoshihiko Ikenagabfb27bb2012-02-14 11:28:35 +09001358 return ret;
Irfan Sheriff618455f2011-11-18 14:33:09 -08001359 }
1360
1361 @Override
1362 public void exit() {
1363 //TODO: dismiss dialog if not already done
1364 }
1365 }
1366
Irfan Sherifff1180432012-12-13 12:33:42 -08001367 class UserAuthorizingInviteRequestState extends State {
1368 @Override
1369 public void enter() {
1370 if (DBG) logd(getName());
1371 notifyInvitationReceived();
1372 }
1373
1374 @Override
1375 public boolean processMessage(Message message) {
1376 if (DBG) logd(getName() + message.toString());
1377 boolean ret = HANDLED;
1378 switch (message.what) {
1379 case PEER_CONNECTION_USER_ACCEPT:
1380 mWifiNative.p2pStopFind();
1381 if (!reinvokePersistentGroup(mSavedPeerConfig)) {
1382 // Do negotiation when persistence fails
1383 p2pConnectWithPinDisplay(mSavedPeerConfig);
1384 }
1385 mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
1386 sendPeersChangedBroadcast();
1387 transitionTo(mGroupNegotiationState);
1388 break;
1389 case PEER_CONNECTION_USER_REJECT:
1390 if (DBG) logd("User rejected invitation " + mSavedPeerConfig);
1391 transitionTo(mInactiveState);
1392 break;
1393 default:
1394 return NOT_HANDLED;
1395 }
1396 return ret;
1397 }
1398
1399 @Override
1400 public void exit() {
1401 //TODO: dismiss dialog if not already done
1402 }
1403 }
1404
1405
1406
Irfan Sheriff618455f2011-11-18 14:33:09 -08001407 class ProvisionDiscoveryState extends State {
1408 @Override
1409 public void enter() {
1410 if (DBG) logd(getName());
Irfan Sherifffc7f95a2012-01-04 14:50:09 -08001411 mWifiNative.p2pProvisionDiscovery(mSavedPeerConfig);
Irfan Sheriff618455f2011-11-18 14:33:09 -08001412 }
1413
1414 @Override
1415 public boolean processMessage(Message message) {
1416 if (DBG) logd(getName() + message.toString());
1417 WifiP2pProvDiscEvent provDisc;
1418 WifiP2pDevice device;
1419 switch (message.what) {
1420 case WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT:
1421 provDisc = (WifiP2pProvDiscEvent) message.obj;
1422 device = provDisc.device;
1423 if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
1424
1425 if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
1426 if (DBG) logd("Found a match " + mSavedPeerConfig);
Irfan Sheriff4bbb1392012-08-28 16:05:43 -07001427 p2pConnectWithPinDisplay(mSavedPeerConfig);
Irfan Sheriff618455f2011-11-18 14:33:09 -08001428 transitionTo(mGroupNegotiationState);
1429 }
1430 break;
1431 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
1432 provDisc = (WifiP2pProvDiscEvent) message.obj;
1433 device = provDisc.device;
1434 if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
1435
1436 if (mSavedPeerConfig.wps.setup == WpsInfo.KEYPAD) {
1437 if (DBG) logd("Found a match " + mSavedPeerConfig);
1438 /* we already have the pin */
1439 if (!TextUtils.isEmpty(mSavedPeerConfig.wps.pin)) {
Irfan Sheriff4bbb1392012-08-28 16:05:43 -07001440 p2pConnectWithPinDisplay(mSavedPeerConfig);
Irfan Sheriff618455f2011-11-18 14:33:09 -08001441 transitionTo(mGroupNegotiationState);
1442 } else {
Irfan Sheriff10ca8702012-05-10 16:52:49 -07001443 mJoinExistingGroup = false;
Irfan Sherifff1180432012-12-13 12:33:42 -08001444 transitionTo(mUserAuthorizingNegotiationRequestState);
Irfan Sheriff618455f2011-11-18 14:33:09 -08001445 }
1446 }
1447 break;
1448 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
1449 provDisc = (WifiP2pProvDiscEvent) message.obj;
1450 device = provDisc.device;
1451 if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
1452
1453 if (mSavedPeerConfig.wps.setup == WpsInfo.DISPLAY) {
1454 if (DBG) logd("Found a match " + mSavedPeerConfig);
1455 mSavedPeerConfig.wps.pin = provDisc.pin;
Irfan Sheriff4bbb1392012-08-28 16:05:43 -07001456 p2pConnectWithPinDisplay(mSavedPeerConfig);
Irfan Sheriffef96a432012-12-05 16:36:20 -08001457 notifyInvitationSent(provDisc.pin, device.deviceAddress);
Irfan Sheriff618455f2011-11-18 14:33:09 -08001458 transitionTo(mGroupNegotiationState);
1459 }
1460 break;
Irfan Sheriffc41096e2012-09-24 14:21:54 -07001461 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
1462 loge("provision discovery failed");
1463 handleGroupCreationFailure();
1464 transitionTo(mInactiveState);
1465 break;
Irfan Sheriff618455f2011-11-18 14:33:09 -08001466 default:
1467 return NOT_HANDLED;
1468 }
1469 return HANDLED;
1470 }
1471 }
1472
1473 class GroupNegotiationState extends State {
1474 @Override
1475 public void enter() {
1476 if (DBG) logd(getName());
1477 }
1478
1479 @Override
1480 public boolean processMessage(Message message) {
1481 if (DBG) logd(getName() + message.toString());
1482 switch (message.what) {
1483 // We ignore these right now, since we get a GROUP_STARTED notification
1484 // afterwards
1485 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
1486 case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:
1487 if (DBG) logd(getName() + " go success");
1488 break;
1489 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
1490 mGroup = (WifiP2pGroup) message.obj;
1491 if (DBG) logd(getName() + " group started");
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001492
1493 if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) {
1494 /*
1495 * update cache information and set network id to mGroup.
1496 */
Irfan Sheriffca1269f2012-09-27 17:01:41 -07001497 updatePersistentNetworks(NO_RELOAD);
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001498 String devAddr = mGroup.getOwner().deviceAddress;
1499 mGroup.setNetworkId(mGroups.getNetworkId(devAddr,
1500 mGroup.getNetworkName()));
1501 }
1502
Irfan Sheriff618455f2011-11-18 14:33:09 -08001503 if (mGroup.isGroupOwner()) {
Irfan Sheriffce6fc8d2012-09-28 16:49:50 -07001504 /* Setting an idle time out on GO causes issues with certain scenarios
1505 * on clients where it can be off-channel for longer and with the power
1506 * save modes used.
1507 *
1508 * TODO: Verify multi-channel scenarios and supplicant behavior are
1509 * better before adding a time out in future
1510 */
Robert Greenwaltc77e2d72013-05-10 15:26:30 -07001511 //Set group idle timeout of 10 sec, to avoid GO beaconing incase of any
1512 //failure during 4-way Handshake.
1513 if (!mAutonomousGroup) {
1514 mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);
1515 }
Irfan Sheriff618455f2011-11-18 14:33:09 -08001516 startDhcpServer(mGroup.getInterface());
1517 } else {
Irfan Sheriffce6fc8d2012-09-28 16:49:50 -07001518 mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);
Irfan Sheriff618455f2011-11-18 14:33:09 -08001519 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(mContext,
1520 P2pStateMachine.this, mGroup.getInterface());
Dmitry Shmidte25f9d22013-05-10 17:53:58 -07001521 // TODO: We should use DHCP state machine PRE message like WifiStateMachine
1522 mWifiNative.setP2pPowerSave(mGroup.getInterface(), false);
Irfan Sheriff618455f2011-11-18 14:33:09 -08001523 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
1524 WifiP2pDevice groupOwner = mGroup.getOwner();
Irfan Sheriff9dab7d62013-02-12 09:51:47 -08001525 WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress);
1526 if (peer != null) {
1527 // update group owner details with peer details found at discovery
1528 groupOwner.updateSupplicantDetails(peer);
1529 mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED);
1530 sendPeersChangedBroadcast();
1531 } else {
1532 // A supplicant bug can lead to reporting an invalid
1533 // group owner address (all zeroes) at times. Avoid a
1534 // crash, but continue group creation since it is not
1535 // essential.
1536 logw("Unknown group owner " + groupOwner);
1537 }
Irfan Sheriff618455f2011-11-18 14:33:09 -08001538 }
Irfan Sheriff618455f2011-11-18 14:33:09 -08001539 transitionTo(mGroupCreatedState);
1540 break;
1541 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
Irfan Sheriff9f452d02012-10-15 12:00:29 -07001542 P2pStatus status = (P2pStatus) message.obj;
1543 if (status == P2pStatus.NO_COMMON_CHANNEL) {
1544 transitionTo(mFrequencyConflictState);
1545 break;
1546 }
1547 /* continue with group removal handling */
Irfan Sheriffde1e9fa92012-05-01 16:15:23 -07001548 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
Irfan Sheriff618455f2011-11-18 14:33:09 -08001549 if (DBG) logd(getName() + " go failure");
Irfan Sheriff55bfa422012-04-06 15:25:41 -07001550 handleGroupCreationFailure();
Irfan Sheriff618455f2011-11-18 14:33:09 -08001551 transitionTo(mInactiveState);
1552 break;
Irfan Sheriffde1e9fa92012-05-01 16:15:23 -07001553 // A group formation failure is always followed by
1554 // a group removed event. Flushing things at group formation
1555 // failure causes supplicant issues. Ignore right now.
1556 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
Irfan Sheriff9f452d02012-10-15 12:00:29 -07001557 status = (P2pStatus) message.obj;
1558 if (status == P2pStatus.NO_COMMON_CHANNEL) {
1559 transitionTo(mFrequencyConflictState);
1560 break;
1561 }
Irfan Sheriffde1e9fa92012-05-01 16:15:23 -07001562 break;
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001563 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
Irfan Sheriff9f452d02012-10-15 12:00:29 -07001564 status = (P2pStatus)message.obj;
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001565 if (status == P2pStatus.SUCCESS) {
1566 // invocation was succeeded.
1567 // wait P2P_GROUP_STARTED_EVENT.
1568 break;
Irfan Sherifff1180432012-12-13 12:33:42 -08001569 }
1570 loge("Invitation result " + status);
1571 if (status == P2pStatus.UNKNOWN_P2P_GROUP) {
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001572 // target device has already removed the credential.
1573 // So, remove this credential accordingly.
1574 int netId = mSavedPeerConfig.netId;
1575 if (netId >= 0) {
1576 if (DBG) logd("Remove unknown client from the list");
1577 removeClientFromList(netId, mSavedPeerConfig.deviceAddress, true);
1578 }
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001579
Irfan Sherifff1180432012-12-13 12:33:42 -08001580 // Reinvocation has failed, try group negotiation
Yoshihiko Ikenaga93480052012-11-16 18:01:49 +09001581 mSavedPeerConfig.netId = WifiP2pGroup.PERSISTENT_NET_ID;
Irfan Sherifff1180432012-12-13 12:33:42 -08001582 p2pConnectWithPinDisplay(mSavedPeerConfig);
Yoshihiko Ikenaga93480052012-11-16 18:01:49 +09001583 } else if (status == P2pStatus.INFORMATION_IS_CURRENTLY_UNAVAILABLE) {
1584
1585 // Devices setting persistent_reconnect to 0 in wpa_supplicant
1586 // always defer the invocation request and return
1587 // "information is currently unable" error.
1588 // So, try another way to connect for interoperability.
Irfan Sheriffca1269f2012-09-27 17:01:41 -07001589 mSavedPeerConfig.netId = WifiP2pGroup.PERSISTENT_NET_ID;
Irfan Sherifff1180432012-12-13 12:33:42 -08001590 p2pConnectWithPinDisplay(mSavedPeerConfig);
Irfan Sheriff9f452d02012-10-15 12:00:29 -07001591 } else if (status == P2pStatus.NO_COMMON_CHANNEL) {
1592 transitionTo(mFrequencyConflictState);
Irfan Sheriffca1269f2012-09-27 17:01:41 -07001593 } else {
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001594 handleGroupCreationFailure();
1595 transitionTo(mInactiveState);
1596 }
1597 break;
Irfan Sheriff618455f2011-11-18 14:33:09 -08001598 default:
1599 return NOT_HANDLED;
1600 }
1601 return HANDLED;
1602 }
1603 }
1604
Irfan Sheriff9f452d02012-10-15 12:00:29 -07001605 class FrequencyConflictState extends State {
1606 private AlertDialog mFrequencyConflictDialog;
1607 @Override
1608 public void enter() {
1609 if (DBG) logd(getName());
1610 notifyFrequencyConflict();
1611 }
Irfan Sheriff618455f2011-11-18 14:33:09 -08001612
Irfan Sheriff9f452d02012-10-15 12:00:29 -07001613 private void notifyFrequencyConflict() {
1614 logd("Notify frequency conflict");
1615 Resources r = Resources.getSystem();
1616
1617 AlertDialog dialog = new AlertDialog.Builder(mContext)
1618 .setMessage(r.getString(R.string.wifi_p2p_frequency_conflict_message,
1619 getDeviceName(mSavedPeerConfig.deviceAddress)))
1620 .setPositiveButton(r.getString(R.string.dlg_ok), new OnClickListener() {
1621 @Override
1622 public void onClick(DialogInterface dialog, int which) {
1623 sendMessage(DROP_WIFI_USER_ACCEPT);
1624 }
1625 })
1626 .setNegativeButton(r.getString(R.string.decline), new OnClickListener() {
1627 @Override
1628 public void onClick(DialogInterface dialog, int which) {
1629 sendMessage(DROP_WIFI_USER_REJECT);
1630 }
1631 })
1632 .setOnCancelListener(new DialogInterface.OnCancelListener() {
1633 @Override
1634 public void onCancel(DialogInterface arg0) {
1635 sendMessage(DROP_WIFI_USER_REJECT);
1636 }
1637 })
1638 .create();
1639
1640 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1641 dialog.show();
1642 mFrequencyConflictDialog = dialog;
1643 }
1644
1645 @Override
1646 public boolean processMessage(Message message) {
1647 if (DBG) logd(getName() + message.toString());
1648 switch (message.what) {
1649 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
1650 case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:
1651 loge(getName() + "group sucess during freq conflict!");
1652 break;
1653 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
1654 loge(getName() + "group started after freq conflict, handle anyway");
1655 deferMessage(message);
1656 transitionTo(mGroupNegotiationState);
1657 break;
1658 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
1659 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
1660 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
1661 // Ignore failures since we retry again
1662 break;
1663 case DROP_WIFI_USER_REJECT:
1664 // User rejected dropping wifi in favour of p2p
1665 handleGroupCreationFailure();
1666 transitionTo(mInactiveState);
1667 break;
1668 case DROP_WIFI_USER_ACCEPT:
1669 // User accepted dropping wifi in favour of p2p
1670 mWifiChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_REQUEST, 1);
1671 mTempoarilyDisconnectedWifi = true;
1672 break;
1673 case DISCONNECT_WIFI_RESPONSE:
1674 // Got a response from wifistatemachine, retry p2p
1675 if (DBG) logd(getName() + "Wifi disconnected, retry p2p");
1676 transitionTo(mInactiveState);
1677 sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
1678 break;
1679 default:
1680 return NOT_HANDLED;
1681 }
1682 return HANDLED;
1683 }
1684
1685 public void exit() {
1686 if (mFrequencyConflictDialog != null) mFrequencyConflictDialog.dismiss();
1687 }
1688 }
Irfan Sheriff618455f2011-11-18 14:33:09 -08001689
repo sync55bc5f32011-06-24 14:23:07 -07001690 class GroupCreatedState extends State {
1691 @Override
1692 public void enter() {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07001693 if (DBG) logd(getName());
Irfan Sherifff1180432012-12-13 12:33:42 -08001694 // Once connected, peer config details are invalid
1695 mSavedPeerConfig.invalidate();
repo syncaea743a2011-07-29 23:55:49 -07001696 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
Irfan Sheriff859e7de2011-08-25 13:58:25 -07001697
Irfan Sheriff651cdfc2011-09-07 00:31:20 -07001698 updateThisDevice(WifiP2pDevice.CONNECTED);
1699
Irfan Sheriff859e7de2011-08-25 13:58:25 -07001700 //DHCP server has already been started if I am a group owner
1701 if (mGroup.isGroupOwner()) {
Robert Greenwalt4717c262012-10-31 14:32:53 -07001702 setWifiP2pInfoOnGroupFormation(NetworkUtils.numericToInetAddress(SERVER_ADDRESS));
Irfan Sheriff859e7de2011-08-25 13:58:25 -07001703 }
Irfan Sheriff61e42262012-10-19 12:03:47 -07001704
1705 // In case of a negotiation group, connection changed is sent
1706 // after a client joins. For autonomous, send now
1707 if (mAutonomousGroup) {
1708 sendP2pConnectionChangedBroadcast();
1709 }
repo sync55bc5f32011-06-24 14:23:07 -07001710 }
1711
1712 @Override
1713 public boolean processMessage(Message message) {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07001714 if (DBG) logd(getName() + message.toString());
repo sync55bc5f32011-06-24 14:23:07 -07001715 switch (message.what) {
1716 case WifiMonitor.AP_STA_CONNECTED_EVENT:
Irfan Sheriffbfed2d62011-12-09 12:40:04 -08001717 WifiP2pDevice device = (WifiP2pDevice) message.obj;
1718 String deviceAddress = device.deviceAddress;
Robert Greenwaltc77e2d72013-05-10 15:26:30 -07001719 // Clear timeout that was set when group was started.
1720 mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0);
Irfan Sheriff93226872011-08-29 10:36:05 -07001721 if (deviceAddress != null) {
Irfan Sheriff61e42262012-10-19 12:03:47 -07001722 if (mPeers.get(deviceAddress) != null) {
1723 mGroup.addClient(mPeers.get(deviceAddress));
1724 } else {
1725 mGroup.addClient(deviceAddress);
1726 }
Yoshihiko Ikenagabfb27bb2012-02-14 11:28:35 +09001727 mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED);
Irfan Sheriff93226872011-08-29 10:36:05 -07001728 if (DBG) logd(getName() + " ap sta connected");
Irfan Sheriff3a67e252012-12-07 15:51:34 -08001729 sendPeersChangedBroadcast();
Irfan Sheriff93226872011-08-29 10:36:05 -07001730 } else {
Irfan Sheriffbfed2d62011-12-09 12:40:04 -08001731 loge("Connect on null device address, ignore");
Irfan Sheriff93226872011-08-29 10:36:05 -07001732 }
Irfan Sheriffe0c28d52012-09-18 12:05:31 -07001733 sendP2pConnectionChangedBroadcast();
repo sync55bc5f32011-06-24 14:23:07 -07001734 break;
1735 case WifiMonitor.AP_STA_DISCONNECTED_EVENT:
Yoshihiko Ikenaga61472a82012-03-23 13:48:11 +09001736 device = (WifiP2pDevice) message.obj;
1737 deviceAddress = device.deviceAddress;
Irfan Sheriff93226872011-08-29 10:36:05 -07001738 if (deviceAddress != null) {
Yoshihiko Ikenagabfb27bb2012-02-14 11:28:35 +09001739 mPeers.updateStatus(deviceAddress, WifiP2pDevice.AVAILABLE);
Irfan Sheriff93226872011-08-29 10:36:05 -07001740 if (mGroup.removeClient(deviceAddress)) {
1741 if (DBG) logd("Removed client " + deviceAddress);
Yoshihiko Ikenagabfb27bb2012-02-14 11:28:35 +09001742 if (!mAutonomousGroup && mGroup.isClientListEmpty()) {
Irfan Sherifff1180432012-12-13 12:33:42 -08001743 logd("Client list empty, remove non-persistent p2p group");
Irfan Sherifffc7f95a2012-01-04 14:50:09 -08001744 mWifiNative.p2pGroupRemove(mGroup.getInterface());
Irfan Sheriff5ef9c592012-09-18 12:39:22 -07001745 // We end up sending connection changed broadcast
1746 // when this happens at exit()
1747 } else {
1748 // Notify when a client disconnects from group
1749 sendP2pConnectionChangedBroadcast();
Irfan Sheriff4be4d312011-09-03 11:03:23 -07001750 }
Irfan Sheriff93226872011-08-29 10:36:05 -07001751 } else {
1752 if (DBG) logd("Failed to remove client " + deviceAddress);
1753 for (WifiP2pDevice c : mGroup.getClientList()) {
1754 if (DBG) logd("client " + c.deviceAddress);
1755 }
repo sync55bc5f32011-06-24 14:23:07 -07001756 }
Irfan Sheriff3a67e252012-12-07 15:51:34 -08001757 sendPeersChangedBroadcast();
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001758 if (DBG) logd(getName() + " ap sta disconnected");
Irfan Sheriff93226872011-08-29 10:36:05 -07001759 } else {
Yoshihiko Ikenaga61472a82012-03-23 13:48:11 +09001760 loge("Disconnect on unknown device: " + device);
repo sync55bc5f32011-06-24 14:23:07 -07001761 }
repo sync55bc5f32011-06-24 14:23:07 -07001762 break;
repo syncaea743a2011-07-29 23:55:49 -07001763 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
Robert Greenwalt4717c262012-10-31 14:32:53 -07001764 DhcpResults dhcpResults = (DhcpResults) message.obj;
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07001765 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS &&
Robert Greenwalt4717c262012-10-31 14:32:53 -07001766 dhcpResults != null) {
1767 if (DBG) logd("DhcpResults: " + dhcpResults);
1768 setWifiP2pInfoOnGroupFormation(dhcpResults.serverAddress);
repo syncaea743a2011-07-29 23:55:49 -07001769 sendP2pConnectionChangedBroadcast();
Irfan Sheriff55bfa422012-04-06 15:25:41 -07001770 //Turn on power save on client
1771 mWifiNative.setP2pPowerSave(mGroup.getInterface(), true);
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07001772 } else {
Yoshihiko Ikenaga61472a82012-03-23 13:48:11 +09001773 loge("DHCP failed");
Irfan Sherifffc7f95a2012-01-04 14:50:09 -08001774 mWifiNative.p2pGroupRemove(mGroup.getInterface());
repo syncaea743a2011-07-29 23:55:49 -07001775 }
1776 break;
repo sync55bc5f32011-06-24 14:23:07 -07001777 case WifiP2pManager.REMOVE_GROUP:
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001778 if (DBG) logd(getName() + " remove group");
Irfan Sherifffc7f95a2012-01-04 14:50:09 -08001779 if (mWifiNative.p2pGroupRemove(mGroup.getInterface())) {
Irfan Sheriffc41096e2012-09-24 14:21:54 -07001780 transitionTo(mOngoingGroupRemovalState);
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07001781 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED);
1782 } else {
Irfan Sheriffd36adc32012-09-23 15:27:50 -07001783 handleGroupRemoved();
1784 transitionTo(mInactiveState);
Irfan Sheriff4be4d312011-09-03 11:03:23 -07001785 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
1786 WifiP2pManager.ERROR);
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07001787 }
repo sync55bc5f32011-06-24 14:23:07 -07001788 break;
Irfan Sheriff2bc0c5f2012-10-24 13:34:31 -07001789 /* We do not listen to NETWORK_DISCONNECTION_EVENT for group removal
1790 * handling since supplicant actually tries to reconnect after a temporary
1791 * disconnect until group idle time out. Eventually, a group removal event
1792 * will come when group has been removed.
1793 *
1794 * When there are connectivity issues during temporary disconnect, the application
1795 * will also just remove the group.
1796 *
1797 * Treating network disconnection as group removal causes race conditions since
1798 * supplicant would still maintain the group at that stage.
1799 */
repo sync55bc5f32011-06-24 14:23:07 -07001800 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001801 if (DBG) logd(getName() + " group removed");
Irfan Sheriffd36adc32012-09-23 15:27:50 -07001802 handleGroupRemoved();
repo sync55bc5f32011-06-24 14:23:07 -07001803 transitionTo(mInactiveState);
1804 break;
1805 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
Irfan Sheriffbfed2d62011-12-09 12:40:04 -08001806 device = (WifiP2pDevice) message.obj;
Irfan Sheriff530040e2011-11-30 17:20:47 -08001807 //Device loss for a connected device indicates it is not in discovery any more
1808 if (mGroup.contains(device)) {
Irfan Sheriff41de2402012-10-12 15:52:13 -07001809 if (DBG) logd("Add device to lost list " + device);
Irfan Sheriff3a67e252012-12-07 15:51:34 -08001810 mPeersLostDuringConnection.updateSupplicantDetails(device);
Irfan Sheriff530040e2011-11-30 17:20:47 -08001811 return HANDLED;
repo sync55bc5f32011-06-24 14:23:07 -07001812 }
Irfan Sheriff530040e2011-11-30 17:20:47 -08001813 // Do the regular device lost handling
1814 return NOT_HANDLED;
Irfan Sheriff62fa6de2012-10-18 12:39:22 -07001815 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
repo sync55bc5f32011-06-24 14:23:07 -07001816 sendMessage(WifiP2pManager.REMOVE_GROUP);
1817 deferMessage(message);
1818 break;
Irfan Sheriffef96a432012-12-05 16:36:20 -08001819 // This allows any client to join the GO during the
1820 // WPS window
Irfan Sherifff1180432012-12-13 12:33:42 -08001821 case WifiP2pManager.START_WPS:
1822 WpsInfo wps = (WpsInfo) message.obj;
1823 if (wps == null) {
1824 replyToMessage(message, WifiP2pManager.START_WPS_FAILED);
1825 break;
1826 }
1827 boolean ret = true;
1828 if (wps.setup == WpsInfo.PBC) {
1829 ret = mWifiNative.startWpsPbc(mGroup.getInterface(), null);
1830 } else {
1831 if (wps.pin == null) {
1832 String pin = mWifiNative.startWpsPinDisplay(mGroup.getInterface());
1833 try {
1834 Integer.parseInt(pin);
1835 notifyInvitationSent(pin, "any");
1836 } catch (NumberFormatException ignore) {
1837 ret = false;
1838 }
1839 } else {
1840 ret = mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
1841 wps.pin);
1842 }
1843 }
1844 replyToMessage(message, ret ? WifiP2pManager.START_WPS_SUCCEEDED :
1845 WifiP2pManager.START_WPS_FAILED);
1846 break;
1847 case WifiP2pManager.CONNECT:
1848 WifiP2pConfig config = (WifiP2pConfig) message.obj;
1849 if (isConfigInvalid(config)) {
1850 loge("Dropping connect requeset " + config);
1851 replyToMessage(message, WifiP2pManager.CONNECT_FAILED);
1852 break;
1853 }
1854 logd("Inviting device : " + config.deviceAddress);
1855 mSavedPeerConfig = config;
1856 if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) {
1857 mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED);
1858 sendPeersChangedBroadcast();
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07001859 replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
1860 } else {
Irfan Sherifff1180432012-12-13 12:33:42 -08001861 replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
1862 WifiP2pManager.ERROR);
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07001863 }
repo sync55bc5f32011-06-24 14:23:07 -07001864 // TODO: figure out updating the status to declined when invitation is rejected
1865 break;
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001866 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
1867 P2pStatus status = (P2pStatus)message.obj;
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001868 if (status == P2pStatus.SUCCESS) {
1869 // invocation was succeeded.
1870 break;
Irfan Sherifff1180432012-12-13 12:33:42 -08001871 }
1872 loge("Invitation result " + status);
1873 if (status == P2pStatus.UNKNOWN_P2P_GROUP) {
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001874 // target device has already removed the credential.
1875 // So, remove this credential accordingly.
1876 int netId = mGroup.getNetworkId();
1877 if (netId >= 0) {
1878 if (DBG) logd("Remove unknown client from the list");
1879 if (!removeClientFromList(netId,
1880 mSavedPeerConfig.deviceAddress, false)) {
1881 // not found the client on the list
Irfan Sherifff1180432012-12-13 12:33:42 -08001882 loge("Already removed the client, ignore");
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09001883 break;
1884 }
1885 // try invitation.
1886 sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
1887 }
1888 }
1889 break;
repo sync55bc5f32011-06-24 14:23:07 -07001890 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
repo sync55bc5f32011-06-24 14:23:07 -07001891 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
Irfan Sheriff618455f2011-11-18 14:33:09 -08001892 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
1893 WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj;
1894 mSavedPeerConfig = new WifiP2pConfig();
1895 mSavedPeerConfig.deviceAddress = provDisc.device.deviceAddress;
1896 if (message.what == WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) {
1897 mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD;
1898 } else if (message.what == WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT) {
1899 mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;
1900 mSavedPeerConfig.wps.pin = provDisc.pin;
1901 } else {
1902 mSavedPeerConfig.wps.setup = WpsInfo.PBC;
1903 }
Irfan Sheriffef96a432012-12-05 16:36:20 -08001904 transitionTo(mUserAuthorizingJoinState);
repo sync55bc5f32011-06-24 14:23:07 -07001905 break;
Irfan Sheriff93226872011-08-29 10:36:05 -07001906 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
Irfan Sherifff1180432012-12-13 12:33:42 -08001907 loge("Duplicate group creation event notice, ignore");
Irfan Sheriff93226872011-08-29 10:36:05 -07001908 break;
repo sync55bc5f32011-06-24 14:23:07 -07001909 default:
1910 return NOT_HANDLED;
1911 }
1912 return HANDLED;
1913 }
repo syncaea743a2011-07-29 23:55:49 -07001914
1915 public void exit() {
Irfan Sheriff651cdfc2011-09-07 00:31:20 -07001916 updateThisDevice(WifiP2pDevice.AVAILABLE);
Irfan Sheriff0a667632012-09-06 14:19:30 -07001917 resetWifiP2pInfo();
repo syncaea743a2011-07-29 23:55:49 -07001918 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07001919 sendP2pConnectionChangedBroadcast();
repo syncaea743a2011-07-29 23:55:49 -07001920 }
repo sync55bc5f32011-06-24 14:23:07 -07001921 }
1922
Irfan Sheriff618455f2011-11-18 14:33:09 -08001923 class UserAuthorizingJoinState extends State {
1924 @Override
1925 public void enter() {
1926 if (DBG) logd(getName());
1927 notifyInvitationReceived();
1928 }
1929
1930 @Override
1931 public boolean processMessage(Message message) {
1932 if (DBG) logd(getName() + message.toString());
1933 switch (message.what) {
1934 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
1935 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
1936 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
1937 //Ignore more client requests
1938 break;
1939 case PEER_CONNECTION_USER_ACCEPT:
Deepthi Gowri575bb452013-02-23 00:02:00 +05301940 //Stop discovery to avoid failure due to channel switch
1941 mWifiNative.p2pStopFind();
Irfan Sheriff618455f2011-11-18 14:33:09 -08001942 if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
Yoshihiko Ikenagabfb27bb2012-02-14 11:28:35 +09001943 mWifiNative.startWpsPbc(mGroup.getInterface(), null);
Irfan Sheriff618455f2011-11-18 14:33:09 -08001944 } else {
Yoshihiko Ikenagabfb27bb2012-02-14 11:28:35 +09001945 mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
1946 mSavedPeerConfig.wps.pin);
Irfan Sheriff618455f2011-11-18 14:33:09 -08001947 }
Irfan Sheriff618455f2011-11-18 14:33:09 -08001948 transitionTo(mGroupCreatedState);
1949 break;
1950 case PEER_CONNECTION_USER_REJECT:
1951 if (DBG) logd("User rejected incoming request");
Irfan Sheriff618455f2011-11-18 14:33:09 -08001952 transitionTo(mGroupCreatedState);
1953 break;
1954 default:
1955 return NOT_HANDLED;
1956 }
1957 return HANDLED;
1958 }
1959
1960 @Override
1961 public void exit() {
1962 //TODO: dismiss dialog if not already done
1963 }
1964 }
1965
Irfan Sheriffc41096e2012-09-24 14:21:54 -07001966 class OngoingGroupRemovalState extends State {
1967 @Override
1968 public void enter() {
1969 if (DBG) logd(getName());
1970 }
1971
1972 @Override
1973 public boolean processMessage(Message message) {
1974 if (DBG) logd(getName() + message.toString());
1975 switch (message.what) {
1976 // Group removal ongoing. Multiple calls
1977 // end up removing persisted network. Do nothing.
1978 case WifiP2pManager.REMOVE_GROUP:
1979 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED);
1980 break;
1981 // Parent state will transition out of this state
1982 // when removal is complete
1983 default:
1984 return NOT_HANDLED;
1985 }
1986 return HANDLED;
1987 }
1988 }
1989
Irfan Sherifff0afe412012-11-30 14:07:44 -08001990 @Override
1991 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1992 super.dump(fd, pw, args);
1993 pw.println("mWifiP2pInfo " + mWifiP2pInfo);
1994 pw.println("mGroup " + mGroup);
1995 pw.println("mSavedPeerConfig " + mSavedPeerConfig);
1996 pw.println("mSavedP2pGroup " + mSavedP2pGroup);
Irfan Sherifff0afe412012-11-30 14:07:44 -08001997 pw.println();
1998 }
1999
repo sync55bc5f32011-06-24 14:23:07 -07002000 private void sendP2pStateChangedBroadcast(boolean enabled) {
2001 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
2002 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2003 if (enabled) {
2004 intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE,
2005 WifiP2pManager.WIFI_P2P_STATE_ENABLED);
2006 } else {
2007 intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE,
2008 WifiP2pManager.WIFI_P2P_STATE_DISABLED);
2009 }
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002010 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
repo sync55bc5f32011-06-24 14:23:07 -07002011 }
2012
Irfan Sheriffc111d1c2012-03-28 15:59:30 -07002013 private void sendP2pDiscoveryChangedBroadcast(boolean started) {
2014 if (mDiscoveryStarted == started) return;
2015 mDiscoveryStarted = started;
2016
2017 if (DBG) logd("discovery change broadcast " + started);
2018
2019 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);
2020 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2021 intent.putExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE, started ?
2022 WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED :
2023 WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002024 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Irfan Sheriffc111d1c2012-03-28 15:59:30 -07002025 }
2026
Irfan Sheriff651cdfc2011-09-07 00:31:20 -07002027 private void sendThisDeviceChangedBroadcast() {
2028 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
2029 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2030 intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE, new WifiP2pDevice(mThisDevice));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002031 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Irfan Sheriff651cdfc2011-09-07 00:31:20 -07002032 }
2033
Irfan Sheriff3a67e252012-12-07 15:51:34 -08002034 private void sendPeersChangedBroadcast() {
repo sync55bc5f32011-06-24 14:23:07 -07002035 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
Irfan Sheriffab3b9fb2013-02-27 11:06:45 -08002036 intent.putExtra(WifiP2pManager.EXTRA_P2P_DEVICE_LIST, new WifiP2pDeviceList(mPeers));
repo sync55bc5f32011-06-24 14:23:07 -07002037 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002038 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
repo sync55bc5f32011-06-24 14:23:07 -07002039 }
2040
repo syncaea743a2011-07-29 23:55:49 -07002041 private void sendP2pConnectionChangedBroadcast() {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002042 if (DBG) logd("sending p2p connection changed broadcast");
repo syncaea743a2011-07-29 23:55:49 -07002043 Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
2044 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
2045 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002046 intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, new WifiP2pInfo(mWifiP2pInfo));
repo syncaea743a2011-07-29 23:55:49 -07002047 intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
Irfan Sheriff3a67e252012-12-07 15:51:34 -08002048 intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, new WifiP2pGroup(mGroup));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002049 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Irfan Sheriff3809f502012-09-17 16:04:57 -07002050 mWifiChannel.sendMessage(WifiP2pService.P2P_CONNECTION_CHANGED,
2051 new NetworkInfo(mNetworkInfo));
repo syncaea743a2011-07-29 23:55:49 -07002052 }
2053
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002054 private void sendP2pPersistentGroupsChangedBroadcast() {
2055 if (DBG) logd("sending p2p persistent groups changed broadcast");
2056 Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION);
2057 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002058 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002059 }
2060
repo syncaea743a2011-07-29 23:55:49 -07002061 private void startDhcpServer(String intf) {
repo syncaea743a2011-07-29 23:55:49 -07002062 InterfaceConfiguration ifcg = null;
2063 try {
2064 ifcg = mNwService.getInterfaceConfig(intf);
Jeff Sharkeyddba1062011-11-29 18:37:04 -08002065 ifcg.setLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress(
2066 SERVER_ADDRESS), 24));
2067 ifcg.setInterfaceUp();
repo syncaea743a2011-07-29 23:55:49 -07002068 mNwService.setInterfaceConfig(intf, ifcg);
2069 /* This starts the dnsmasq server */
Irfan Sheriff859e7de2011-08-25 13:58:25 -07002070 mNwService.startTethering(DHCP_RANGE);
repo syncaea743a2011-07-29 23:55:49 -07002071 } catch (Exception e) {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002072 loge("Error configuring interface " + intf + ", :" + e);
repo syncaea743a2011-07-29 23:55:49 -07002073 return;
2074 }
2075
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002076 logd("Started Dhcp server on " + intf);
Irfan Sheriff859e7de2011-08-25 13:58:25 -07002077 }
repo syncaea743a2011-07-29 23:55:49 -07002078
Irfan Sheriffb81bb9b2012-06-07 16:44:57 -07002079 private void stopDhcpServer(String intf) {
repo syncaea743a2011-07-29 23:55:49 -07002080 try {
2081 mNwService.stopTethering();
2082 } catch (Exception e) {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002083 loge("Error stopping Dhcp server" + e);
repo syncaea743a2011-07-29 23:55:49 -07002084 return;
2085 }
2086
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002087 logd("Stopped Dhcp server");
repo syncaea743a2011-07-29 23:55:49 -07002088 }
2089
repo sync55bc5f32011-06-24 14:23:07 -07002090 private void notifyP2pEnableFailure() {
2091 Resources r = Resources.getSystem();
2092 AlertDialog dialog = new AlertDialog.Builder(mContext)
2093 .setTitle(r.getString(R.string.wifi_p2p_dialog_title))
2094 .setMessage(r.getString(R.string.wifi_p2p_failed_message))
2095 .setPositiveButton(r.getString(R.string.ok), null)
2096 .create();
2097 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
2098 dialog.show();
2099 }
2100
Irfan Sheriff618455f2011-11-18 14:33:09 -08002101 private void addRowToDialog(ViewGroup group, int stringId, String value) {
repo sync55bc5f32011-06-24 14:23:07 -07002102 Resources r = Resources.getSystem();
Irfan Sheriff618455f2011-11-18 14:33:09 -08002103 View row = LayoutInflater.from(mContext).inflate(R.layout.wifi_p2p_dialog_row,
2104 group, false);
2105 ((TextView) row.findViewById(R.id.name)).setText(r.getString(stringId));
2106 ((TextView) row.findViewById(R.id.value)).setText(value);
2107 group.addView(row);
2108 }
2109
2110 private void notifyInvitationSent(String pin, String peerAddress) {
2111 Resources r = Resources.getSystem();
2112
2113 final View textEntryView = LayoutInflater.from(mContext)
2114 .inflate(R.layout.wifi_p2p_dialog, null);
2115
2116 ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info);
2117 addRowToDialog(group, R.string.wifi_p2p_to_message, getDeviceName(peerAddress));
2118 addRowToDialog(group, R.string.wifi_p2p_show_pin_message, pin);
2119
repo sync55bc5f32011-06-24 14:23:07 -07002120 AlertDialog dialog = new AlertDialog.Builder(mContext)
Irfan Sheriff618455f2011-11-18 14:33:09 -08002121 .setTitle(r.getString(R.string.wifi_p2p_invitation_sent_title))
2122 .setView(textEntryView)
repo sync55bc5f32011-06-24 14:23:07 -07002123 .setPositiveButton(r.getString(R.string.ok), null)
2124 .create();
2125 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
2126 dialog.show();
2127 }
2128
Irfan Sheriff618455f2011-11-18 14:33:09 -08002129 private void notifyInvitationReceived() {
repo sync55bc5f32011-06-24 14:23:07 -07002130 Resources r = Resources.getSystem();
Irfan Sheriff618455f2011-11-18 14:33:09 -08002131 final WpsInfo wps = mSavedPeerConfig.wps;
repo sync55bc5f32011-06-24 14:23:07 -07002132 final View textEntryView = LayoutInflater.from(mContext)
Irfan Sheriff618455f2011-11-18 14:33:09 -08002133 .inflate(R.layout.wifi_p2p_dialog, null);
2134
2135 ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info);
2136 addRowToDialog(group, R.string.wifi_p2p_from_message, getDeviceName(
2137 mSavedPeerConfig.deviceAddress));
2138
2139 final EditText pin = (EditText) textEntryView.findViewById(R.id.wifi_p2p_wps_pin);
repo sync55bc5f32011-06-24 14:23:07 -07002140
2141 AlertDialog dialog = new AlertDialog.Builder(mContext)
Irfan Sheriff618455f2011-11-18 14:33:09 -08002142 .setTitle(r.getString(R.string.wifi_p2p_invitation_to_connect_title))
repo sync55bc5f32011-06-24 14:23:07 -07002143 .setView(textEntryView)
Irfan Sheriff618455f2011-11-18 14:33:09 -08002144 .setPositiveButton(r.getString(R.string.accept), new OnClickListener() {
repo sync55bc5f32011-06-24 14:23:07 -07002145 public void onClick(DialogInterface dialog, int which) {
Irfan Sheriff618455f2011-11-18 14:33:09 -08002146 if (wps.setup == WpsInfo.KEYPAD) {
2147 mSavedPeerConfig.wps.pin = pin.getText().toString();
repo syncaea743a2011-07-29 23:55:49 -07002148 }
Irfan Sheriff618455f2011-11-18 14:33:09 -08002149 if (DBG) logd(getName() + " accept invitation " + mSavedPeerConfig);
2150 sendMessage(PEER_CONNECTION_USER_ACCEPT);
repo sync55bc5f32011-06-24 14:23:07 -07002151 }
2152 })
Irfan Sheriff618455f2011-11-18 14:33:09 -08002153 .setNegativeButton(r.getString(R.string.decline), new OnClickListener() {
repo sync55bc5f32011-06-24 14:23:07 -07002154 @Override
2155 public void onClick(DialogInterface dialog, int which) {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002156 if (DBG) logd(getName() + " ignore connect");
Irfan Sheriff618455f2011-11-18 14:33:09 -08002157 sendMessage(PEER_CONNECTION_USER_REJECT);
repo sync55bc5f32011-06-24 14:23:07 -07002158 }
2159 })
Irfan Sheriff10ca8702012-05-10 16:52:49 -07002160 .setOnCancelListener(new DialogInterface.OnCancelListener() {
2161 @Override
2162 public void onCancel(DialogInterface arg0) {
2163 if (DBG) logd(getName() + " ignore connect");
2164 sendMessage(PEER_CONNECTION_USER_REJECT);
2165 }
2166 })
repo sync55bc5f32011-06-24 14:23:07 -07002167 .create();
2168
Irfan Sheriff618455f2011-11-18 14:33:09 -08002169 //make the enter pin area or the display pin area visible
2170 switch (wps.setup) {
2171 case WpsInfo.KEYPAD:
2172 if (DBG) logd("Enter pin section visible");
2173 textEntryView.findViewById(R.id.enter_pin_section).setVisibility(View.VISIBLE);
2174 break;
2175 case WpsInfo.DISPLAY:
2176 if (DBG) logd("Shown pin section visible");
2177 addRowToDialog(group, R.string.wifi_p2p_show_pin_message, wps.pin);
2178 break;
2179 default:
2180 break;
repo sync55bc5f32011-06-24 14:23:07 -07002181 }
2182
Justin Koh8f38f3c2012-10-17 11:33:15 -07002183 if ((r.getConfiguration().uiMode & Configuration.UI_MODE_TYPE_APPLIANCE) ==
2184 Configuration.UI_MODE_TYPE_APPLIANCE) {
2185 // For appliance devices, add a key listener which accepts.
2186 dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
2187
2188 @Override
2189 public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
2190 // TODO: make the actual key come from a config value.
2191 if (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
2192 sendMessage(PEER_CONNECTION_USER_ACCEPT);
2193 dialog.dismiss();
2194 return true;
2195 }
2196 return false;
2197 }
2198 });
2199 // TODO: add timeout for this dialog.
2200 // TODO: update UI in appliance mode to tell user what to do.
2201 }
2202
repo sync55bc5f32011-06-24 14:23:07 -07002203 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
2204 dialog.show();
2205 }
2206
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002207 /**
2208 * Synchronize the persistent group list between
2209 * wpa_supplicant and mGroups.
2210 */
Irfan Sheriffca1269f2012-09-27 17:01:41 -07002211 private void updatePersistentNetworks(boolean reload) {
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002212 String listStr = mWifiNative.listNetworks();
Irfan Sheriffd36adc32012-09-23 15:27:50 -07002213 if (listStr == null) return;
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002214
2215 boolean isSaveRequired = false;
2216 String[] lines = listStr.split("\n");
Irfan Sheriffd36adc32012-09-23 15:27:50 -07002217 if (lines == null) return;
2218
Irfan Sheriffca1269f2012-09-27 17:01:41 -07002219 if (reload) mGroups.clear();
2220
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002221 // Skip the first line, which is a header
2222 for (int i = 1; i < lines.length; i++) {
2223 String[] result = lines[i].split("\t");
2224 if (result == null || result.length < 4) {
2225 continue;
2226 }
2227 // network-id | ssid | bssid | flags
2228 int netId = -1;
2229 String ssid = result[1];
2230 String bssid = result[2];
2231 String flags = result[3];
2232 try {
2233 netId = Integer.parseInt(result[0]);
2234 } catch(NumberFormatException e) {
2235 e.printStackTrace();
2236 continue;
2237 }
2238
2239 if (flags.indexOf("[CURRENT]") != -1) {
2240 continue;
2241 }
2242 if (flags.indexOf("[P2P-PERSISTENT]") == -1) {
2243 /*
2244 * The unused profile is sometimes remained when the p2p group formation is failed.
2245 * So, we clean up the p2p group here.
2246 */
2247 if (DBG) logd("clean up the unused persistent group. netId=" + netId);
2248 mWifiNative.removeNetwork(netId);
2249 isSaveRequired = true;
2250 continue;
2251 }
2252
2253 if (mGroups.contains(netId)) {
2254 continue;
2255 }
2256
2257 WifiP2pGroup group = new WifiP2pGroup();
2258 group.setNetworkId(netId);
2259 group.setNetworkName(ssid);
2260 String mode = mWifiNative.getNetworkVariable(netId, "mode");
2261 if (mode != null && mode.equals("3")) {
2262 group.setIsGroupOwner(true);
2263 }
2264 if (bssid.equalsIgnoreCase(mThisDevice.deviceAddress)) {
2265 group.setOwner(mThisDevice);
2266 } else {
2267 WifiP2pDevice device = new WifiP2pDevice();
2268 device.deviceAddress = bssid;
2269 group.setOwner(device);
2270 }
2271 mGroups.add(group);
2272 isSaveRequired = true;
2273 }
2274
Irfan Sheriffca1269f2012-09-27 17:01:41 -07002275 if (reload || isSaveRequired) {
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002276 mWifiNative.saveConfig();
Irfan Sheriffca1269f2012-09-27 17:01:41 -07002277 sendP2pPersistentGroupsChangedBroadcast();
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002278 }
2279 }
2280
2281 /**
Irfan Sherifff1180432012-12-13 12:33:42 -08002282 * A config is valid if it has a peer address that has already been
2283 * discovered
2284 * @return true if it is invalid, false otherwise
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002285 */
Irfan Sherifff1180432012-12-13 12:33:42 -08002286 private boolean isConfigInvalid(WifiP2pConfig config) {
2287 if (config == null) return true;
2288 if (TextUtils.isEmpty(config.deviceAddress)) return true;
2289 if (mPeers.get(config.deviceAddress) == null) return true;
2290 return false;
2291 }
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002292
Irfan Sherifff1180432012-12-13 12:33:42 -08002293 /* TODO: The supplicant does not provide group capability changes as an event.
2294 * Having it pushed as an event would avoid polling for this information right
2295 * before a connection
2296 */
2297 private WifiP2pDevice fetchCurrentDeviceDetails(WifiP2pConfig config) {
2298 /* Fetch & update group capability from supplicant on the device */
2299 int gc = mWifiNative.getGroupCapability(config.deviceAddress);
2300 mPeers.updateGroupCapability(config.deviceAddress, gc);
2301 return mPeers.get(config.deviceAddress);
2302 }
2303
2304 /**
2305 * Start a p2p group negotiation and display pin if necessary
2306 * @param config for the peer
2307 */
2308 private void p2pConnectWithPinDisplay(WifiP2pConfig config) {
2309 WifiP2pDevice dev = fetchCurrentDeviceDetails(config);
2310
2311 String pin = mWifiNative.p2pConnect(config, dev.isGroupOwner());
2312 try {
2313 Integer.parseInt(pin);
2314 notifyInvitationSent(pin, config.deviceAddress);
2315 } catch (NumberFormatException ignore) {
2316 // do nothing if p2pConnect did not return a pin
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002317 }
Irfan Sherifff1180432012-12-13 12:33:42 -08002318 }
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002319
Irfan Sherifff1180432012-12-13 12:33:42 -08002320 /**
2321 * Reinvoke a persistent group.
2322 *
2323 * @param config for the peer
2324 * @return true on success, false on failure
2325 */
2326 private boolean reinvokePersistentGroup(WifiP2pConfig config) {
2327 WifiP2pDevice dev = fetchCurrentDeviceDetails(config);
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002328
2329 boolean join = dev.isGroupOwner();
2330 String ssid = mWifiNative.p2pGetSsid(dev.deviceAddress);
2331 if (DBG) logd("target ssid is " + ssid + " join:" + join);
2332
2333 if (join && dev.isGroupLimit()) {
2334 if (DBG) logd("target device reaches group limit.");
2335
2336 // if the target group has reached the limit,
2337 // try group formation.
2338 join = false;
2339 } else if (join) {
2340 int netId = mGroups.getNetworkId(dev.deviceAddress, ssid);
2341 if (netId >= 0) {
2342 // Skip WPS and start 4way handshake immediately.
2343 if (!mWifiNative.p2pGroupAdd(netId)) {
Irfan Sherifff1180432012-12-13 12:33:42 -08002344 return false;
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002345 }
Irfan Sherifff1180432012-12-13 12:33:42 -08002346 return true;
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002347 }
2348 }
2349
2350 if (!join && dev.isDeviceLimit()) {
2351 loge("target device reaches the device limit.");
Irfan Sherifff1180432012-12-13 12:33:42 -08002352 return false;
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002353 }
2354
Irfan Sherifff1180432012-12-13 12:33:42 -08002355 if (!join && dev.isInvitationCapable()) {
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002356 int netId = WifiP2pGroup.PERSISTENT_NET_ID;
2357 if (config.netId >= 0) {
2358 if (config.deviceAddress.equals(mGroups.getOwnerAddr(config.netId))) {
2359 netId = config.netId;
2360 }
2361 } else {
2362 netId = mGroups.getNetworkId(dev.deviceAddress);
2363 }
2364 if (netId < 0) {
2365 netId = getNetworkIdFromClientList(dev.deviceAddress);
2366 }
2367 if (DBG) logd("netId related with " + dev.deviceAddress + " = " + netId);
2368 if (netId >= 0) {
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002369 // Invoke the persistent group.
Irfan Sheriffc41096e2012-09-24 14:21:54 -07002370 if (mWifiNative.p2pReinvoke(netId, dev.deviceAddress)) {
2371 // Save network id. It'll be used when an invitation result event is received.
Irfan Sherifff1180432012-12-13 12:33:42 -08002372 config.netId = netId;
2373 return true;
Irfan Sheriffc41096e2012-09-24 14:21:54 -07002374 } else {
2375 loge("p2pReinvoke() failed, update networks");
Irfan Sheriffca1269f2012-09-27 17:01:41 -07002376 updatePersistentNetworks(RELOAD);
Irfan Sherifff1180432012-12-13 12:33:42 -08002377 return false;
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002378 }
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002379 }
2380 }
2381
Irfan Sherifff1180432012-12-13 12:33:42 -08002382 return false;
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002383 }
2384
2385 /**
2386 * Return the network id of the group owner profile which has the p2p client with
2387 * the specified device address in it's client list.
2388 * If more than one persistent group of the same address is present in its client
2389 * lists, return the first one.
2390 *
2391 * @param deviceAddress p2p device address.
2392 * @return the network id. if not found, return -1.
2393 */
2394 private int getNetworkIdFromClientList(String deviceAddress) {
2395 if (deviceAddress == null) return -1;
2396
2397 Collection<WifiP2pGroup> groups = mGroups.getGroupList();
2398 for (WifiP2pGroup group : groups) {
2399 int netId = group.getNetworkId();
2400 String[] p2pClientList = getClientList(netId);
2401 if (p2pClientList == null) continue;
2402 for (String client : p2pClientList) {
2403 if (deviceAddress.equalsIgnoreCase(client)) {
2404 return netId;
2405 }
2406 }
2407 }
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002408 return -1;
2409 }
2410
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002411 /**
2412 * Return p2p client list associated with the specified network id.
2413 * @param netId network id.
2414 * @return p2p client list. if not found, return null.
2415 */
2416 private String[] getClientList(int netId) {
2417 String p2pClients = mWifiNative.getNetworkVariable(netId, "p2p_client_list");
2418 if (p2pClients == null) {
2419 return null;
2420 }
2421 return p2pClients.split(" ");
2422 }
2423
2424 /**
2425 * Remove the specified p2p client from the specified profile.
2426 * @param netId network id of the profile.
2427 * @param addr p2p client address to be removed.
2428 * @param isRemovable if true, remove the specified profile if its client list becomes empty.
2429 * @return whether removing the specified p2p client is successful or not.
2430 */
2431 private boolean removeClientFromList(int netId, String addr, boolean isRemovable) {
2432 StringBuilder modifiedClientList = new StringBuilder();
2433 String[] currentClientList = getClientList(netId);
2434 boolean isClientRemoved = false;
2435 if (currentClientList != null) {
2436 for (String client : currentClientList) {
2437 if (!client.equalsIgnoreCase(addr)) {
2438 modifiedClientList.append(" ");
2439 modifiedClientList.append(client);
2440 } else {
2441 isClientRemoved = true;
2442 }
2443 }
2444 }
2445 if (modifiedClientList.length() == 0 && isRemovable) {
2446 // the client list is empty. so remove it.
2447 if (DBG) logd("Remove unknown network");
2448 mGroups.remove(netId);
2449 return true;
2450 }
2451
2452 if (!isClientRemoved) {
2453 // specified p2p client is not found. already removed.
2454 return false;
2455 }
2456
2457 if (DBG) logd("Modified client list: " + modifiedClientList);
2458 if (modifiedClientList.length() == 0) {
2459 modifiedClientList.append("\"\"");
2460 }
2461 mWifiNative.setNetworkVariable(netId,
2462 "p2p_client_list", modifiedClientList.toString());
2463 mWifiNative.saveConfig();
2464 return true;
2465 }
2466
Robert Greenwalt4717c262012-10-31 14:32:53 -07002467 private void setWifiP2pInfoOnGroupFormation(InetAddress serverInetAddress) {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002468 mWifiP2pInfo.groupFormed = true;
2469 mWifiP2pInfo.isGroupOwner = mGroup.isGroupOwner();
Robert Greenwalt4717c262012-10-31 14:32:53 -07002470 mWifiP2pInfo.groupOwnerAddress = serverInetAddress;
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002471 }
2472
Irfan Sheriff0a667632012-09-06 14:19:30 -07002473 private void resetWifiP2pInfo() {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002474 mWifiP2pInfo.groupFormed = false;
2475 mWifiP2pInfo.isGroupOwner = false;
2476 mWifiP2pInfo.groupOwnerAddress = null;
2477 }
2478
Irfan Sheriff618455f2011-11-18 14:33:09 -08002479 private String getDeviceName(String deviceAddress) {
Yoshihiko Ikenagabfb27bb2012-02-14 11:28:35 +09002480 WifiP2pDevice d = mPeers.get(deviceAddress);
2481 if (d != null) {
Irfan Sheriff618455f2011-11-18 14:33:09 -08002482 return d.deviceName;
Irfan Sheriff618455f2011-11-18 14:33:09 -08002483 }
2484 //Treat the address as name if there is no match
2485 return deviceAddress;
2486 }
2487
Irfan Sheriff2bdefca2012-04-25 16:40:14 -07002488 private String getPersistedDeviceName() {
Jeff Sharkeybdfce2e2012-09-26 15:54:06 -07002489 String deviceName = Settings.Global.getString(mContext.getContentResolver(),
2490 Settings.Global.WIFI_P2P_DEVICE_NAME);
Irfan Sheriff2bdefca2012-04-25 16:40:14 -07002491 if (deviceName == null) {
2492 /* We use the 4 digits of the ANDROID_ID to have a friendly
2493 * default that has low likelihood of collision with a peer */
2494 String id = Settings.Secure.getString(mContext.getContentResolver(),
2495 Settings.Secure.ANDROID_ID);
2496 return "Android_" + id.substring(0,4);
2497 }
2498 return deviceName;
2499 }
2500
2501 private boolean setAndPersistDeviceName(String devName) {
2502 if (devName == null) return false;
2503
2504 if (!mWifiNative.setDeviceName(devName)) {
2505 loge("Failed to set device name " + devName);
2506 return false;
2507 }
2508
2509 mThisDevice.deviceName = devName;
2510 mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName);
2511
Jeff Sharkeybdfce2e2012-09-26 15:54:06 -07002512 Settings.Global.putString(mContext.getContentResolver(),
2513 Settings.Global.WIFI_P2P_DEVICE_NAME, devName);
Irfan Sheriff2bdefca2012-04-25 16:40:14 -07002514 sendThisDeviceChangedBroadcast();
2515 return true;
2516 }
2517
Andreas Huberab4cd452012-08-15 16:16:31 -07002518 private boolean setWfdInfo(WifiP2pWfdInfo wfdInfo) {
2519 boolean success;
2520
2521 if (!wfdInfo.isWfdEnabled()) {
2522 success = mWifiNative.setWfdEnable(false);
2523 } else {
2524 success =
2525 mWifiNative.setWfdEnable(true)
2526 && mWifiNative.setWfdDeviceInfo(wfdInfo.getDeviceInfoHex());
2527 }
2528
2529 if (!success) {
2530 loge("Failed to set wfd properties");
2531 return false;
2532 }
2533
2534 mThisDevice.wfdInfo = wfdInfo;
2535 sendThisDeviceChangedBroadcast();
2536 return true;
2537 }
2538
Irfan Sheriff93226872011-08-29 10:36:05 -07002539 private void initializeP2pSettings() {
Irfan Sherifffc7f95a2012-01-04 14:50:09 -08002540 mWifiNative.setPersistentReconnect(true);
Irfan Sheriff2bdefca2012-04-25 16:40:14 -07002541 mThisDevice.deviceName = getPersistedDeviceName();
Irfan Sherifffc7f95a2012-01-04 14:50:09 -08002542 mWifiNative.setDeviceName(mThisDevice.deviceName);
Irfan Sheriffde1e9fa92012-05-01 16:15:23 -07002543 // DIRECT-XY-DEVICENAME (XY is randomly generated)
Irfan Sherifffc7f95a2012-01-04 14:50:09 -08002544 mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName);
2545 mWifiNative.setDeviceType(mThisDevice.primaryDeviceType);
Irfan Sheriffde1e9fa92012-05-01 16:15:23 -07002546 // Supplicant defaults to using virtual display with display
2547 // which refers to a remote display. Use physical_display
2548 mWifiNative.setConfigMethods("virtual_push_button physical_display keypad");
2549 // STA has higher priority over P2P
Irfan Sheriff55bfa422012-04-06 15:25:41 -07002550 mWifiNative.setConcurrencyPriority("sta");
Irfan Sheriff4be4d312011-09-03 11:03:23 -07002551
Irfan Sherifffc7f95a2012-01-04 14:50:09 -08002552 mThisDevice.deviceAddress = mWifiNative.p2pGetDeviceAddress();
Irfan Sheriff651cdfc2011-09-07 00:31:20 -07002553 updateThisDevice(WifiP2pDevice.AVAILABLE);
Irfan Sherifff1180432012-12-13 12:33:42 -08002554 if (DBG) logd("DeviceAddress: " + mThisDevice.deviceAddress);
Irfan Sheriff21ba8152012-04-04 16:22:21 -07002555
2556 mClientInfoList.clear();
2557 mWifiNative.p2pFlush();
2558 mWifiNative.p2pServiceFlush();
2559 mServiceTransactionId = 0;
2560 mServiceDiscReqId = null;
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002561
Robert Greenwalt3ea0c992013-10-03 21:13:49 +00002562 String countryCode = Settings.Global.getString(mContext.getContentResolver(),
2563 Settings.Global.WIFI_COUNTRY_CODE);
2564 if (countryCode != null && !countryCode.isEmpty()) {
2565 mP2pStateMachine.sendMessage(SET_COUNTRY_CODE, countryCode);
2566 }
2567
Irfan Sheriffca1269f2012-09-27 17:01:41 -07002568 updatePersistentNetworks(RELOAD);
Irfan Sheriff651cdfc2011-09-07 00:31:20 -07002569 }
2570
2571 private void updateThisDevice(int status) {
2572 mThisDevice.status = status;
2573 sendThisDeviceChangedBroadcast();
Irfan Sheriff93226872011-08-29 10:36:05 -07002574 }
2575
Irfan Sheriff55bfa422012-04-06 15:25:41 -07002576 private void handleGroupCreationFailure() {
Irfan Sheriff0a667632012-09-06 14:19:30 -07002577 resetWifiP2pInfo();
2578 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.FAILED, null, null);
2579 sendP2pConnectionChangedBroadcast();
Irfan Sheriff3a67e252012-12-07 15:51:34 -08002580
2581 // Remove only the peer we failed to connect to so that other devices discovered
2582 // that have not timed out still remain in list for connection
2583 boolean peersChanged = mPeers.remove(mPeersLostDuringConnection);
Irfan Sherifff1180432012-12-13 12:33:42 -08002584 if (mPeers.remove(mSavedPeerConfig.deviceAddress) != null) {
Irfan Sheriff3a67e252012-12-07 15:51:34 -08002585 peersChanged = true;
2586 }
2587 if (peersChanged) {
2588 sendPeersChangedBroadcast();
2589 }
2590
Irfan Sheriff41de2402012-10-12 15:52:13 -07002591 mPeersLostDuringConnection.clear();
Irfan Sheriffde1e9fa92012-05-01 16:15:23 -07002592 mServiceDiscReqId = null;
Irfan Sheriff55bfa422012-04-06 15:25:41 -07002593 sendMessage(WifiP2pManager.DISCOVER_PEERS);
2594 }
2595
Irfan Sheriffd36adc32012-09-23 15:27:50 -07002596 private void handleGroupRemoved() {
Irfan Sheriffd36adc32012-09-23 15:27:50 -07002597 if (mGroup.isGroupOwner()) {
2598 stopDhcpServer(mGroup.getInterface());
2599 } else {
2600 if (DBG) logd("stop DHCP client");
2601 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
2602 mDhcpStateMachine.doQuit();
2603 mDhcpStateMachine = null;
2604 }
2605
Irfan Sheriff0befeb22012-10-03 15:53:45 -07002606 try {
2607 mNwService.clearInterfaceAddresses(mGroup.getInterface());
2608 } catch (Exception e) {
2609 loge("Failed to clear addresses " + e);
2610 }
2611 NetworkUtils.resetConnections(mGroup.getInterface(), NetworkUtils.RESET_ALL_ADDRESSES);
2612
Irfan Sheriff51aec5e2012-10-22 16:28:02 -07002613 // Clear any timeout that was set. This is essential for devices
2614 // that reuse the main p2p interface for a created group.
2615 mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0);
2616
Irfan Sheriff3a67e252012-12-07 15:51:34 -08002617 boolean peersChanged = false;
2618 // Remove only peers part of the group, so that other devices discovered
2619 // that have not timed out still remain in list for connection
2620 for (WifiP2pDevice d : mGroup.getClientList()) {
2621 if (mPeers.remove(d)) peersChanged = true;
2622 }
2623 if (mPeers.remove(mGroup.getOwner())) peersChanged = true;
2624 if (mPeers.remove(mPeersLostDuringConnection)) peersChanged = true;
2625 if (peersChanged) {
2626 sendPeersChangedBroadcast();
2627 }
2628
Irfan Sheriffd36adc32012-09-23 15:27:50 -07002629 mGroup = null;
Irfan Sheriff41de2402012-10-12 15:52:13 -07002630 mPeersLostDuringConnection.clear();
Irfan Sheriffd36adc32012-09-23 15:27:50 -07002631 mServiceDiscReqId = null;
Irfan Sheriff9f452d02012-10-15 12:00:29 -07002632
2633 if (mTempoarilyDisconnectedWifi) {
2634 mWifiChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_REQUEST, 0);
2635 mTempoarilyDisconnectedWifi = false;
2636 }
Irfan Sheriff51aec5e2012-10-22 16:28:02 -07002637 }
Irfan Sheriffd36adc32012-09-23 15:27:50 -07002638
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002639 //State machine initiated requests can have replyTo set to null indicating
Irfan Sheriffde1e9fa92012-05-01 16:15:23 -07002640 //there are no recipients, we ignore those reply actions
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002641 private void replyToMessage(Message msg, int what) {
2642 if (msg.replyTo == null) return;
Irfan Sheriff651cdfc2011-09-07 00:31:20 -07002643 Message dstMsg = obtainMessage(msg);
2644 dstMsg.what = what;
2645 mReplyChannel.replyToMessage(msg, dstMsg);
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002646 }
2647
Irfan Sherifff0ef26a2011-09-07 15:05:54 -07002648 private void replyToMessage(Message msg, int what, int arg1) {
2649 if (msg.replyTo == null) return;
Irfan Sheriff651cdfc2011-09-07 00:31:20 -07002650 Message dstMsg = obtainMessage(msg);
2651 dstMsg.what = what;
2652 dstMsg.arg1 = arg1;
2653 mReplyChannel.replyToMessage(msg, dstMsg);
Irfan Sherifff0ef26a2011-09-07 15:05:54 -07002654 }
2655
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002656 private void replyToMessage(Message msg, int what, Object obj) {
2657 if (msg.replyTo == null) return;
Irfan Sheriff651cdfc2011-09-07 00:31:20 -07002658 Message dstMsg = obtainMessage(msg);
2659 dstMsg.what = what;
2660 dstMsg.obj = obj;
2661 mReplyChannel.replyToMessage(msg, dstMsg);
2662 }
2663
2664 /* arg2 on the source message has a hash code that needs to be retained in replies
2665 * see WifiP2pManager for details */
2666 private Message obtainMessage(Message srcMsg) {
2667 Message msg = Message.obtain();
2668 msg.arg2 = srcMsg.arg2;
2669 return msg;
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002670 }
2671
Wink Saville58c73c32013-01-28 10:52:34 -08002672 @Override
2673 protected void logd(String s) {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002674 Slog.d(TAG, s);
2675 }
2676
Wink Saville58c73c32013-01-28 10:52:34 -08002677 @Override
2678 protected void loge(String s) {
Irfan Sheriffea5b16a2011-08-24 12:30:20 -07002679 Slog.e(TAG, s);
2680 }
2681
Irfan Sheriff21ba8152012-04-04 16:22:21 -07002682 /**
2683 * Update service discovery request to wpa_supplicant.
2684 */
2685 private boolean updateSupplicantServiceRequest() {
2686 clearSupplicantServiceRequest();
2687
2688 StringBuffer sb = new StringBuffer();
2689 for (ClientInfo c: mClientInfoList.values()) {
2690 int key;
2691 WifiP2pServiceRequest req;
2692 for (int i=0; i < c.mReqList.size(); i++) {
Irfan Sheriff3b8be872012-04-18 15:46:00 -07002693 req = c.mReqList.valueAt(i);
Irfan Sheriff21ba8152012-04-04 16:22:21 -07002694 if (req != null) {
2695 sb.append(req.getSupplicantQuery());
2696 }
2697 }
2698 }
2699
2700 if (sb.length() == 0) {
2701 return false;
2702 }
2703
2704 mServiceDiscReqId = mWifiNative.p2pServDiscReq("00:00:00:00:00:00", sb.toString());
2705 if (mServiceDiscReqId == null) {
2706 return false;
2707 }
2708 return true;
2709 }
2710
2711 /**
2712 * Clear service discovery request in wpa_supplicant
2713 */
2714 private void clearSupplicantServiceRequest() {
2715 if (mServiceDiscReqId == null) return;
2716
2717 mWifiNative.p2pServDiscCancelReq(mServiceDiscReqId);
2718 mServiceDiscReqId = null;
2719 }
2720
Irfan Sheriffde1e9fa92012-05-01 16:15:23 -07002721 /* TODO: We could track individual service adds separately and avoid
Irfan Sheriff21ba8152012-04-04 16:22:21 -07002722 * having to do update all service requests on every new request
2723 */
2724 private boolean addServiceRequest(Messenger m, WifiP2pServiceRequest req) {
2725 clearClientDeadChannels();
2726 ClientInfo clientInfo = getClientInfo(m, true);
2727 if (clientInfo == null) {
2728 return false;
2729 }
2730
Irfan Sheriff3b8be872012-04-18 15:46:00 -07002731 ++mServiceTransactionId;
2732 //The Wi-Fi p2p spec says transaction id should be non-zero
2733 if (mServiceTransactionId == 0) ++mServiceTransactionId;
2734 req.setTransactionId(mServiceTransactionId);
Irfan Sheriff21ba8152012-04-04 16:22:21 -07002735 clientInfo.mReqList.put(mServiceTransactionId, req);
2736
2737 if (mServiceDiscReqId == null) {
2738 return true;
2739 }
2740
2741 return updateSupplicantServiceRequest();
2742 }
2743
2744 private void removeServiceRequest(Messenger m, WifiP2pServiceRequest req) {
Irfan Sheriff21ba8152012-04-04 16:22:21 -07002745 ClientInfo clientInfo = getClientInfo(m, false);
2746 if (clientInfo == null) {
2747 return;
2748 }
2749
Irfan Sheriff3b8be872012-04-18 15:46:00 -07002750 //Application does not have transaction id information
2751 //go through stored requests to remove
2752 boolean removed = false;
Yoshihiko Ikenaga0879d032012-08-16 23:37:36 +09002753 for (int i=0; i<clientInfo.mReqList.size(); i++) {
Irfan Sheriff3b8be872012-04-18 15:46:00 -07002754 if (req.equals(clientInfo.mReqList.valueAt(i))) {
2755 removed = true;
2756 clientInfo.mReqList.removeAt(i);
2757 break;
2758 }
2759 }
2760
2761 if (!removed) return;
Irfan Sheriff21ba8152012-04-04 16:22:21 -07002762
2763 if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) {
2764 if (DBG) logd("remove client information from framework");
2765 mClientInfoList.remove(clientInfo.mMessenger);
2766 }
2767
2768 if (mServiceDiscReqId == null) {
2769 return;
2770 }
2771
2772 updateSupplicantServiceRequest();
2773 }
2774
2775 private void clearServiceRequests(Messenger m) {
2776
2777 ClientInfo clientInfo = getClientInfo(m, false);
2778 if (clientInfo == null) {
2779 return;
2780 }
2781
2782 if (clientInfo.mReqList.size() == 0) {
2783 return;
2784 }
2785
2786 clientInfo.mReqList.clear();
2787
2788 if (clientInfo.mServList.size() == 0) {
2789 if (DBG) logd("remove channel information from framework");
2790 mClientInfoList.remove(clientInfo.mMessenger);
2791 }
2792
2793 if (mServiceDiscReqId == null) {
2794 return;
2795 }
2796
2797 updateSupplicantServiceRequest();
2798 }
2799
2800 private boolean addLocalService(Messenger m, WifiP2pServiceInfo servInfo) {
2801 clearClientDeadChannels();
2802 ClientInfo clientInfo = getClientInfo(m, true);
2803 if (clientInfo == null) {
2804 return false;
2805 }
2806
2807 if (!clientInfo.mServList.add(servInfo)) {
2808 return false;
2809 }
2810
2811 if (!mWifiNative.p2pServiceAdd(servInfo)) {
2812 clientInfo.mServList.remove(servInfo);
2813 return false;
2814 }
2815
2816 return true;
2817 }
2818
2819 private void removeLocalService(Messenger m, WifiP2pServiceInfo servInfo) {
2820 ClientInfo clientInfo = getClientInfo(m, false);
2821 if (clientInfo == null) {
2822 return;
2823 }
2824
2825 mWifiNative.p2pServiceDel(servInfo);
2826
2827 clientInfo.mServList.remove(servInfo);
2828 if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) {
2829 if (DBG) logd("remove client information from framework");
2830 mClientInfoList.remove(clientInfo.mMessenger);
2831 }
2832 }
2833
2834 private void clearLocalServices(Messenger m) {
2835 ClientInfo clientInfo = getClientInfo(m, false);
2836 if (clientInfo == null) {
2837 return;
2838 }
2839
2840 for (WifiP2pServiceInfo servInfo: clientInfo.mServList) {
2841 mWifiNative.p2pServiceDel(servInfo);
2842 }
2843
2844 clientInfo.mServList.clear();
2845 if (clientInfo.mReqList.size() == 0) {
2846 if (DBG) logd("remove client information from framework");
2847 mClientInfoList.remove(clientInfo.mMessenger);
2848 }
2849 }
2850
2851 private void clearClientInfo(Messenger m) {
2852 clearLocalServices(m);
2853 clearServiceRequests(m);
2854 }
2855
2856 /**
2857 * Send the service response to the WifiP2pManager.Channel.
2858 *
2859 * @param resp
2860 */
2861 private void sendServiceResponse(WifiP2pServiceResponse resp) {
2862 for (ClientInfo c : mClientInfoList.values()) {
2863 WifiP2pServiceRequest req = c.mReqList.get(resp.getTransactionId());
2864 if (req != null) {
2865 Message msg = Message.obtain();
2866 msg.what = WifiP2pManager.RESPONSE_SERVICE;
2867 msg.arg1 = 0;
2868 msg.arg2 = 0;
2869 msg.obj = resp;
2870 try {
2871 c.mMessenger.send(msg);
2872 } catch (RemoteException e) {
2873 if (DBG) logd("detect dead channel");
2874 clearClientInfo(c.mMessenger);
Irfan Sheriff3b8be872012-04-18 15:46:00 -07002875 return;
Irfan Sheriff21ba8152012-04-04 16:22:21 -07002876 }
2877 }
2878 }
2879 }
2880
2881 /**
2882 * We dont get notifications of clients that have gone away.
2883 * We detect this actively when services are added and throw
2884 * them away.
2885 *
2886 * TODO: This can be done better with full async channels.
2887 */
2888 private void clearClientDeadChannels() {
Irfan Sheriff3b8be872012-04-18 15:46:00 -07002889 ArrayList<Messenger> deadClients = new ArrayList<Messenger>();
2890
Irfan Sheriff21ba8152012-04-04 16:22:21 -07002891 for (ClientInfo c : mClientInfoList.values()) {
2892 Message msg = Message.obtain();
2893 msg.what = WifiP2pManager.PING;
2894 msg.arg1 = 0;
2895 msg.arg2 = 0;
2896 msg.obj = null;
2897 try {
2898 c.mMessenger.send(msg);
2899 } catch (RemoteException e) {
2900 if (DBG) logd("detect dead channel");
Irfan Sheriff3b8be872012-04-18 15:46:00 -07002901 deadClients.add(c.mMessenger);
Irfan Sheriff21ba8152012-04-04 16:22:21 -07002902 }
2903 }
Irfan Sheriff3b8be872012-04-18 15:46:00 -07002904
2905 for (Messenger m : deadClients) {
2906 clearClientInfo(m);
2907 }
Irfan Sheriff21ba8152012-04-04 16:22:21 -07002908 }
2909
2910 /**
2911 * Return the specified ClientInfo.
2912 * @param m Messenger
2913 * @param createIfNotExist if true and the specified channel info does not exist,
2914 * create new client info.
2915 * @return the specified ClientInfo.
2916 */
2917 private ClientInfo getClientInfo(Messenger m, boolean createIfNotExist) {
2918 ClientInfo clientInfo = mClientInfoList.get(m);
2919
2920 if (clientInfo == null && createIfNotExist) {
2921 if (DBG) logd("add a new client");
2922 clientInfo = new ClientInfo(m);
2923 mClientInfoList.put(m, clientInfo);
2924 }
2925
2926 return clientInfo;
2927 }
2928
2929 }
2930
2931 /**
2932 * Information about a particular client and we track the service discovery requests
2933 * and the local services registered by the client.
2934 */
2935 private class ClientInfo {
2936
2937 /*
2938 * A reference to WifiP2pManager.Channel handler.
2939 * The response of this request is notified to WifiP2pManager.Channel handler
2940 */
2941 private Messenger mMessenger;
2942
2943 /*
2944 * A service discovery request list.
2945 */
2946 private SparseArray<WifiP2pServiceRequest> mReqList;
2947
2948 /*
2949 * A local service information list.
2950 */
2951 private List<WifiP2pServiceInfo> mServList;
2952
2953 private ClientInfo(Messenger m) {
2954 mMessenger = m;
2955 mReqList = new SparseArray();
2956 mServList = new ArrayList<WifiP2pServiceInfo>();
2957 }
repo sync55bc5f32011-06-24 14:23:07 -07002958 }
repo sync55bc5f32011-06-24 14:23:07 -07002959}