Home | History | Annotate | Download | only in p2p
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.wifi.p2p;
     18 
     19 import android.app.AlertDialog;
     20 import android.app.Notification;
     21 import android.content.Context;
     22 import android.content.DialogInterface;
     23 import android.content.DialogInterface.OnClickListener;
     24 import android.content.Intent;
     25 import android.content.pm.PackageManager;
     26 import android.content.res.Configuration;
     27 import android.content.res.Resources;
     28 import android.net.ConnectivityManager;
     29 import android.net.DhcpResults;
     30 import android.net.DhcpStateMachine;
     31 import android.net.InterfaceConfiguration;
     32 import android.net.LinkAddress;
     33 import android.net.NetworkInfo;
     34 import android.net.NetworkUtils;
     35 import android.net.wifi.WpsInfo;
     36 import android.net.wifi.p2p.IWifiP2pManager;
     37 import android.net.wifi.p2p.WifiP2pConfig;
     38 import android.net.wifi.p2p.WifiP2pDevice;
     39 import android.net.wifi.p2p.WifiP2pDeviceList;
     40 import android.net.wifi.p2p.WifiP2pGroup;
     41 import android.net.wifi.p2p.WifiP2pGroupList;
     42 import android.net.wifi.p2p.WifiP2pGroupList.GroupDeleteListener;
     43 import android.net.wifi.p2p.WifiP2pInfo;
     44 import android.net.wifi.p2p.WifiP2pManager;
     45 import android.net.wifi.p2p.WifiP2pProvDiscEvent;
     46 import android.net.wifi.p2p.WifiP2pWfdInfo;
     47 import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
     48 import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
     49 import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
     50 import android.os.Binder;
     51 import android.os.Bundle;
     52 import android.os.Handler;
     53 import android.os.HandlerThread;
     54 import android.os.IBinder;
     55 import android.os.INetworkManagementService;
     56 import android.os.Looper;
     57 import android.os.Message;
     58 import android.os.Messenger;
     59 import android.os.RemoteException;
     60 import android.os.ServiceManager;
     61 import android.os.UserHandle;
     62 import android.provider.Settings;
     63 import android.text.TextUtils;
     64 import android.util.Slog;
     65 import android.util.SparseArray;
     66 import android.view.KeyEvent;
     67 import android.view.LayoutInflater;
     68 import android.view.View;
     69 import android.view.ViewGroup;
     70 import android.view.WindowManager;
     71 import android.widget.EditText;
     72 import android.widget.TextView;
     73 
     74 import com.android.internal.R;
     75 import com.android.internal.util.AsyncChannel;
     76 import com.android.internal.util.Protocol;
     77 import com.android.internal.util.State;
     78 import com.android.internal.util.StateMachine;
     79 import com.android.server.wifi.WifiMonitor;
     80 import com.android.server.wifi.WifiNative;
     81 import com.android.server.wifi.WifiStateMachine;
     82 
     83 import java.io.FileDescriptor;
     84 import java.io.PrintWriter;
     85 import java.net.InetAddress;
     86 import java.util.ArrayList;
     87 import java.util.Collection;
     88 import java.util.HashMap;
     89 import java.util.List;
     90 import java.util.Locale;
     91 
     92 
     93 /**
     94  * WifiP2pService includes a state machine to perform Wi-Fi p2p operations. Applications
     95  * communicate with this service to issue device discovery and connectivity requests
     96  * through the WifiP2pManager interface. The state machine communicates with the wifi
     97  * driver through wpa_supplicant and handles the event responses through WifiMonitor.
     98  *
     99  * Note that the term Wifi when used without a p2p suffix refers to the client mode
    100  * of Wifi operation
    101  * @hide
    102  */
    103 public final class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
    104     private static final String TAG = "WifiP2pService";
    105     private static final boolean DBG = false;
    106     private static final String NETWORKTYPE = "WIFI_P2P";
    107 
    108     private Context mContext;
    109     private String mInterface;
    110     private Notification mNotification;
    111 
    112     INetworkManagementService mNwService;
    113     private DhcpStateMachine mDhcpStateMachine;
    114 
    115     private P2pStateMachine mP2pStateMachine;
    116     private AsyncChannel mReplyChannel = new AsyncChannel();
    117     private AsyncChannel mWifiChannel;
    118 
    119     private static final Boolean JOIN_GROUP = true;
    120     private static final Boolean FORM_GROUP = false;
    121 
    122     private static final Boolean RELOAD = true;
    123     private static final Boolean NO_RELOAD = false;
    124 
    125     /* Two minutes comes from the wpa_supplicant setting */
    126     private static final int GROUP_CREATING_WAIT_TIME_MS = 120 * 1000;
    127     private static int mGroupCreatingTimeoutIndex = 0;
    128 
    129     private static final int DISABLE_P2P_WAIT_TIME_MS = 5 * 1000;
    130     private static int mDisableP2pTimeoutIndex = 0;
    131 
    132     /* Set a two minute discover timeout to avoid STA scans from being blocked */
    133     private static final int DISCOVER_TIMEOUT_S = 120;
    134 
    135     /* Idle time after a peer is gone when the group is torn down */
    136     private static final int GROUP_IDLE_TIME_S = 10;
    137 
    138     private static final int BASE = Protocol.BASE_WIFI_P2P_SERVICE;
    139 
    140     /* Delayed message to timeout group creation */
    141     public static final int GROUP_CREATING_TIMED_OUT        =   BASE + 1;
    142 
    143     /* User accepted a peer request */
    144     private static final int PEER_CONNECTION_USER_ACCEPT    =   BASE + 2;
    145     /* User rejected a peer request */
    146     private static final int PEER_CONNECTION_USER_REJECT    =   BASE + 3;
    147     /* User wants to disconnect wifi in favour of p2p */
    148     private static final int DROP_WIFI_USER_ACCEPT          =   BASE + 4;
    149     /* User wants to keep his wifi connection and drop p2p */
    150     private static final int DROP_WIFI_USER_REJECT          =   BASE + 5;
    151     /* Delayed message to timeout p2p disable */
    152     public static final int DISABLE_P2P_TIMED_OUT           =   BASE + 6;
    153 
    154 
    155     /* Commands to the WifiStateMachine */
    156     public static final int P2P_CONNECTION_CHANGED          =   BASE + 11;
    157 
    158     /* These commands are used to temporarily disconnect wifi when we detect
    159      * a frequency conflict which would make it impossible to have with p2p
    160      * and wifi active at the same time.
    161      *
    162      * If the user chooses to disable wifi temporarily, we keep wifi disconnected
    163      * until the p2p connection is done and terminated at which point we will
    164      * bring back wifi up
    165      *
    166      * DISCONNECT_WIFI_REQUEST
    167      *      msg.arg1 = 1 enables temporary disconnect and 0 disables it.
    168      */
    169     public static final int DISCONNECT_WIFI_REQUEST         =   BASE + 12;
    170     public static final int DISCONNECT_WIFI_RESPONSE        =   BASE + 13;
    171 
    172     public static final int SET_MIRACAST_MODE               =   BASE + 14;
    173 
    174     // During dhcp (and perhaps other times) we can't afford to drop packets
    175     // but Discovery will switch our channel enough we will.
    176     //   msg.arg1 = ENABLED for blocking, DISABLED for resumed.
    177     //   msg.arg2 = msg to send when blocked
    178     //   msg.obj  = StateMachine to send to when blocked
    179     public static final int BLOCK_DISCOVERY                 =   BASE + 15;
    180 
    181     // set country code
    182     public static final int SET_COUNTRY_CODE                =   BASE + 16;
    183 
    184     public static final int ENABLED                         = 1;
    185     public static final int DISABLED                        = 0;
    186 
    187     private final boolean mP2pSupported;
    188 
    189     private WifiP2pDevice mThisDevice = new WifiP2pDevice();
    190 
    191     /* When a group has been explicitly created by an app, we persist the group
    192      * even after all clients have been disconnected until an explicit remove
    193      * is invoked */
    194     private boolean mAutonomousGroup;
    195 
    196     /* Invitation to join an existing p2p group */
    197     private boolean mJoinExistingGroup;
    198 
    199     /* Track whether we are in p2p discovery. This is used to avoid sending duplicate
    200      * broadcasts
    201      */
    202     private boolean mDiscoveryStarted;
    203     /* Track whether servcice/peer discovery is blocked in favor of other wifi actions
    204      * (notably dhcp)
    205      */
    206     private boolean mDiscoveryBlocked;
    207 
    208     // Supplicant doesn't like setting the same country code multiple times (it may drop
    209     // current connected network), so we save the country code here to avoid redundency
    210     private String mLastSetCountryCode;
    211 
    212     /*
    213      * remember if we were in a scan when it had to be stopped
    214      */
    215     private boolean mDiscoveryPostponed = false;
    216 
    217     private NetworkInfo mNetworkInfo;
    218 
    219     private boolean mTemporarilyDisconnectedWifi = false;
    220 
    221     /* The transaction Id of service discovery request */
    222     private byte mServiceTransactionId = 0;
    223 
    224     /* Service discovery request ID of wpa_supplicant.
    225      * null means it's not set yet. */
    226     private String mServiceDiscReqId;
    227 
    228     /* clients(application) information list. */
    229     private HashMap<Messenger, ClientInfo> mClientInfoList = new HashMap<Messenger, ClientInfo>();
    230 
    231     /* Is chosen as a unique address to avoid conflict with
    232        the ranges defined in Tethering.java */
    233     private static final String SERVER_ADDRESS = "192.168.49.1";
    234 
    235     /**
    236      * Error code definition.
    237      * see the Table.8 in the WiFi Direct specification for the detail.
    238      */
    239     public static enum P2pStatus {
    240         /* Success. */
    241         SUCCESS,
    242 
    243         /* The target device is currently unavailable. */
    244         INFORMATION_IS_CURRENTLY_UNAVAILABLE,
    245 
    246         /* Protocol error. */
    247         INCOMPATIBLE_PARAMETERS,
    248 
    249         /* The target device reached the limit of the number of the connectable device.
    250          * For example, device limit or group limit is set. */
    251         LIMIT_REACHED,
    252 
    253         /* Protocol error. */
    254         INVALID_PARAMETER,
    255 
    256         /* Unable to accommodate request. */
    257         UNABLE_TO_ACCOMMODATE_REQUEST,
    258 
    259         /* Previous protocol error, or disruptive behavior. */
    260         PREVIOUS_PROTOCOL_ERROR,
    261 
    262         /* There is no common channels the both devices can use. */
    263         NO_COMMON_CHANNEL,
    264 
    265         /* Unknown p2p group. For example, Device A tries to invoke the previous persistent group,
    266          *  but device B has removed the specified credential already. */
    267         UNKNOWN_P2P_GROUP,
    268 
    269         /* Both p2p devices indicated an intent of 15 in group owner negotiation. */
    270         BOTH_GO_INTENT_15,
    271 
    272         /* Incompatible provisioning method. */
    273         INCOMPATIBLE_PROVISIONING_METHOD,
    274 
    275         /* Rejected by user */
    276         REJECTED_BY_USER,
    277 
    278         /* Unknown error */
    279         UNKNOWN;
    280 
    281         public static P2pStatus valueOf(int error) {
    282             switch(error) {
    283             case 0 :
    284                 return SUCCESS;
    285             case 1:
    286                 return INFORMATION_IS_CURRENTLY_UNAVAILABLE;
    287             case 2:
    288                 return INCOMPATIBLE_PARAMETERS;
    289             case 3:
    290                 return LIMIT_REACHED;
    291             case 4:
    292                 return INVALID_PARAMETER;
    293             case 5:
    294                 return UNABLE_TO_ACCOMMODATE_REQUEST;
    295             case 6:
    296                 return PREVIOUS_PROTOCOL_ERROR;
    297             case 7:
    298                 return NO_COMMON_CHANNEL;
    299             case 8:
    300                 return UNKNOWN_P2P_GROUP;
    301             case 9:
    302                 return BOTH_GO_INTENT_15;
    303             case 10:
    304                 return INCOMPATIBLE_PROVISIONING_METHOD;
    305             case 11:
    306                 return REJECTED_BY_USER;
    307             default:
    308                 return UNKNOWN;
    309             }
    310         }
    311     }
    312 
    313     /**
    314      * Handles client connections
    315      */
    316     private class ClientHandler extends Handler {
    317 
    318         ClientHandler(android.os.Looper looper) {
    319             super(looper);
    320         }
    321 
    322         @Override
    323         public void handleMessage(Message msg) {
    324             switch (msg.what) {
    325               case WifiP2pManager.SET_DEVICE_NAME:
    326               case WifiP2pManager.SET_WFD_INFO:
    327               case WifiP2pManager.DISCOVER_PEERS:
    328               case WifiP2pManager.STOP_DISCOVERY:
    329               case WifiP2pManager.CONNECT:
    330               case WifiP2pManager.CANCEL_CONNECT:
    331               case WifiP2pManager.CREATE_GROUP:
    332               case WifiP2pManager.REMOVE_GROUP:
    333               case WifiP2pManager.START_LISTEN:
    334               case WifiP2pManager.STOP_LISTEN:
    335               case WifiP2pManager.SET_CHANNEL:
    336               case WifiP2pManager.START_WPS:
    337               case WifiP2pManager.ADD_LOCAL_SERVICE:
    338               case WifiP2pManager.REMOVE_LOCAL_SERVICE:
    339               case WifiP2pManager.CLEAR_LOCAL_SERVICES:
    340               case WifiP2pManager.DISCOVER_SERVICES:
    341               case WifiP2pManager.ADD_SERVICE_REQUEST:
    342               case WifiP2pManager.REMOVE_SERVICE_REQUEST:
    343               case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
    344               case WifiP2pManager.REQUEST_PEERS:
    345               case WifiP2pManager.REQUEST_CONNECTION_INFO:
    346               case WifiP2pManager.REQUEST_GROUP_INFO:
    347               case WifiP2pManager.DELETE_PERSISTENT_GROUP:
    348               case WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO:
    349                 mP2pStateMachine.sendMessage(Message.obtain(msg));
    350                 break;
    351               default:
    352                 Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg);
    353                 break;
    354             }
    355         }
    356     }
    357     private ClientHandler mClientHandler;
    358 
    359     public WifiP2pServiceImpl(Context context) {
    360         mContext = context;
    361 
    362         //STOPSHIP: get this from native side
    363         mInterface = "p2p0";
    364         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, "");
    365 
    366         mP2pSupported = mContext.getPackageManager().hasSystemFeature(
    367                 PackageManager.FEATURE_WIFI_DIRECT);
    368 
    369         mThisDevice.primaryDeviceType = mContext.getResources().getString(
    370                 com.android.internal.R.string.config_wifi_p2p_device_type);
    371 
    372         HandlerThread wifiP2pThread = new HandlerThread("WifiP2pService");
    373         wifiP2pThread.start();
    374         mClientHandler = new ClientHandler(wifiP2pThread.getLooper());
    375 
    376         mP2pStateMachine = new P2pStateMachine(TAG, wifiP2pThread.getLooper(), mP2pSupported);
    377         mP2pStateMachine.start();
    378     }
    379 
    380     public void connectivityServiceReady() {
    381         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
    382         mNwService = INetworkManagementService.Stub.asInterface(b);
    383     }
    384 
    385     private void enforceAccessPermission() {
    386         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
    387                 "WifiP2pService");
    388     }
    389 
    390     private void enforceChangePermission() {
    391         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
    392                 "WifiP2pService");
    393     }
    394 
    395     private void enforceConnectivityInternalPermission() {
    396         mContext.enforceCallingOrSelfPermission(
    397                 android.Manifest.permission.CONNECTIVITY_INTERNAL,
    398                 "WifiP2pService");
    399     }
    400 
    401     private int checkConnectivityInternalPermission() {
    402         return mContext.checkCallingOrSelfPermission(
    403                 android.Manifest.permission.CONNECTIVITY_INTERNAL);
    404     }
    405 
    406     private int checkLocationHardwarePermission() {
    407         return mContext.checkCallingOrSelfPermission(
    408                 android.Manifest.permission.LOCATION_HARDWARE);
    409     }
    410 
    411     private void enforceConnectivityInternalOrLocationHardwarePermission() {
    412         if (checkConnectivityInternalPermission() != PackageManager.PERMISSION_GRANTED
    413                 && checkLocationHardwarePermission() != PackageManager.PERMISSION_GRANTED) {
    414             enforceConnectivityInternalPermission();
    415         }
    416     }
    417 
    418     /**
    419      * Get a reference to handler. This is used by a client to establish
    420      * an AsyncChannel communication with WifiP2pService
    421      */
    422     public Messenger getMessenger() {
    423         enforceAccessPermission();
    424         enforceChangePermission();
    425         return new Messenger(mClientHandler);
    426     }
    427 
    428     /**
    429      * Get a reference to handler. This is used by a WifiStateMachine to establish
    430      * an AsyncChannel communication with P2pStateMachine
    431      * @hide
    432      */
    433     public Messenger getP2pStateMachineMessenger() {
    434         enforceConnectivityInternalOrLocationHardwarePermission();
    435         enforceAccessPermission();
    436         enforceChangePermission();
    437         return new Messenger(mP2pStateMachine.getHandler());
    438     }
    439 
    440     /** This is used to provide information to drivers to optimize performance depending
    441      * on the current mode of operation.
    442      * 0 - disabled
    443      * 1 - source operation
    444      * 2 - sink operation
    445      *
    446      * As an example, the driver could reduce the channel dwell time during scanning
    447      * when acting as a source or sink to minimize impact on miracast.
    448      */
    449     public void setMiracastMode(int mode) {
    450         enforceConnectivityInternalPermission();
    451         mP2pStateMachine.sendMessage(SET_MIRACAST_MODE, mode);
    452     }
    453 
    454     @Override
    455     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    456         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
    457                 != PackageManager.PERMISSION_GRANTED) {
    458             pw.println("Permission Denial: can't dump WifiP2pService from from pid="
    459                     + Binder.getCallingPid()
    460                     + ", uid=" + Binder.getCallingUid());
    461             return;
    462         }
    463         mP2pStateMachine.dump(fd, pw, args);
    464         pw.println("mAutonomousGroup " + mAutonomousGroup);
    465         pw.println("mJoinExistingGroup " + mJoinExistingGroup);
    466         pw.println("mDiscoveryStarted " + mDiscoveryStarted);
    467         pw.println("mNetworkInfo " + mNetworkInfo);
    468         pw.println("mTemporarilyDisconnectedWifi " + mTemporarilyDisconnectedWifi);
    469         pw.println("mServiceDiscReqId " + mServiceDiscReqId);
    470         pw.println();
    471     }
    472 
    473 
    474     /**
    475      * Handles interaction with WifiStateMachine
    476      */
    477     private class P2pStateMachine extends StateMachine {
    478 
    479         private DefaultState mDefaultState = new DefaultState();
    480         private P2pNotSupportedState mP2pNotSupportedState = new P2pNotSupportedState();
    481         private P2pDisablingState mP2pDisablingState = new P2pDisablingState();
    482         private P2pDisabledState mP2pDisabledState = new P2pDisabledState();
    483         private P2pEnablingState mP2pEnablingState = new P2pEnablingState();
    484         private P2pEnabledState mP2pEnabledState = new P2pEnabledState();
    485         // Inactive is when p2p is enabled with no connectivity
    486         private InactiveState mInactiveState = new InactiveState();
    487         private GroupCreatingState mGroupCreatingState = new GroupCreatingState();
    488         private UserAuthorizingInviteRequestState mUserAuthorizingInviteRequestState
    489                 = new UserAuthorizingInviteRequestState();
    490         private UserAuthorizingNegotiationRequestState mUserAuthorizingNegotiationRequestState
    491                 = new UserAuthorizingNegotiationRequestState();
    492         private ProvisionDiscoveryState mProvisionDiscoveryState = new ProvisionDiscoveryState();
    493         private GroupNegotiationState mGroupNegotiationState = new GroupNegotiationState();
    494         private FrequencyConflictState mFrequencyConflictState =new FrequencyConflictState();
    495 
    496         private GroupCreatedState mGroupCreatedState = new GroupCreatedState();
    497         private UserAuthorizingJoinState mUserAuthorizingJoinState = new UserAuthorizingJoinState();
    498         private OngoingGroupRemovalState mOngoingGroupRemovalState = new OngoingGroupRemovalState();
    499 
    500         private WifiNative mWifiNative = new WifiNative(mInterface);
    501         private WifiMonitor mWifiMonitor = new WifiMonitor(this, mWifiNative);
    502 
    503         private final WifiP2pDeviceList mPeers = new WifiP2pDeviceList();
    504         /* During a connection, supplicant can tell us that a device was lost. From a supplicant's
    505          * perspective, the discovery stops during connection and it purges device since it does
    506          * not get latest updates about the device without being in discovery state.
    507          *
    508          * From the framework perspective, the device is still there since we are connecting or
    509          * connected to it. so we keep these devices in a separate list, so that they are removed
    510          * when connection is cancelled or lost
    511          */
    512         private final WifiP2pDeviceList mPeersLostDuringConnection = new WifiP2pDeviceList();
    513         private final WifiP2pGroupList mGroups = new WifiP2pGroupList(null,
    514                 new GroupDeleteListener() {
    515             @Override
    516             public void onDeleteGroup(int netId) {
    517                 if (DBG) logd("called onDeleteGroup() netId=" + netId);
    518                 mWifiNative.removeNetwork(netId);
    519                 mWifiNative.saveConfig();
    520                 sendP2pPersistentGroupsChangedBroadcast();
    521             }
    522         });
    523         private final WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo();
    524         private WifiP2pGroup mGroup;
    525 
    526         // Saved WifiP2pConfig for an ongoing peer connection. This will never be null.
    527         // The deviceAddress will be an empty string when the device is inactive
    528         // or if it is connected without any ongoing join request
    529         private WifiP2pConfig mSavedPeerConfig = new WifiP2pConfig();
    530 
    531         // Saved WifiP2pGroup from invitation request
    532         private WifiP2pGroup mSavedP2pGroup;
    533 
    534         P2pStateMachine(String name, Looper looper, boolean p2pSupported) {
    535             super(name, looper);
    536 
    537             addState(mDefaultState);
    538                 addState(mP2pNotSupportedState, mDefaultState);
    539                 addState(mP2pDisablingState, mDefaultState);
    540                 addState(mP2pDisabledState, mDefaultState);
    541                 addState(mP2pEnablingState, mDefaultState);
    542                 addState(mP2pEnabledState, mDefaultState);
    543                     addState(mInactiveState, mP2pEnabledState);
    544                     addState(mGroupCreatingState, mP2pEnabledState);
    545                         addState(mUserAuthorizingInviteRequestState, mGroupCreatingState);
    546                         addState(mUserAuthorizingNegotiationRequestState, mGroupCreatingState);
    547                         addState(mProvisionDiscoveryState, mGroupCreatingState);
    548                         addState(mGroupNegotiationState, mGroupCreatingState);
    549                         addState(mFrequencyConflictState, mGroupCreatingState);
    550                     addState(mGroupCreatedState, mP2pEnabledState);
    551                         addState(mUserAuthorizingJoinState, mGroupCreatedState);
    552                         addState(mOngoingGroupRemovalState, mGroupCreatedState);
    553 
    554             if (p2pSupported) {
    555                 setInitialState(mP2pDisabledState);
    556             } else {
    557                 setInitialState(mP2pNotSupportedState);
    558             }
    559             setLogRecSize(50);
    560             setLogOnlyTransitions(true);
    561         }
    562 
    563     class DefaultState extends State {
    564         @Override
    565         public boolean processMessage(Message message) {
    566             if (DBG) logd(getName() + message.toString());
    567             switch (message.what) {
    568                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
    569                     if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
    570                         if (DBG) logd("Full connection with WifiStateMachine established");
    571                         mWifiChannel = (AsyncChannel) message.obj;
    572                     } else {
    573                         loge("Full connection failure, error = " + message.arg1);
    574                         mWifiChannel = null;
    575                     }
    576                     break;
    577 
    578                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
    579                     if (message.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
    580                         loge("Send failed, client connection lost");
    581                     } else {
    582                         loge("Client connection lost with reason: " + message.arg1);
    583                     }
    584                     mWifiChannel = null;
    585                     break;
    586 
    587                 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
    588                     AsyncChannel ac = new AsyncChannel();
    589                     ac.connect(mContext, getHandler(), message.replyTo);
    590                     break;
    591                 case BLOCK_DISCOVERY:
    592                     mDiscoveryBlocked = (message.arg1 == ENABLED ? true : false);
    593                     // always reset this - we went to a state that doesn't support discovery so
    594                     // it would have stopped regardless
    595                     mDiscoveryPostponed = false;
    596                     if (mDiscoveryBlocked) {
    597                         try {
    598                             StateMachine m = (StateMachine)message.obj;
    599                             m.sendMessage(message.arg2);
    600                         } catch (Exception e) {
    601                             loge("unable to send BLOCK_DISCOVERY response: " + e);
    602                         }
    603                     }
    604                     break;
    605                 case WifiP2pManager.DISCOVER_PEERS:
    606                     replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
    607                             WifiP2pManager.BUSY);
    608                     break;
    609                 case WifiP2pManager.STOP_DISCOVERY:
    610                     replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
    611                             WifiP2pManager.BUSY);
    612                     break;
    613                 case WifiP2pManager.DISCOVER_SERVICES:
    614                     replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
    615                             WifiP2pManager.BUSY);
    616                     break;
    617                 case WifiP2pManager.CONNECT:
    618                     replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
    619                             WifiP2pManager.BUSY);
    620                     break;
    621                 case WifiP2pManager.CANCEL_CONNECT:
    622                     replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
    623                             WifiP2pManager.BUSY);
    624                     break;
    625                 case WifiP2pManager.CREATE_GROUP:
    626                     replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
    627                             WifiP2pManager.BUSY);
    628                     break;
    629                 case WifiP2pManager.REMOVE_GROUP:
    630                     replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
    631                             WifiP2pManager.BUSY);
    632                     break;
    633                 case WifiP2pManager.ADD_LOCAL_SERVICE:
    634                     replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED,
    635                             WifiP2pManager.BUSY);
    636                     break;
    637                 case WifiP2pManager.REMOVE_LOCAL_SERVICE:
    638                     replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED,
    639                             WifiP2pManager.BUSY);
    640                     break;
    641                 case WifiP2pManager.CLEAR_LOCAL_SERVICES:
    642                     replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED,
    643                             WifiP2pManager.BUSY);
    644                     break;
    645                 case WifiP2pManager.ADD_SERVICE_REQUEST:
    646                     replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED,
    647                             WifiP2pManager.BUSY);
    648                     break;
    649                 case WifiP2pManager.REMOVE_SERVICE_REQUEST:
    650                     replyToMessage(message,
    651                             WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED,
    652                             WifiP2pManager.BUSY);
    653                     break;
    654                 case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
    655                     replyToMessage(message,
    656                             WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED,
    657                             WifiP2pManager.BUSY);
    658                     break;
    659                 case WifiP2pManager.SET_DEVICE_NAME:
    660                     replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
    661                             WifiP2pManager.BUSY);
    662                     break;
    663                 case WifiP2pManager.DELETE_PERSISTENT_GROUP:
    664                     replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP,
    665                             WifiP2pManager.BUSY);
    666                     break;
    667                 case WifiP2pManager.SET_WFD_INFO:
    668                     replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
    669                             WifiP2pManager.BUSY);
    670                     break;
    671                 case WifiP2pManager.REQUEST_PEERS:
    672                     replyToMessage(message, WifiP2pManager.RESPONSE_PEERS,
    673                             new WifiP2pDeviceList(mPeers));
    674                     break;
    675                 case WifiP2pManager.REQUEST_CONNECTION_INFO:
    676                     replyToMessage(message, WifiP2pManager.RESPONSE_CONNECTION_INFO,
    677                             new WifiP2pInfo(mWifiP2pInfo));
    678                     break;
    679                 case WifiP2pManager.REQUEST_GROUP_INFO:
    680                     replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO,
    681                             mGroup != null ? new WifiP2pGroup(mGroup) : null);
    682                     break;
    683                 case WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO:
    684                     replyToMessage(message, WifiP2pManager.RESPONSE_PERSISTENT_GROUP_INFO,
    685                             new WifiP2pGroupList(mGroups, null));
    686                     break;
    687                 case WifiP2pManager.START_WPS:
    688                     replyToMessage(message, WifiP2pManager.START_WPS_FAILED,
    689                         WifiP2pManager.BUSY);
    690                     break;
    691                 case WifiP2pManager.GET_HANDOVER_REQUEST:
    692                 case WifiP2pManager.GET_HANDOVER_SELECT:
    693                     replyToMessage(message, WifiP2pManager.RESPONSE_GET_HANDOVER_MESSAGE, null);
    694                     break;
    695                 case WifiP2pManager.INITIATOR_REPORT_NFC_HANDOVER:
    696                 case WifiP2pManager.RESPONDER_REPORT_NFC_HANDOVER:
    697                     replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_FAILED,
    698                             WifiP2pManager.BUSY);
    699                     break;
    700                     // Ignore
    701                 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
    702                 case WifiMonitor.SCAN_RESULTS_EVENT:
    703                 case WifiMonitor.SUP_CONNECTION_EVENT:
    704                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
    705                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
    706                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
    707                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
    708                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
    709                 case WifiMonitor.WPS_SUCCESS_EVENT:
    710                 case WifiMonitor.WPS_FAIL_EVENT:
    711                 case WifiMonitor.WPS_OVERLAP_EVENT:
    712                 case WifiMonitor.WPS_TIMEOUT_EVENT:
    713                 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
    714                 case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
    715                 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
    716                 case WifiMonitor.P2P_FIND_STOPPED_EVENT:
    717                 case WifiMonitor.P2P_SERV_DISC_RESP_EVENT:
    718                 case PEER_CONNECTION_USER_ACCEPT:
    719                 case PEER_CONNECTION_USER_REJECT:
    720                 case DISCONNECT_WIFI_RESPONSE:
    721                 case DROP_WIFI_USER_ACCEPT:
    722                 case DROP_WIFI_USER_REJECT:
    723                 case GROUP_CREATING_TIMED_OUT:
    724                 case DISABLE_P2P_TIMED_OUT:
    725                 case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
    726                 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
    727                 case DhcpStateMachine.CMD_ON_QUIT:
    728                 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
    729                 case SET_MIRACAST_MODE:
    730                 case WifiP2pManager.START_LISTEN:
    731                 case WifiP2pManager.STOP_LISTEN:
    732                 case WifiP2pManager.SET_CHANNEL:
    733                 case SET_COUNTRY_CODE:
    734                     break;
    735                 case WifiStateMachine.CMD_ENABLE_P2P:
    736                     // Enable is lazy and has no response
    737                     break;
    738                 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
    739                     // If we end up handling in default, p2p is not enabled
    740                     mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP);
    741                     break;
    742                     /* unexpected group created, remove */
    743                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
    744                     mGroup = (WifiP2pGroup) message.obj;
    745                     loge("Unexpected group creation, remove " + mGroup);
    746                     mWifiNative.p2pGroupRemove(mGroup.getInterface());
    747                     break;
    748                 // A group formation failure is always followed by
    749                 // a group removed event. Flushing things at group formation
    750                 // failure causes supplicant issues. Ignore right now.
    751                 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
    752                     break;
    753                 default:
    754                     loge("Unhandled message " + message);
    755                     return NOT_HANDLED;
    756             }
    757             return HANDLED;
    758         }
    759     }
    760 
    761     class P2pNotSupportedState extends State {
    762         @Override
    763         public boolean processMessage(Message message) {
    764             switch (message.what) {
    765                case WifiP2pManager.DISCOVER_PEERS:
    766                     replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
    767                             WifiP2pManager.P2P_UNSUPPORTED);
    768                     break;
    769                 case WifiP2pManager.STOP_DISCOVERY:
    770                     replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
    771                             WifiP2pManager.P2P_UNSUPPORTED);
    772                     break;
    773                 case WifiP2pManager.DISCOVER_SERVICES:
    774                     replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
    775                             WifiP2pManager.P2P_UNSUPPORTED);
    776                     break;
    777                 case WifiP2pManager.CONNECT:
    778                     replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
    779                             WifiP2pManager.P2P_UNSUPPORTED);
    780                     break;
    781                 case WifiP2pManager.CANCEL_CONNECT:
    782                     replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
    783                             WifiP2pManager.P2P_UNSUPPORTED);
    784                     break;
    785                case WifiP2pManager.CREATE_GROUP:
    786                     replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
    787                             WifiP2pManager.P2P_UNSUPPORTED);
    788                     break;
    789                 case WifiP2pManager.REMOVE_GROUP:
    790                     replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
    791                             WifiP2pManager.P2P_UNSUPPORTED);
    792                     break;
    793                 case WifiP2pManager.ADD_LOCAL_SERVICE:
    794                     replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED,
    795                             WifiP2pManager.P2P_UNSUPPORTED);
    796                     break;
    797                 case WifiP2pManager.REMOVE_LOCAL_SERVICE:
    798                     replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED,
    799                             WifiP2pManager.P2P_UNSUPPORTED);
    800                     break;
    801                 case WifiP2pManager.CLEAR_LOCAL_SERVICES:
    802                     replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED,
    803                             WifiP2pManager.P2P_UNSUPPORTED);
    804                     break;
    805                 case WifiP2pManager.ADD_SERVICE_REQUEST:
    806                     replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED,
    807                             WifiP2pManager.P2P_UNSUPPORTED);
    808                     break;
    809                 case WifiP2pManager.REMOVE_SERVICE_REQUEST:
    810                     replyToMessage(message,
    811                             WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED,
    812                             WifiP2pManager.P2P_UNSUPPORTED);
    813                     break;
    814                 case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
    815                     replyToMessage(message,
    816                             WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED,
    817                             WifiP2pManager.P2P_UNSUPPORTED);
    818                     break;
    819                 case WifiP2pManager.SET_DEVICE_NAME:
    820                     replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
    821                             WifiP2pManager.P2P_UNSUPPORTED);
    822                     break;
    823                 case WifiP2pManager.DELETE_PERSISTENT_GROUP:
    824                     replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP,
    825                             WifiP2pManager.P2P_UNSUPPORTED);
    826                     break;
    827                 case WifiP2pManager.SET_WFD_INFO:
    828                     replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
    829                             WifiP2pManager.P2P_UNSUPPORTED);
    830                     break;
    831                 case WifiP2pManager.START_WPS:
    832                     replyToMessage(message, WifiP2pManager.START_WPS_FAILED,
    833                             WifiP2pManager.P2P_UNSUPPORTED);
    834                     break;
    835                 case WifiP2pManager.START_LISTEN:
    836                     replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED,
    837                             WifiP2pManager.P2P_UNSUPPORTED);
    838                     break;
    839                 case WifiP2pManager.STOP_LISTEN:
    840                     replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED,
    841                             WifiP2pManager.P2P_UNSUPPORTED);
    842                     break;
    843 
    844                 default:
    845                     return NOT_HANDLED;
    846             }
    847             return HANDLED;
    848         }
    849     }
    850 
    851     class P2pDisablingState extends State {
    852         @Override
    853         public void enter() {
    854             if (DBG) logd(getName());
    855             sendMessageDelayed(obtainMessage(DISABLE_P2P_TIMED_OUT,
    856                     ++mDisableP2pTimeoutIndex, 0), DISABLE_P2P_WAIT_TIME_MS);
    857         }
    858 
    859         @Override
    860         public boolean processMessage(Message message) {
    861             if (DBG) logd(getName() + message.toString());
    862             switch (message.what) {
    863                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
    864                     if (DBG) logd("p2p socket connection lost");
    865                     transitionTo(mP2pDisabledState);
    866                     break;
    867                 case WifiStateMachine.CMD_ENABLE_P2P:
    868                 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
    869                     deferMessage(message);
    870                     break;
    871                 case DISABLE_P2P_TIMED_OUT:
    872                     if (mDisableP2pTimeoutIndex == message.arg1) {
    873                         loge("P2p disable timed out");
    874                         transitionTo(mP2pDisabledState);
    875                     }
    876                     break;
    877                 default:
    878                     return NOT_HANDLED;
    879             }
    880             return HANDLED;
    881         }
    882 
    883         @Override
    884         public void exit() {
    885             mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP);
    886         }
    887     }
    888 
    889     class P2pDisabledState extends State {
    890        @Override
    891         public void enter() {
    892             if (DBG) logd(getName());
    893         }
    894 
    895         @Override
    896         public boolean processMessage(Message message) {
    897             if (DBG) logd(getName() + message.toString());
    898             switch (message.what) {
    899                 case WifiStateMachine.CMD_ENABLE_P2P:
    900                     try {
    901                         mNwService.setInterfaceUp(mInterface);
    902                     } catch (RemoteException re) {
    903                         loge("Unable to change interface settings: " + re);
    904                     } catch (IllegalStateException ie) {
    905                         loge("Unable to change interface settings: " + ie);
    906                     }
    907                     mWifiMonitor.startMonitoring();
    908                     transitionTo(mP2pEnablingState);
    909                     break;
    910                 default:
    911                     return NOT_HANDLED;
    912             }
    913             return HANDLED;
    914         }
    915     }
    916 
    917     class P2pEnablingState extends State {
    918         @Override
    919         public void enter() {
    920             if (DBG) logd(getName());
    921         }
    922 
    923         @Override
    924         public boolean processMessage(Message message) {
    925             if (DBG) logd(getName() + message.toString());
    926             switch (message.what) {
    927                 case WifiMonitor.SUP_CONNECTION_EVENT:
    928                     if (DBG) logd("P2p socket connection successful");
    929                     transitionTo(mInactiveState);
    930                     break;
    931                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
    932                     loge("P2p socket connection failed");
    933                     transitionTo(mP2pDisabledState);
    934                     break;
    935                 case WifiStateMachine.CMD_ENABLE_P2P:
    936                 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
    937                     deferMessage(message);
    938                     break;
    939                 default:
    940                     return NOT_HANDLED;
    941             }
    942             return HANDLED;
    943         }
    944     }
    945 
    946     class P2pEnabledState extends State {
    947         @Override
    948         public void enter() {
    949             if (DBG) logd(getName());
    950             sendP2pStateChangedBroadcast(true);
    951             mNetworkInfo.setIsAvailable(true);
    952             sendP2pConnectionChangedBroadcast();
    953             initializeP2pSettings();
    954         }
    955 
    956         @Override
    957         public boolean processMessage(Message message) {
    958             if (DBG) logd(getName() + message.toString());
    959             switch (message.what) {
    960                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
    961                     loge("Unexpected loss of p2p socket connection");
    962                     transitionTo(mP2pDisabledState);
    963                     break;
    964                 case WifiStateMachine.CMD_ENABLE_P2P:
    965                     //Nothing to do
    966                     break;
    967                 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
    968                     if (mPeers.clear()) {
    969                         sendPeersChangedBroadcast();
    970                     }
    971                     if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast();
    972 
    973                     mWifiMonitor.stopMonitoring();
    974                     transitionTo(mP2pDisablingState);
    975                     break;
    976                 case WifiP2pManager.SET_DEVICE_NAME:
    977                 {
    978                     WifiP2pDevice d = (WifiP2pDevice) message.obj;
    979                     if (d != null && setAndPersistDeviceName(d.deviceName)) {
    980                         if (DBG) logd("set device name " + d.deviceName);
    981                         replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_SUCCEEDED);
    982                     } else {
    983                         replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
    984                                 WifiP2pManager.ERROR);
    985                     }
    986                     break;
    987                 }
    988                 case WifiP2pManager.SET_WFD_INFO:
    989                 {
    990                     WifiP2pWfdInfo d = (WifiP2pWfdInfo) message.obj;
    991                     if (d != null && setWfdInfo(d)) {
    992                         replyToMessage(message, WifiP2pManager.SET_WFD_INFO_SUCCEEDED);
    993                     } else {
    994                         replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
    995                                 WifiP2pManager.ERROR);
    996                     }
    997                     break;
    998                 }
    999                 case BLOCK_DISCOVERY:
   1000                     boolean blocked = (message.arg1 == ENABLED ? true : false);
   1001                     if (mDiscoveryBlocked == blocked) break;
   1002                     mDiscoveryBlocked = blocked;
   1003                     if (blocked && mDiscoveryStarted) {
   1004                         mWifiNative.p2pStopFind();
   1005                         mDiscoveryPostponed = true;
   1006                     }
   1007                     if (!blocked && mDiscoveryPostponed) {
   1008                         mDiscoveryPostponed = false;
   1009                         mWifiNative.p2pFind(DISCOVER_TIMEOUT_S);
   1010                     }
   1011                     if (blocked) {
   1012                         try {
   1013                             StateMachine m = (StateMachine)message.obj;
   1014                             m.sendMessage(message.arg2);
   1015                         } catch (Exception e) {
   1016                             loge("unable to send BLOCK_DISCOVERY response: " + e);
   1017                         }
   1018                     }
   1019                     break;
   1020                 case WifiP2pManager.DISCOVER_PEERS:
   1021                     if (mDiscoveryBlocked) {
   1022                         replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
   1023                                 WifiP2pManager.BUSY);
   1024                         break;
   1025                     }
   1026                     // do not send service discovery request while normal find operation.
   1027                     clearSupplicantServiceRequest();
   1028                     if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {
   1029                         replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED);
   1030                         sendP2pDiscoveryChangedBroadcast(true);
   1031                     } else {
   1032                         replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
   1033                                 WifiP2pManager.ERROR);
   1034                     }
   1035                     break;
   1036                 case WifiMonitor.P2P_FIND_STOPPED_EVENT:
   1037                     sendP2pDiscoveryChangedBroadcast(false);
   1038                     break;
   1039                 case WifiP2pManager.STOP_DISCOVERY:
   1040                     if (mWifiNative.p2pStopFind()) {
   1041                         replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED);
   1042                     } else {
   1043                         replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
   1044                                 WifiP2pManager.ERROR);
   1045                     }
   1046                     break;
   1047                 case WifiP2pManager.DISCOVER_SERVICES:
   1048                     if (mDiscoveryBlocked) {
   1049                         replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
   1050                                 WifiP2pManager.BUSY);
   1051                         break;
   1052                     }
   1053                     if (DBG) logd(getName() + " discover services");
   1054                     if (!updateSupplicantServiceRequest()) {
   1055                         replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
   1056                                 WifiP2pManager.NO_SERVICE_REQUESTS);
   1057                         break;
   1058                     }
   1059                     if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {
   1060                         replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_SUCCEEDED);
   1061                     } else {
   1062                         replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
   1063                                 WifiP2pManager.ERROR);
   1064                     }
   1065                     break;
   1066                 case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
   1067                     WifiP2pDevice device = (WifiP2pDevice) message.obj;
   1068                     if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break;
   1069                     mPeers.updateSupplicantDetails(device);
   1070                     sendPeersChangedBroadcast();
   1071                     break;
   1072                 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
   1073                     device = (WifiP2pDevice) message.obj;
   1074                     // Gets current details for the one removed
   1075                     device = mPeers.remove(device.deviceAddress);
   1076                     if (device != null) {
   1077                         sendPeersChangedBroadcast();
   1078                     }
   1079                     break;
   1080                 case WifiP2pManager.ADD_LOCAL_SERVICE:
   1081                     if (DBG) logd(getName() + " add service");
   1082                     WifiP2pServiceInfo servInfo = (WifiP2pServiceInfo)message.obj;
   1083                     if (addLocalService(message.replyTo, servInfo)) {
   1084                         replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_SUCCEEDED);
   1085                     } else {
   1086                         replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED);
   1087                     }
   1088                     break;
   1089                 case WifiP2pManager.REMOVE_LOCAL_SERVICE:
   1090                     if (DBG) logd(getName() + " remove service");
   1091                     servInfo = (WifiP2pServiceInfo)message.obj;
   1092                     removeLocalService(message.replyTo, servInfo);
   1093                     replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_SUCCEEDED);
   1094                     break;
   1095                 case WifiP2pManager.CLEAR_LOCAL_SERVICES:
   1096                     if (DBG) logd(getName() + " clear service");
   1097                     clearLocalServices(message.replyTo);
   1098                     replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_SUCCEEDED);
   1099                     break;
   1100                 case WifiP2pManager.ADD_SERVICE_REQUEST:
   1101                     if (DBG) logd(getName() + " add service request");
   1102                     if (!addServiceRequest(message.replyTo, (WifiP2pServiceRequest)message.obj)) {
   1103                         replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED);
   1104                         break;
   1105                     }
   1106                     replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_SUCCEEDED);
   1107                     break;
   1108                 case WifiP2pManager.REMOVE_SERVICE_REQUEST:
   1109                     if (DBG) logd(getName() + " remove service request");
   1110                     removeServiceRequest(message.replyTo, (WifiP2pServiceRequest)message.obj);
   1111                     replyToMessage(message, WifiP2pManager.REMOVE_SERVICE_REQUEST_SUCCEEDED);
   1112                     break;
   1113                 case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
   1114                     if (DBG) logd(getName() + " clear service request");
   1115                     clearServiceRequests(message.replyTo);
   1116                     replyToMessage(message, WifiP2pManager.CLEAR_SERVICE_REQUESTS_SUCCEEDED);
   1117                     break;
   1118                 case WifiMonitor.P2P_SERV_DISC_RESP_EVENT:
   1119                     if (DBG) logd(getName() + " receive service response");
   1120                     List<WifiP2pServiceResponse> sdRespList =
   1121                         (List<WifiP2pServiceResponse>) message.obj;
   1122                     for (WifiP2pServiceResponse resp : sdRespList) {
   1123                         WifiP2pDevice dev =
   1124                             mPeers.get(resp.getSrcDevice().deviceAddress);
   1125                         resp.setSrcDevice(dev);
   1126                         sendServiceResponse(resp);
   1127                     }
   1128                     break;
   1129                 case WifiP2pManager.DELETE_PERSISTENT_GROUP:
   1130                    if (DBG) logd(getName() + " delete persistent group");
   1131                    mGroups.remove(message.arg1);
   1132                    replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP_SUCCEEDED);
   1133                    break;
   1134                 case SET_MIRACAST_MODE:
   1135                     mWifiNative.setMiracastMode(message.arg1);
   1136                     break;
   1137                 case WifiP2pManager.START_LISTEN:
   1138                     if (DBG) logd(getName() + " start listen mode");
   1139                     mWifiNative.p2pFlush();
   1140                     if (mWifiNative.p2pExtListen(true, 500, 500)) {
   1141                         replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED);
   1142                     } else {
   1143                         replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED);
   1144                     }
   1145                     break;
   1146                 case WifiP2pManager.STOP_LISTEN:
   1147                     if (DBG) logd(getName() + " stop listen mode");
   1148                     if (mWifiNative.p2pExtListen(false, 0, 0)) {
   1149                         replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED);
   1150                     } else {
   1151                         replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED);
   1152                     }
   1153                     mWifiNative.p2pFlush();
   1154                     break;
   1155                 case WifiP2pManager.SET_CHANNEL:
   1156                     Bundle p2pChannels = (Bundle) message.obj;
   1157                     int lc = p2pChannels.getInt("lc", 0);
   1158                     int oc = p2pChannels.getInt("oc", 0);
   1159                     if (DBG) logd(getName() + " set listen and operating channel");
   1160                     if (mWifiNative.p2pSetChannel(lc, oc)) {
   1161                         replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED);
   1162                     } else {
   1163                         replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED);
   1164                     }
   1165                     break;
   1166                 case SET_COUNTRY_CODE:
   1167                     String countryCode = (String) message.obj;
   1168                     countryCode = countryCode.toUpperCase(Locale.ROOT);
   1169                     if (mLastSetCountryCode == null ||
   1170                             countryCode.equals(mLastSetCountryCode) == false) {
   1171                         if (mWifiNative.setCountryCode(countryCode)) {
   1172                             mLastSetCountryCode = countryCode;
   1173                         }
   1174                     }
   1175                     break;
   1176                 case WifiP2pManager.GET_HANDOVER_REQUEST:
   1177                     Bundle requestBundle = new Bundle();
   1178                     requestBundle.putString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE,
   1179                             mWifiNative.getNfcHandoverRequest());
   1180                     replyToMessage(message, WifiP2pManager.RESPONSE_GET_HANDOVER_MESSAGE,
   1181                             requestBundle);
   1182                     break;
   1183                 case WifiP2pManager.GET_HANDOVER_SELECT:
   1184                     Bundle selectBundle = new Bundle();
   1185                     selectBundle.putString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE,
   1186                             mWifiNative.getNfcHandoverSelect());
   1187                     replyToMessage(message, WifiP2pManager.RESPONSE_GET_HANDOVER_MESSAGE,
   1188                             selectBundle);
   1189                     break;
   1190                 default:
   1191                    return NOT_HANDLED;
   1192             }
   1193             return HANDLED;
   1194         }
   1195 
   1196         @Override
   1197         public void exit() {
   1198             sendP2pDiscoveryChangedBroadcast(false);
   1199             sendP2pStateChangedBroadcast(false);
   1200             mNetworkInfo.setIsAvailable(false);
   1201 
   1202             mLastSetCountryCode = null;
   1203         }
   1204     }
   1205 
   1206     class InactiveState extends State {
   1207         @Override
   1208         public void enter() {
   1209             if (DBG) logd(getName());
   1210             mSavedPeerConfig.invalidate();
   1211         }
   1212 
   1213         @Override
   1214         public boolean processMessage(Message message) {
   1215             if (DBG) logd(getName() + message.toString());
   1216             switch (message.what) {
   1217                 case WifiP2pManager.CONNECT:
   1218                     if (DBG) logd(getName() + " sending connect");
   1219                     WifiP2pConfig config = (WifiP2pConfig) message.obj;
   1220                     if (isConfigInvalid(config)) {
   1221                         loge("Dropping connect requeset " + config);
   1222                         replyToMessage(message, WifiP2pManager.CONNECT_FAILED);
   1223                         break;
   1224                     }
   1225 
   1226                     mAutonomousGroup = false;
   1227                     mWifiNative.p2pStopFind();
   1228                     if (reinvokePersistentGroup(config)) {
   1229                         transitionTo(mGroupNegotiationState);
   1230                     } else {
   1231                         transitionTo(mProvisionDiscoveryState);
   1232                     }
   1233                     mSavedPeerConfig = config;
   1234                     mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
   1235                     sendPeersChangedBroadcast();
   1236                     replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
   1237                     break;
   1238                 case WifiP2pManager.STOP_DISCOVERY:
   1239                     if (mWifiNative.p2pStopFind()) {
   1240                         // When discovery stops in inactive state, flush to clear
   1241                         // state peer data
   1242                         mWifiNative.p2pFlush();
   1243                         mServiceDiscReqId = null;
   1244                         replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED);
   1245                     } else {
   1246                         replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
   1247                                 WifiP2pManager.ERROR);
   1248                     }
   1249                     break;
   1250                 case WifiMonitor.P2P_GO_NEGOTIATION_REQUEST_EVENT:
   1251                     config = (WifiP2pConfig) message.obj;
   1252                     if (isConfigInvalid(config)) {
   1253                         loge("Dropping GO neg request " + config);
   1254                         break;
   1255                     }
   1256                     mSavedPeerConfig = config;
   1257                     mAutonomousGroup = false;
   1258                     mJoinExistingGroup = false;
   1259                     transitionTo(mUserAuthorizingNegotiationRequestState);
   1260                     break;
   1261                 case WifiMonitor.P2P_INVITATION_RECEIVED_EVENT:
   1262                     WifiP2pGroup group = (WifiP2pGroup) message.obj;
   1263                     WifiP2pDevice owner = group.getOwner();
   1264 
   1265                     if (owner == null) {
   1266                         loge("Ignored invitation from null owner");
   1267                         break;
   1268                     }
   1269 
   1270                     config = new WifiP2pConfig();
   1271                     config.deviceAddress = group.getOwner().deviceAddress;
   1272 
   1273                     if (isConfigInvalid(config)) {
   1274                         loge("Dropping invitation request " + config);
   1275                         break;
   1276                     }
   1277                     mSavedPeerConfig = config;
   1278 
   1279                     //Check if we have the owner in peer list and use appropriate
   1280                     //wps method. Default is to use PBC.
   1281                     if ((owner = mPeers.get(owner.deviceAddress)) != null) {
   1282                         if (owner.wpsPbcSupported()) {
   1283                             mSavedPeerConfig.wps.setup = WpsInfo.PBC;
   1284                         } else if (owner.wpsKeypadSupported()) {
   1285                             mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD;
   1286                         } else if (owner.wpsDisplaySupported()) {
   1287                             mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;
   1288                         }
   1289                     }
   1290 
   1291                     mAutonomousGroup = false;
   1292                     mJoinExistingGroup = true;
   1293                     transitionTo(mUserAuthorizingInviteRequestState);
   1294                     break;
   1295                 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
   1296                 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
   1297                 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
   1298                     //We let the supplicant handle the provision discovery response
   1299                     //and wait instead for the GO_NEGOTIATION_REQUEST_EVENT.
   1300                     //Handling provision discovery and issuing a p2p_connect before
   1301                     //group negotiation comes through causes issues
   1302                     break;
   1303                 case WifiP2pManager.CREATE_GROUP:
   1304                     mAutonomousGroup = true;
   1305                     int netId = message.arg1;
   1306                     boolean ret = false;
   1307                     if (netId == WifiP2pGroup.PERSISTENT_NET_ID) {
   1308                         // check if the go persistent group is present.
   1309                         netId = mGroups.getNetworkId(mThisDevice.deviceAddress);
   1310                         if (netId != -1) {
   1311                             ret = mWifiNative.p2pGroupAdd(netId);
   1312                         } else {
   1313                             ret = mWifiNative.p2pGroupAdd(true);
   1314                         }
   1315                     } else {
   1316                         ret = mWifiNative.p2pGroupAdd(false);
   1317                     }
   1318 
   1319                     if (ret) {
   1320                         replyToMessage(message, WifiP2pManager.CREATE_GROUP_SUCCEEDED);
   1321                         transitionTo(mGroupNegotiationState);
   1322                     } else {
   1323                         replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
   1324                                 WifiP2pManager.ERROR);
   1325                         // remain at this state.
   1326                     }
   1327                     break;
   1328                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
   1329                     mGroup = (WifiP2pGroup) message.obj;
   1330                     if (DBG) logd(getName() + " group started");
   1331 
   1332                     // We hit this scenario when a persistent group is reinvoked
   1333                     if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) {
   1334                         mAutonomousGroup = false;
   1335                         deferMessage(message);
   1336                         transitionTo(mGroupNegotiationState);
   1337                     } else {
   1338                         loge("Unexpected group creation, remove " + mGroup);
   1339                         mWifiNative.p2pGroupRemove(mGroup.getInterface());
   1340                     }
   1341                     break;
   1342                 case WifiP2pManager.START_LISTEN:
   1343                     if (DBG) logd(getName() + " start listen mode");
   1344                     mWifiNative.p2pFlush();
   1345                     if (mWifiNative.p2pExtListen(true, 500, 500)) {
   1346                         replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED);
   1347                     } else {
   1348                         replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED);
   1349                     }
   1350                     break;
   1351                 case WifiP2pManager.STOP_LISTEN:
   1352                     if (DBG) logd(getName() + " stop listen mode");
   1353                     if (mWifiNative.p2pExtListen(false, 0, 0)) {
   1354                         replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED);
   1355                     } else {
   1356                         replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED);
   1357                     }
   1358                     mWifiNative.p2pFlush();
   1359                     break;
   1360                 case WifiP2pManager.SET_CHANNEL:
   1361                     Bundle p2pChannels = (Bundle) message.obj;
   1362                     int lc = p2pChannels.getInt("lc", 0);
   1363                     int oc = p2pChannels.getInt("oc", 0);
   1364                     if (DBG) logd(getName() + " set listen and operating channel");
   1365                     if (mWifiNative.p2pSetChannel(lc, oc)) {
   1366                         replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED);
   1367                     } else {
   1368                         replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED);
   1369                     }
   1370                     break;
   1371                 case WifiP2pManager.INITIATOR_REPORT_NFC_HANDOVER:
   1372                     String handoverSelect = null;
   1373 
   1374                     if (message.obj != null) {
   1375                         handoverSelect = ((Bundle) message.obj)
   1376                                 .getString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE);
   1377                     }
   1378 
   1379                     if (handoverSelect != null
   1380                             && mWifiNative.initiatorReportNfcHandover(handoverSelect)) {
   1381                         replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_SUCCEEDED);
   1382                         transitionTo(mGroupCreatingState);
   1383                     } else {
   1384                         replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_FAILED);
   1385                     }
   1386                     break;
   1387                 case WifiP2pManager.RESPONDER_REPORT_NFC_HANDOVER:
   1388                     String handoverRequest = null;
   1389 
   1390                     if (message.obj != null) {
   1391                         handoverRequest = ((Bundle) message.obj)
   1392                                 .getString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE);
   1393                     }
   1394 
   1395                     if (handoverRequest != null
   1396                             && mWifiNative.responderReportNfcHandover(handoverRequest)) {
   1397                         replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_SUCCEEDED);
   1398                         transitionTo(mGroupCreatingState);
   1399                     } else {
   1400                         replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_FAILED);
   1401                     }
   1402                     break;
   1403                 default:
   1404                     return NOT_HANDLED;
   1405             }
   1406             return HANDLED;
   1407         }
   1408     }
   1409 
   1410     class GroupCreatingState extends State {
   1411         @Override
   1412         public void enter() {
   1413             if (DBG) logd(getName());
   1414             sendMessageDelayed(obtainMessage(GROUP_CREATING_TIMED_OUT,
   1415                     ++mGroupCreatingTimeoutIndex, 0), GROUP_CREATING_WAIT_TIME_MS);
   1416         }
   1417 
   1418         @Override
   1419         public boolean processMessage(Message message) {
   1420             if (DBG) logd(getName() + message.toString());
   1421             boolean ret = HANDLED;
   1422             switch (message.what) {
   1423                case GROUP_CREATING_TIMED_OUT:
   1424                     if (mGroupCreatingTimeoutIndex == message.arg1) {
   1425                         if (DBG) logd("Group negotiation timed out");
   1426                         handleGroupCreationFailure();
   1427                         transitionTo(mInactiveState);
   1428                     }
   1429                     break;
   1430                 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
   1431                     WifiP2pDevice device = (WifiP2pDevice) message.obj;
   1432                     if (!mSavedPeerConfig.deviceAddress.equals(device.deviceAddress)) {
   1433                         if (DBG) {
   1434                             logd("mSavedPeerConfig " + mSavedPeerConfig.deviceAddress +
   1435                                 "device " + device.deviceAddress);
   1436                         }
   1437                         // Do the regular device lost handling
   1438                         ret = NOT_HANDLED;
   1439                         break;
   1440                     }
   1441                     // Do nothing
   1442                     if (DBG) logd("Add device to lost list " + device);
   1443                     mPeersLostDuringConnection.updateSupplicantDetails(device);
   1444                     break;
   1445                 case WifiP2pManager.DISCOVER_PEERS:
   1446                     /* Discovery will break negotiation */
   1447                     replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
   1448                             WifiP2pManager.BUSY);
   1449                     break;
   1450                 case WifiP2pManager.CANCEL_CONNECT:
   1451                     //Do a supplicant p2p_cancel which only cancels an ongoing
   1452                     //group negotiation. This will fail for a pending provision
   1453                     //discovery or for a pending user action, but at the framework
   1454                     //level, we always treat cancel as succeeded and enter
   1455                     //an inactive state
   1456                     mWifiNative.p2pCancelConnect();
   1457                     handleGroupCreationFailure();
   1458                     transitionTo(mInactiveState);
   1459                     replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_SUCCEEDED);
   1460                     break;
   1461                 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
   1462                     // We hit this scenario when NFC handover is invoked.
   1463                     mAutonomousGroup = false;
   1464                     transitionTo(mGroupNegotiationState);
   1465                     break;
   1466                 default:
   1467                     ret = NOT_HANDLED;
   1468             }
   1469             return ret;
   1470         }
   1471     }
   1472 
   1473     class UserAuthorizingNegotiationRequestState extends State {
   1474         @Override
   1475         public void enter() {
   1476             if (DBG) logd(getName());
   1477             notifyInvitationReceived();
   1478         }
   1479 
   1480         @Override
   1481         public boolean processMessage(Message message) {
   1482             if (DBG) logd(getName() + message.toString());
   1483             boolean ret = HANDLED;
   1484             switch (message.what) {
   1485                 case PEER_CONNECTION_USER_ACCEPT:
   1486                     mWifiNative.p2pStopFind();
   1487                     p2pConnectWithPinDisplay(mSavedPeerConfig);
   1488                     mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
   1489                     sendPeersChangedBroadcast();
   1490                     transitionTo(mGroupNegotiationState);
   1491                    break;
   1492                 case PEER_CONNECTION_USER_REJECT:
   1493                     if (DBG) logd("User rejected negotiation " + mSavedPeerConfig);
   1494                     transitionTo(mInactiveState);
   1495                     break;
   1496                 default:
   1497                     return NOT_HANDLED;
   1498             }
   1499             return ret;
   1500         }
   1501 
   1502         @Override
   1503         public void exit() {
   1504             //TODO: dismiss dialog if not already done
   1505         }
   1506     }
   1507 
   1508     class UserAuthorizingInviteRequestState extends State {
   1509         @Override
   1510         public void enter() {
   1511             if (DBG) logd(getName());
   1512             notifyInvitationReceived();
   1513         }
   1514 
   1515         @Override
   1516         public boolean processMessage(Message message) {
   1517             if (DBG) logd(getName() + message.toString());
   1518             boolean ret = HANDLED;
   1519             switch (message.what) {
   1520                 case PEER_CONNECTION_USER_ACCEPT:
   1521                     mWifiNative.p2pStopFind();
   1522                     if (!reinvokePersistentGroup(mSavedPeerConfig)) {
   1523                         // Do negotiation when persistence fails
   1524                         p2pConnectWithPinDisplay(mSavedPeerConfig);
   1525                     }
   1526                     mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
   1527                     sendPeersChangedBroadcast();
   1528                     transitionTo(mGroupNegotiationState);
   1529                    break;
   1530                 case PEER_CONNECTION_USER_REJECT:
   1531                     if (DBG) logd("User rejected invitation " + mSavedPeerConfig);
   1532                     transitionTo(mInactiveState);
   1533                     break;
   1534                 default:
   1535                     return NOT_HANDLED;
   1536             }
   1537             return ret;
   1538         }
   1539 
   1540         @Override
   1541         public void exit() {
   1542             //TODO: dismiss dialog if not already done
   1543         }
   1544     }
   1545 
   1546 
   1547 
   1548     class ProvisionDiscoveryState extends State {
   1549         @Override
   1550         public void enter() {
   1551             if (DBG) logd(getName());
   1552             mWifiNative.p2pProvisionDiscovery(mSavedPeerConfig);
   1553         }
   1554 
   1555         @Override
   1556         public boolean processMessage(Message message) {
   1557             if (DBG) logd(getName() + message.toString());
   1558             WifiP2pProvDiscEvent provDisc;
   1559             WifiP2pDevice device;
   1560             switch (message.what) {
   1561                 case WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT:
   1562                     provDisc = (WifiP2pProvDiscEvent) message.obj;
   1563                     device = provDisc.device;
   1564                     if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
   1565 
   1566                     if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
   1567                         if (DBG) logd("Found a match " + mSavedPeerConfig);
   1568                         p2pConnectWithPinDisplay(mSavedPeerConfig);
   1569                         transitionTo(mGroupNegotiationState);
   1570                     }
   1571                     break;
   1572                 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
   1573                     provDisc = (WifiP2pProvDiscEvent) message.obj;
   1574                     device = provDisc.device;
   1575                     if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
   1576 
   1577                     if (mSavedPeerConfig.wps.setup == WpsInfo.KEYPAD) {
   1578                         if (DBG) logd("Found a match " + mSavedPeerConfig);
   1579                         /* we already have the pin */
   1580                         if (!TextUtils.isEmpty(mSavedPeerConfig.wps.pin)) {
   1581                             p2pConnectWithPinDisplay(mSavedPeerConfig);
   1582                             transitionTo(mGroupNegotiationState);
   1583                         } else {
   1584                             mJoinExistingGroup = false;
   1585                             transitionTo(mUserAuthorizingNegotiationRequestState);
   1586                         }
   1587                     }
   1588                     break;
   1589                 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
   1590                     provDisc = (WifiP2pProvDiscEvent) message.obj;
   1591                     device = provDisc.device;
   1592                     if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
   1593 
   1594                     if (mSavedPeerConfig.wps.setup == WpsInfo.DISPLAY) {
   1595                         if (DBG) logd("Found a match " + mSavedPeerConfig);
   1596                         mSavedPeerConfig.wps.pin = provDisc.pin;
   1597                         p2pConnectWithPinDisplay(mSavedPeerConfig);
   1598                         notifyInvitationSent(provDisc.pin, device.deviceAddress);
   1599                         transitionTo(mGroupNegotiationState);
   1600                     }
   1601                     break;
   1602                 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
   1603                     loge("provision discovery failed");
   1604                     handleGroupCreationFailure();
   1605                     transitionTo(mInactiveState);
   1606                     break;
   1607                 default:
   1608                     return NOT_HANDLED;
   1609             }
   1610             return HANDLED;
   1611         }
   1612     }
   1613 
   1614     class GroupNegotiationState extends State {
   1615         @Override
   1616         public void enter() {
   1617             if (DBG) logd(getName());
   1618         }
   1619 
   1620         @Override
   1621         public boolean processMessage(Message message) {
   1622             if (DBG) logd(getName() + message.toString());
   1623             switch (message.what) {
   1624                 // We ignore these right now, since we get a GROUP_STARTED notification
   1625                 // afterwards
   1626                 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
   1627                 case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:
   1628                     if (DBG) logd(getName() + " go success");
   1629                     break;
   1630                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
   1631                     mGroup = (WifiP2pGroup) message.obj;
   1632                     if (DBG) logd(getName() + " group started");
   1633 
   1634                     if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) {
   1635                         /*
   1636                          * update cache information and set network id to mGroup.
   1637                          */
   1638                         updatePersistentNetworks(NO_RELOAD);
   1639                         String devAddr = mGroup.getOwner().deviceAddress;
   1640                         mGroup.setNetworkId(mGroups.getNetworkId(devAddr,
   1641                                 mGroup.getNetworkName()));
   1642                     }
   1643 
   1644                     if (mGroup.isGroupOwner()) {
   1645                         /* Setting an idle time out on GO causes issues with certain scenarios
   1646                          * on clients where it can be off-channel for longer and with the power
   1647                          * save modes used.
   1648                          *
   1649                          * TODO: Verify multi-channel scenarios and supplicant behavior are
   1650                          * better before adding a time out in future
   1651                          */
   1652                         //Set group idle timeout of 10 sec, to avoid GO beaconing incase of any
   1653                         //failure during 4-way Handshake.
   1654                         if (!mAutonomousGroup) {
   1655                             mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);
   1656                         }
   1657                         startDhcpServer(mGroup.getInterface());
   1658                     } else {
   1659                         mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);
   1660                         mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(mContext,
   1661                                 P2pStateMachine.this, mGroup.getInterface());
   1662                         // TODO: We should use DHCP state machine PRE message like WifiStateMachine
   1663                         mWifiNative.setP2pPowerSave(mGroup.getInterface(), false);
   1664                         mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
   1665                         WifiP2pDevice groupOwner = mGroup.getOwner();
   1666                         WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress);
   1667                         if (peer != null) {
   1668                             // update group owner details with peer details found at discovery
   1669                             groupOwner.updateSupplicantDetails(peer);
   1670                             mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED);
   1671                             sendPeersChangedBroadcast();
   1672                         } else {
   1673                             // A supplicant bug can lead to reporting an invalid
   1674                             // group owner address (all zeroes) at times. Avoid a
   1675                             // crash, but continue group creation since it is not
   1676                             // essential.
   1677                             logw("Unknown group owner " + groupOwner);
   1678                         }
   1679                     }
   1680                     transitionTo(mGroupCreatedState);
   1681                     break;
   1682                 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
   1683                     P2pStatus status = (P2pStatus) message.obj;
   1684                     if (status == P2pStatus.NO_COMMON_CHANNEL) {
   1685                         transitionTo(mFrequencyConflictState);
   1686                         break;
   1687                     }
   1688                     /* continue with group removal handling */
   1689                 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
   1690                     if (DBG) logd(getName() + " go failure");
   1691                     handleGroupCreationFailure();
   1692                     transitionTo(mInactiveState);
   1693                     break;
   1694                 // A group formation failure is always followed by
   1695                 // a group removed event. Flushing things at group formation
   1696                 // failure causes supplicant issues. Ignore right now.
   1697                 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
   1698                     status = (P2pStatus) message.obj;
   1699                     if (status == P2pStatus.NO_COMMON_CHANNEL) {
   1700                         transitionTo(mFrequencyConflictState);
   1701                         break;
   1702                     }
   1703                     break;
   1704                 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
   1705                     status = (P2pStatus)message.obj;
   1706                     if (status == P2pStatus.SUCCESS) {
   1707                         // invocation was succeeded.
   1708                         // wait P2P_GROUP_STARTED_EVENT.
   1709                         break;
   1710                     }
   1711                     loge("Invitation result " + status);
   1712                     if (status == P2pStatus.UNKNOWN_P2P_GROUP) {
   1713                         // target device has already removed the credential.
   1714                         // So, remove this credential accordingly.
   1715                         int netId = mSavedPeerConfig.netId;
   1716                         if (netId >= 0) {
   1717                             if (DBG) logd("Remove unknown client from the list");
   1718                             removeClientFromList(netId, mSavedPeerConfig.deviceAddress, true);
   1719                         }
   1720 
   1721                         // Reinvocation has failed, try group negotiation
   1722                         mSavedPeerConfig.netId = WifiP2pGroup.PERSISTENT_NET_ID;
   1723                         p2pConnectWithPinDisplay(mSavedPeerConfig);
   1724                     } else if (status == P2pStatus.INFORMATION_IS_CURRENTLY_UNAVAILABLE) {
   1725 
   1726                         // Devices setting persistent_reconnect to 0 in wpa_supplicant
   1727                         // always defer the invocation request and return
   1728                         // "information is currently unable" error.
   1729                         // So, try another way to connect for interoperability.
   1730                         mSavedPeerConfig.netId = WifiP2pGroup.PERSISTENT_NET_ID;
   1731                         p2pConnectWithPinDisplay(mSavedPeerConfig);
   1732                     } else if (status == P2pStatus.NO_COMMON_CHANNEL) {
   1733                         transitionTo(mFrequencyConflictState);
   1734                     } else {
   1735                         handleGroupCreationFailure();
   1736                         transitionTo(mInactiveState);
   1737                     }
   1738                     break;
   1739                 default:
   1740                     return NOT_HANDLED;
   1741             }
   1742             return HANDLED;
   1743         }
   1744     }
   1745 
   1746     class FrequencyConflictState extends State {
   1747         private AlertDialog mFrequencyConflictDialog;
   1748         @Override
   1749         public void enter() {
   1750             if (DBG) logd(getName());
   1751             notifyFrequencyConflict();
   1752         }
   1753 
   1754         private void notifyFrequencyConflict() {
   1755             logd("Notify frequency conflict");
   1756             Resources r = Resources.getSystem();
   1757 
   1758             AlertDialog dialog = new AlertDialog.Builder(mContext)
   1759                 .setMessage(r.getString(R.string.wifi_p2p_frequency_conflict_message,
   1760                         getDeviceName(mSavedPeerConfig.deviceAddress)))
   1761                 .setPositiveButton(r.getString(R.string.dlg_ok), new OnClickListener() {
   1762                         @Override
   1763                         public void onClick(DialogInterface dialog, int which) {
   1764                             sendMessage(DROP_WIFI_USER_ACCEPT);
   1765                         }
   1766                     })
   1767                 .setNegativeButton(r.getString(R.string.decline), new OnClickListener() {
   1768                         @Override
   1769                         public void onClick(DialogInterface dialog, int which) {
   1770                             sendMessage(DROP_WIFI_USER_REJECT);
   1771                         }
   1772                     })
   1773                 .setOnCancelListener(new DialogInterface.OnCancelListener() {
   1774                         @Override
   1775                         public void onCancel(DialogInterface arg0) {
   1776                             sendMessage(DROP_WIFI_USER_REJECT);
   1777                         }
   1778                     })
   1779                 .create();
   1780 
   1781             dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
   1782             dialog.show();
   1783             mFrequencyConflictDialog = dialog;
   1784         }
   1785 
   1786         @Override
   1787         public boolean processMessage(Message message) {
   1788             if (DBG) logd(getName() + message.toString());
   1789             switch (message.what) {
   1790                 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
   1791                 case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:
   1792                     loge(getName() + "group sucess during freq conflict!");
   1793                     break;
   1794                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
   1795                     loge(getName() + "group started after freq conflict, handle anyway");
   1796                     deferMessage(message);
   1797                     transitionTo(mGroupNegotiationState);
   1798                     break;
   1799                 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
   1800                 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
   1801                 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
   1802                     // Ignore failures since we retry again
   1803                     break;
   1804                 case DROP_WIFI_USER_REJECT:
   1805                     // User rejected dropping wifi in favour of p2p
   1806                     handleGroupCreationFailure();
   1807                     transitionTo(mInactiveState);
   1808                     break;
   1809                 case DROP_WIFI_USER_ACCEPT:
   1810                     // User accepted dropping wifi in favour of p2p
   1811                     mWifiChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST, 1);
   1812                     mTemporarilyDisconnectedWifi = true;
   1813                     break;
   1814                 case DISCONNECT_WIFI_RESPONSE:
   1815                     // Got a response from wifistatemachine, retry p2p
   1816                     if (DBG) logd(getName() + "Wifi disconnected, retry p2p");
   1817                     transitionTo(mInactiveState);
   1818                     sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
   1819                     break;
   1820                 default:
   1821                     return NOT_HANDLED;
   1822             }
   1823             return HANDLED;
   1824         }
   1825 
   1826         public void exit() {
   1827             if (mFrequencyConflictDialog != null) mFrequencyConflictDialog.dismiss();
   1828         }
   1829     }
   1830 
   1831     class GroupCreatedState extends State {
   1832         @Override
   1833         public void enter() {
   1834             if (DBG) logd(getName());
   1835             // Once connected, peer config details are invalid
   1836             mSavedPeerConfig.invalidate();
   1837             mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
   1838 
   1839             updateThisDevice(WifiP2pDevice.CONNECTED);
   1840 
   1841             //DHCP server has already been started if I am a group owner
   1842             if (mGroup.isGroupOwner()) {
   1843                 setWifiP2pInfoOnGroupFormation(NetworkUtils.numericToInetAddress(SERVER_ADDRESS));
   1844             }
   1845 
   1846             // In case of a negotiation group, connection changed is sent
   1847             // after a client joins. For autonomous, send now
   1848             if (mAutonomousGroup) {
   1849                 sendP2pConnectionChangedBroadcast();
   1850             }
   1851         }
   1852 
   1853         @Override
   1854         public boolean processMessage(Message message) {
   1855             if (DBG) logd(getName() + message.toString());
   1856             switch (message.what) {
   1857                 case WifiMonitor.AP_STA_CONNECTED_EVENT:
   1858                     WifiP2pDevice device = (WifiP2pDevice) message.obj;
   1859                     String deviceAddress = device.deviceAddress;
   1860                     // Clear timeout that was set when group was started.
   1861                     mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0);
   1862                     if (deviceAddress != null) {
   1863                         if (mPeers.get(deviceAddress) != null) {
   1864                             mGroup.addClient(mPeers.get(deviceAddress));
   1865                         } else {
   1866                             mGroup.addClient(deviceAddress);
   1867                         }
   1868                         mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED);
   1869                         if (DBG) logd(getName() + " ap sta connected");
   1870                         sendPeersChangedBroadcast();
   1871                     } else {
   1872                         loge("Connect on null device address, ignore");
   1873                     }
   1874                     sendP2pConnectionChangedBroadcast();
   1875                     break;
   1876                 case WifiMonitor.AP_STA_DISCONNECTED_EVENT:
   1877                     device = (WifiP2pDevice) message.obj;
   1878                     deviceAddress = device.deviceAddress;
   1879                     if (deviceAddress != null) {
   1880                         mPeers.updateStatus(deviceAddress, WifiP2pDevice.AVAILABLE);
   1881                         if (mGroup.removeClient(deviceAddress)) {
   1882                             if (DBG) logd("Removed client " + deviceAddress);
   1883                             if (!mAutonomousGroup && mGroup.isClientListEmpty()) {
   1884                                 logd("Client list empty, remove non-persistent p2p group");
   1885                                 mWifiNative.p2pGroupRemove(mGroup.getInterface());
   1886                                 // We end up sending connection changed broadcast
   1887                                 // when this happens at exit()
   1888                             } else {
   1889                                 // Notify when a client disconnects from group
   1890                                 sendP2pConnectionChangedBroadcast();
   1891                             }
   1892                         } else {
   1893                             if (DBG) logd("Failed to remove client " + deviceAddress);
   1894                             for (WifiP2pDevice c : mGroup.getClientList()) {
   1895                                 if (DBG) logd("client " + c.deviceAddress);
   1896                             }
   1897                         }
   1898                         sendPeersChangedBroadcast();
   1899                         if (DBG) logd(getName() + " ap sta disconnected");
   1900                     } else {
   1901                         loge("Disconnect on unknown device: " + device);
   1902                     }
   1903                     break;
   1904                 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
   1905                     DhcpResults dhcpResults = (DhcpResults) message.obj;
   1906                     if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS &&
   1907                             dhcpResults != null) {
   1908                         if (DBG) logd("DhcpResults: " + dhcpResults);
   1909                         setWifiP2pInfoOnGroupFormation(dhcpResults.serverAddress);
   1910                         sendP2pConnectionChangedBroadcast();
   1911                         //Turn on power save on client
   1912                         mWifiNative.setP2pPowerSave(mGroup.getInterface(), true);
   1913                         try {
   1914                             String iface = mGroup.getInterface();
   1915                             mNwService.addInterfaceToLocalNetwork(iface,
   1916                                                                   dhcpResults.getRoutes(iface));
   1917                         } catch (RemoteException e) {
   1918                             loge("Failed to add iface to local network " + e);
   1919                         }
   1920                     } else {
   1921                         loge("DHCP failed");
   1922                         mWifiNative.p2pGroupRemove(mGroup.getInterface());
   1923                     }
   1924                     break;
   1925                 case WifiP2pManager.REMOVE_GROUP:
   1926                     if (DBG) logd(getName() + " remove group");
   1927                     if (mWifiNative.p2pGroupRemove(mGroup.getInterface())) {
   1928                         transitionTo(mOngoingGroupRemovalState);
   1929                         replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED);
   1930                     } else {
   1931                         handleGroupRemoved();
   1932                         transitionTo(mInactiveState);
   1933                         replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
   1934                                 WifiP2pManager.ERROR);
   1935                     }
   1936                     break;
   1937                 /* We do not listen to NETWORK_DISCONNECTION_EVENT for group removal
   1938                  * handling since supplicant actually tries to reconnect after a temporary
   1939                  * disconnect until group idle time out. Eventually, a group removal event
   1940                  * will come when group has been removed.
   1941                  *
   1942                  * When there are connectivity issues during temporary disconnect, the application
   1943                  * will also just remove the group.
   1944                  *
   1945                  * Treating network disconnection as group removal causes race conditions since
   1946                  * supplicant would still maintain the group at that stage.
   1947                  */
   1948                 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
   1949                     if (DBG) logd(getName() + " group removed");
   1950                     handleGroupRemoved();
   1951                     transitionTo(mInactiveState);
   1952                     break;
   1953                 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
   1954                     device = (WifiP2pDevice) message.obj;
   1955                     //Device loss for a connected device indicates it is not in discovery any more
   1956                     if (mGroup.contains(device)) {
   1957                         if (DBG) logd("Add device to lost list " + device);
   1958                         mPeersLostDuringConnection.updateSupplicantDetails(device);
   1959                         return HANDLED;
   1960                     }
   1961                     // Do the regular device lost handling
   1962                     return NOT_HANDLED;
   1963                 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
   1964                     sendMessage(WifiP2pManager.REMOVE_GROUP);
   1965                     deferMessage(message);
   1966                     break;
   1967                     // This allows any client to join the GO during the
   1968                     // WPS window
   1969                 case WifiP2pManager.START_WPS:
   1970                     WpsInfo wps = (WpsInfo) message.obj;
   1971                     if (wps == null) {
   1972                         replyToMessage(message, WifiP2pManager.START_WPS_FAILED);
   1973                         break;
   1974                     }
   1975                     boolean ret = true;
   1976                     if (wps.setup == WpsInfo.PBC) {
   1977                         ret = mWifiNative.startWpsPbc(mGroup.getInterface(), null);
   1978                     } else {
   1979                         if (wps.pin == null) {
   1980                             String pin = mWifiNative.startWpsPinDisplay(mGroup.getInterface());
   1981                             try {
   1982                                 Integer.parseInt(pin);
   1983                                 notifyInvitationSent(pin, "any");
   1984                             } catch (NumberFormatException ignore) {
   1985                                 ret = false;
   1986                             }
   1987                         } else {
   1988                             ret = mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
   1989                                     wps.pin);
   1990                         }
   1991                     }
   1992                     replyToMessage(message, ret ? WifiP2pManager.START_WPS_SUCCEEDED :
   1993                             WifiP2pManager.START_WPS_FAILED);
   1994                     break;
   1995                 case WifiP2pManager.CONNECT:
   1996                     WifiP2pConfig config = (WifiP2pConfig) message.obj;
   1997                     if (isConfigInvalid(config)) {
   1998                         loge("Dropping connect requeset " + config);
   1999                         replyToMessage(message, WifiP2pManager.CONNECT_FAILED);
   2000                         break;
   2001                     }
   2002                     logd("Inviting device : " + config.deviceAddress);
   2003                     mSavedPeerConfig = config;
   2004                     if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) {
   2005                         mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED);
   2006                         sendPeersChangedBroadcast();
   2007                         replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
   2008                     } else {
   2009                         replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
   2010                                 WifiP2pManager.ERROR);
   2011                     }
   2012                     // TODO: figure out updating the status to declined when invitation is rejected
   2013                     break;
   2014                 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
   2015                     P2pStatus status = (P2pStatus)message.obj;
   2016                     if (status == P2pStatus.SUCCESS) {
   2017                         // invocation was succeeded.
   2018                         break;
   2019                     }
   2020                     loge("Invitation result " + status);
   2021                     if (status == P2pStatus.UNKNOWN_P2P_GROUP) {
   2022                         // target device has already removed the credential.
   2023                         // So, remove this credential accordingly.
   2024                         int netId = mGroup.getNetworkId();
   2025                         if (netId >= 0) {
   2026                             if (DBG) logd("Remove unknown client from the list");
   2027                             if (!removeClientFromList(netId,
   2028                                     mSavedPeerConfig.deviceAddress, false)) {
   2029                                 // not found the client on the list
   2030                                 loge("Already removed the client, ignore");
   2031                                 break;
   2032                             }
   2033                             // try invitation.
   2034                             sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
   2035                         }
   2036                     }
   2037                     break;
   2038                 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
   2039                 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
   2040                 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
   2041                     WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj;
   2042                     mSavedPeerConfig = new WifiP2pConfig();
   2043                     mSavedPeerConfig.deviceAddress = provDisc.device.deviceAddress;
   2044                     if (message.what == WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) {
   2045                         mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD;
   2046                     } else if (message.what == WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT) {
   2047                         mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;
   2048                         mSavedPeerConfig.wps.pin = provDisc.pin;
   2049                     } else {
   2050                         mSavedPeerConfig.wps.setup = WpsInfo.PBC;
   2051                     }
   2052                     transitionTo(mUserAuthorizingJoinState);
   2053                     break;
   2054                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
   2055                     loge("Duplicate group creation event notice, ignore");
   2056                     break;
   2057                 default:
   2058                     return NOT_HANDLED;
   2059             }
   2060             return HANDLED;
   2061         }
   2062 
   2063         public void exit() {
   2064             updateThisDevice(WifiP2pDevice.AVAILABLE);
   2065             resetWifiP2pInfo();
   2066             mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
   2067             sendP2pConnectionChangedBroadcast();
   2068         }
   2069     }
   2070 
   2071     class UserAuthorizingJoinState extends State {
   2072         @Override
   2073         public void enter() {
   2074             if (DBG) logd(getName());
   2075             notifyInvitationReceived();
   2076         }
   2077 
   2078         @Override
   2079         public boolean processMessage(Message message) {
   2080             if (DBG) logd(getName() + message.toString());
   2081             switch (message.what) {
   2082                 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
   2083                 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
   2084                 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
   2085                     //Ignore more client requests
   2086                     break;
   2087                 case PEER_CONNECTION_USER_ACCEPT:
   2088                     //Stop discovery to avoid failure due to channel switch
   2089                     mWifiNative.p2pStopFind();
   2090                     if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
   2091                         mWifiNative.startWpsPbc(mGroup.getInterface(), null);
   2092                     } else {
   2093                         mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
   2094                                 mSavedPeerConfig.wps.pin);
   2095                     }
   2096                     transitionTo(mGroupCreatedState);
   2097                     break;
   2098                 case PEER_CONNECTION_USER_REJECT:
   2099                     if (DBG) logd("User rejected incoming request");
   2100                     transitionTo(mGroupCreatedState);
   2101                     break;
   2102                 default:
   2103                     return NOT_HANDLED;
   2104             }
   2105             return HANDLED;
   2106         }
   2107 
   2108         @Override
   2109         public void exit() {
   2110             //TODO: dismiss dialog if not already done
   2111         }
   2112     }
   2113 
   2114     class OngoingGroupRemovalState extends State {
   2115         @Override
   2116         public void enter() {
   2117             if (DBG) logd(getName());
   2118         }
   2119 
   2120         @Override
   2121         public boolean processMessage(Message message) {
   2122             if (DBG) logd(getName() + message.toString());
   2123             switch (message.what) {
   2124                 // Group removal ongoing. Multiple calls
   2125                 // end up removing persisted network. Do nothing.
   2126                 case WifiP2pManager.REMOVE_GROUP:
   2127                     replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED);
   2128                     break;
   2129                 // Parent state will transition out of this state
   2130                 // when removal is complete
   2131                 default:
   2132                     return NOT_HANDLED;
   2133             }
   2134             return HANDLED;
   2135         }
   2136     }
   2137 
   2138     @Override
   2139     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   2140         super.dump(fd, pw, args);
   2141         pw.println("mWifiP2pInfo " + mWifiP2pInfo);
   2142         pw.println("mGroup " + mGroup);
   2143         pw.println("mSavedPeerConfig " + mSavedPeerConfig);
   2144         pw.println("mSavedP2pGroup " + mSavedP2pGroup);
   2145         pw.println();
   2146     }
   2147 
   2148     private void sendP2pStateChangedBroadcast(boolean enabled) {
   2149         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
   2150         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   2151         if (enabled) {
   2152             intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE,
   2153                     WifiP2pManager.WIFI_P2P_STATE_ENABLED);
   2154         } else {
   2155             intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE,
   2156                     WifiP2pManager.WIFI_P2P_STATE_DISABLED);
   2157         }
   2158         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   2159     }
   2160 
   2161     private void sendP2pDiscoveryChangedBroadcast(boolean started) {
   2162         if (mDiscoveryStarted == started) return;
   2163         mDiscoveryStarted = started;
   2164 
   2165         if (DBG) logd("discovery change broadcast " + started);
   2166 
   2167         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);
   2168         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   2169         intent.putExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE, started ?
   2170                 WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED :
   2171                 WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED);
   2172         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   2173     }
   2174 
   2175     private void sendThisDeviceChangedBroadcast() {
   2176         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
   2177         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   2178         intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE, new WifiP2pDevice(mThisDevice));
   2179         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   2180     }
   2181 
   2182     private void sendPeersChangedBroadcast() {
   2183         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
   2184         intent.putExtra(WifiP2pManager.EXTRA_P2P_DEVICE_LIST, new WifiP2pDeviceList(mPeers));
   2185         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   2186         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
   2187     }
   2188 
   2189     private void sendP2pConnectionChangedBroadcast() {
   2190         if (DBG) logd("sending p2p connection changed broadcast");
   2191         Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
   2192         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
   2193                 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
   2194         intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, new WifiP2pInfo(mWifiP2pInfo));
   2195         intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
   2196         intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, new WifiP2pGroup(mGroup));
   2197         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   2198         mWifiChannel.sendMessage(WifiP2pServiceImpl.P2P_CONNECTION_CHANGED,
   2199                 new NetworkInfo(mNetworkInfo));
   2200     }
   2201 
   2202     private void sendP2pPersistentGroupsChangedBroadcast() {
   2203         if (DBG) logd("sending p2p persistent groups changed broadcast");
   2204         Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION);
   2205         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   2206         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   2207     }
   2208 
   2209     private void startDhcpServer(String intf) {
   2210         InterfaceConfiguration ifcg = null;
   2211         try {
   2212             ifcg = mNwService.getInterfaceConfig(intf);
   2213             ifcg.setLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress(
   2214                         SERVER_ADDRESS), 24));
   2215             ifcg.setInterfaceUp();
   2216             mNwService.setInterfaceConfig(intf, ifcg);
   2217             /* This starts the dnsmasq server */
   2218             ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
   2219                     Context.CONNECTIVITY_SERVICE);
   2220             String[] tetheringDhcpRanges = cm.getTetheredDhcpRanges();
   2221             if (mNwService.isTetheringStarted()) {
   2222                 if (DBG) logd("Stop existing tethering and restart it");
   2223                 mNwService.stopTethering();
   2224             }
   2225             mNwService.tetherInterface(intf);
   2226             mNwService.startTethering(tetheringDhcpRanges);
   2227         } catch (Exception e) {
   2228             loge("Error configuring interface " + intf + ", :" + e);
   2229             return;
   2230         }
   2231 
   2232         logd("Started Dhcp server on " + intf);
   2233    }
   2234 
   2235     private void stopDhcpServer(String intf) {
   2236         try {
   2237             mNwService.untetherInterface(intf);
   2238             for (String temp : mNwService.listTetheredInterfaces()) {
   2239                 logd("List all interfaces " + temp);
   2240                 if (temp.compareTo(intf) != 0) {
   2241                     logd("Found other tethering interfaces, so keep tethering alive");
   2242                     return;
   2243                 }
   2244             }
   2245             mNwService.stopTethering();
   2246         } catch (Exception e) {
   2247             loge("Error stopping Dhcp server" + e);
   2248             return;
   2249         } finally {
   2250             logd("Stopped Dhcp server");
   2251         }
   2252     }
   2253 
   2254     private void notifyP2pEnableFailure() {
   2255         Resources r = Resources.getSystem();
   2256         AlertDialog dialog = new AlertDialog.Builder(mContext)
   2257             .setTitle(r.getString(R.string.wifi_p2p_dialog_title))
   2258             .setMessage(r.getString(R.string.wifi_p2p_failed_message))
   2259             .setPositiveButton(r.getString(R.string.ok), null)
   2260             .create();
   2261         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
   2262         dialog.show();
   2263     }
   2264 
   2265     private void addRowToDialog(ViewGroup group, int stringId, String value) {
   2266         Resources r = Resources.getSystem();
   2267         View row = LayoutInflater.from(mContext).inflate(R.layout.wifi_p2p_dialog_row,
   2268                 group, false);
   2269         ((TextView) row.findViewById(R.id.name)).setText(r.getString(stringId));
   2270         ((TextView) row.findViewById(R.id.value)).setText(value);
   2271         group.addView(row);
   2272     }
   2273 
   2274     private void notifyInvitationSent(String pin, String peerAddress) {
   2275         Resources r = Resources.getSystem();
   2276 
   2277         final View textEntryView = LayoutInflater.from(mContext)
   2278                 .inflate(R.layout.wifi_p2p_dialog, null);
   2279 
   2280         ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info);
   2281         addRowToDialog(group, R.string.wifi_p2p_to_message, getDeviceName(peerAddress));
   2282         addRowToDialog(group, R.string.wifi_p2p_show_pin_message, pin);
   2283 
   2284         AlertDialog dialog = new AlertDialog.Builder(mContext)
   2285             .setTitle(r.getString(R.string.wifi_p2p_invitation_sent_title))
   2286             .setView(textEntryView)
   2287             .setPositiveButton(r.getString(R.string.ok), null)
   2288             .create();
   2289         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
   2290         dialog.show();
   2291     }
   2292 
   2293     private void notifyInvitationReceived() {
   2294         Resources r = Resources.getSystem();
   2295         final WpsInfo wps = mSavedPeerConfig.wps;
   2296         final View textEntryView = LayoutInflater.from(mContext)
   2297                 .inflate(R.layout.wifi_p2p_dialog, null);
   2298 
   2299         ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info);
   2300         addRowToDialog(group, R.string.wifi_p2p_from_message, getDeviceName(
   2301                 mSavedPeerConfig.deviceAddress));
   2302 
   2303         final EditText pin = (EditText) textEntryView.findViewById(R.id.wifi_p2p_wps_pin);
   2304 
   2305         AlertDialog dialog = new AlertDialog.Builder(mContext)
   2306             .setTitle(r.getString(R.string.wifi_p2p_invitation_to_connect_title))
   2307             .setView(textEntryView)
   2308             .setPositiveButton(r.getString(R.string.accept), new OnClickListener() {
   2309                         public void onClick(DialogInterface dialog, int which) {
   2310                             if (wps.setup == WpsInfo.KEYPAD) {
   2311                                 mSavedPeerConfig.wps.pin = pin.getText().toString();
   2312                             }
   2313                             if (DBG) logd(getName() + " accept invitation " + mSavedPeerConfig);
   2314                             sendMessage(PEER_CONNECTION_USER_ACCEPT);
   2315                         }
   2316                     })
   2317             .setNegativeButton(r.getString(R.string.decline), new OnClickListener() {
   2318                         @Override
   2319                         public void onClick(DialogInterface dialog, int which) {
   2320                             if (DBG) logd(getName() + " ignore connect");
   2321                             sendMessage(PEER_CONNECTION_USER_REJECT);
   2322                         }
   2323                     })
   2324             .setOnCancelListener(new DialogInterface.OnCancelListener() {
   2325                         @Override
   2326                         public void onCancel(DialogInterface arg0) {
   2327                             if (DBG) logd(getName() + " ignore connect");
   2328                             sendMessage(PEER_CONNECTION_USER_REJECT);
   2329                         }
   2330                     })
   2331             .create();
   2332 
   2333         //make the enter pin area or the display pin area visible
   2334         switch (wps.setup) {
   2335             case WpsInfo.KEYPAD:
   2336                 if (DBG) logd("Enter pin section visible");
   2337                 textEntryView.findViewById(R.id.enter_pin_section).setVisibility(View.VISIBLE);
   2338                 break;
   2339             case WpsInfo.DISPLAY:
   2340                 if (DBG) logd("Shown pin section visible");
   2341                 addRowToDialog(group, R.string.wifi_p2p_show_pin_message, wps.pin);
   2342                 break;
   2343             default:
   2344                 break;
   2345         }
   2346 
   2347         if ((r.getConfiguration().uiMode & Configuration.UI_MODE_TYPE_APPLIANCE) ==
   2348                 Configuration.UI_MODE_TYPE_APPLIANCE) {
   2349             // For appliance devices, add a key listener which accepts.
   2350             dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
   2351 
   2352                 @Override
   2353                 public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
   2354                     // TODO: make the actual key come from a config value.
   2355                     if (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
   2356                         sendMessage(PEER_CONNECTION_USER_ACCEPT);
   2357                         dialog.dismiss();
   2358                         return true;
   2359                     }
   2360                     return false;
   2361                 }
   2362             });
   2363             // TODO: add timeout for this dialog.
   2364             // TODO: update UI in appliance mode to tell user what to do.
   2365         }
   2366 
   2367         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
   2368         dialog.show();
   2369     }
   2370 
   2371     /**
   2372      * Synchronize the persistent group list between
   2373      * wpa_supplicant and mGroups.
   2374      */
   2375     private void updatePersistentNetworks(boolean reload) {
   2376         String listStr = mWifiNative.listNetworks();
   2377         if (listStr == null) return;
   2378 
   2379         boolean isSaveRequired = false;
   2380         String[] lines = listStr.split("\n");
   2381         if (lines == null) return;
   2382 
   2383         if (reload) mGroups.clear();
   2384 
   2385         // Skip the first line, which is a header
   2386         for (int i = 1; i < lines.length; i++) {
   2387             String[] result = lines[i].split("\t");
   2388             if (result == null || result.length < 4) {
   2389                 continue;
   2390             }
   2391             // network-id | ssid | bssid | flags
   2392             int netId = -1;
   2393             String ssid = result[1];
   2394             String bssid = result[2];
   2395             String flags = result[3];
   2396             try {
   2397                 netId = Integer.parseInt(result[0]);
   2398             } catch(NumberFormatException e) {
   2399                 e.printStackTrace();
   2400                 continue;
   2401             }
   2402 
   2403             if (flags.indexOf("[CURRENT]") != -1) {
   2404                 continue;
   2405             }
   2406             if (flags.indexOf("[P2P-PERSISTENT]") == -1) {
   2407                 /*
   2408                  * The unused profile is sometimes remained when the p2p group formation is failed.
   2409                  * So, we clean up the p2p group here.
   2410                  */
   2411                 if (DBG) logd("clean up the unused persistent group. netId=" + netId);
   2412                 mWifiNative.removeNetwork(netId);
   2413                 isSaveRequired = true;
   2414                 continue;
   2415             }
   2416 
   2417             if (mGroups.contains(netId)) {
   2418                 continue;
   2419             }
   2420 
   2421             WifiP2pGroup group = new WifiP2pGroup();
   2422             group.setNetworkId(netId);
   2423             group.setNetworkName(ssid);
   2424             String mode = mWifiNative.getNetworkVariable(netId, "mode");
   2425             if (mode != null && mode.equals("3")) {
   2426                 group.setIsGroupOwner(true);
   2427             }
   2428             if (bssid.equalsIgnoreCase(mThisDevice.deviceAddress)) {
   2429                 group.setOwner(mThisDevice);
   2430             } else {
   2431                 WifiP2pDevice device = new WifiP2pDevice();
   2432                 device.deviceAddress = bssid;
   2433                 group.setOwner(device);
   2434             }
   2435             mGroups.add(group);
   2436             isSaveRequired = true;
   2437         }
   2438 
   2439         if (reload || isSaveRequired) {
   2440             mWifiNative.saveConfig();
   2441             sendP2pPersistentGroupsChangedBroadcast();
   2442         }
   2443     }
   2444 
   2445     /**
   2446      * A config is valid if it has a peer address that has already been
   2447      * discovered
   2448      * @return true if it is invalid, false otherwise
   2449      */
   2450     private boolean isConfigInvalid(WifiP2pConfig config) {
   2451         if (config == null) return true;
   2452         if (TextUtils.isEmpty(config.deviceAddress)) return true;
   2453         if (mPeers.get(config.deviceAddress) == null) return true;
   2454         return false;
   2455     }
   2456 
   2457     /* TODO: The supplicant does not provide group capability changes as an event.
   2458      * Having it pushed as an event would avoid polling for this information right
   2459      * before a connection
   2460      */
   2461     private WifiP2pDevice fetchCurrentDeviceDetails(WifiP2pConfig config) {
   2462         /* Fetch & update group capability from supplicant on the device */
   2463         int gc = mWifiNative.getGroupCapability(config.deviceAddress);
   2464         mPeers.updateGroupCapability(config.deviceAddress, gc);
   2465         return mPeers.get(config.deviceAddress);
   2466     }
   2467 
   2468     /**
   2469      * Start a p2p group negotiation and display pin if necessary
   2470      * @param config for the peer
   2471      */
   2472     private void p2pConnectWithPinDisplay(WifiP2pConfig config) {
   2473         WifiP2pDevice dev = fetchCurrentDeviceDetails(config);
   2474 
   2475         String pin = mWifiNative.p2pConnect(config, dev.isGroupOwner());
   2476         try {
   2477             Integer.parseInt(pin);
   2478             notifyInvitationSent(pin, config.deviceAddress);
   2479         } catch (NumberFormatException ignore) {
   2480             // do nothing if p2pConnect did not return a pin
   2481         }
   2482     }
   2483 
   2484     /**
   2485      * Reinvoke a persistent group.
   2486      *
   2487      * @param config for the peer
   2488      * @return true on success, false on failure
   2489      */
   2490     private boolean reinvokePersistentGroup(WifiP2pConfig config) {
   2491         WifiP2pDevice dev = fetchCurrentDeviceDetails(config);
   2492 
   2493         boolean join = dev.isGroupOwner();
   2494         String ssid = mWifiNative.p2pGetSsid(dev.deviceAddress);
   2495         if (DBG) logd("target ssid is " + ssid + " join:" + join);
   2496 
   2497         if (join && dev.isGroupLimit()) {
   2498             if (DBG) logd("target device reaches group limit.");
   2499 
   2500             // if the target group has reached the limit,
   2501             // try group formation.
   2502             join = false;
   2503         } else if (join) {
   2504             int netId = mGroups.getNetworkId(dev.deviceAddress, ssid);
   2505             if (netId >= 0) {
   2506                 // Skip WPS and start 4way handshake immediately.
   2507                 if (!mWifiNative.p2pGroupAdd(netId)) {
   2508                     return false;
   2509                 }
   2510                 return true;
   2511             }
   2512         }
   2513 
   2514         if (!join && dev.isDeviceLimit()) {
   2515             loge("target device reaches the device limit.");
   2516             return false;
   2517         }
   2518 
   2519         if (!join && dev.isInvitationCapable()) {
   2520             int netId = WifiP2pGroup.PERSISTENT_NET_ID;
   2521             if (config.netId >= 0) {
   2522                 if (config.deviceAddress.equals(mGroups.getOwnerAddr(config.netId))) {
   2523                     netId = config.netId;
   2524                 }
   2525             } else {
   2526                 netId = mGroups.getNetworkId(dev.deviceAddress);
   2527             }
   2528             if (netId < 0) {
   2529                 netId = getNetworkIdFromClientList(dev.deviceAddress);
   2530             }
   2531             if (DBG) logd("netId related with " + dev.deviceAddress + " = " + netId);
   2532             if (netId >= 0) {
   2533                 // Invoke the persistent group.
   2534                 if (mWifiNative.p2pReinvoke(netId, dev.deviceAddress)) {
   2535                     // Save network id. It'll be used when an invitation result event is received.
   2536                     config.netId = netId;
   2537                     return true;
   2538                 } else {
   2539                     loge("p2pReinvoke() failed, update networks");
   2540                     updatePersistentNetworks(RELOAD);
   2541                     return false;
   2542                 }
   2543             }
   2544         }
   2545 
   2546         return false;
   2547     }
   2548 
   2549     /**
   2550      * Return the network id of the group owner profile which has the p2p client with
   2551      * the specified device address in it's client list.
   2552      * If more than one persistent group of the same address is present in its client
   2553      * lists, return the first one.
   2554      *
   2555      * @param deviceAddress p2p device address.
   2556      * @return the network id. if not found, return -1.
   2557      */
   2558     private int getNetworkIdFromClientList(String deviceAddress) {
   2559         if (deviceAddress == null) return -1;
   2560 
   2561         Collection<WifiP2pGroup> groups = mGroups.getGroupList();
   2562         for (WifiP2pGroup group : groups) {
   2563             int netId = group.getNetworkId();
   2564             String[] p2pClientList = getClientList(netId);
   2565             if (p2pClientList == null) continue;
   2566             for (String client : p2pClientList) {
   2567                 if (deviceAddress.equalsIgnoreCase(client)) {
   2568                     return netId;
   2569                 }
   2570             }
   2571         }
   2572         return -1;
   2573     }
   2574 
   2575     /**
   2576      * Return p2p client list associated with the specified network id.
   2577      * @param netId network id.
   2578      * @return p2p client list. if not found, return null.
   2579      */
   2580     private String[] getClientList(int netId) {
   2581         String p2pClients = mWifiNative.getNetworkVariable(netId, "p2p_client_list");
   2582         if (p2pClients == null) {
   2583             return null;
   2584         }
   2585         return p2pClients.split(" ");
   2586     }
   2587 
   2588     /**
   2589      * Remove the specified p2p client from the specified profile.
   2590      * @param netId network id of the profile.
   2591      * @param addr p2p client address to be removed.
   2592      * @param isRemovable if true, remove the specified profile if its client list becomes empty.
   2593      * @return whether removing the specified p2p client is successful or not.
   2594      */
   2595     private boolean removeClientFromList(int netId, String addr, boolean isRemovable) {
   2596         StringBuilder modifiedClientList =  new StringBuilder();
   2597         String[] currentClientList = getClientList(netId);
   2598         boolean isClientRemoved = false;
   2599         if (currentClientList != null) {
   2600             for (String client : currentClientList) {
   2601                 if (!client.equalsIgnoreCase(addr)) {
   2602                     modifiedClientList.append(" ");
   2603                     modifiedClientList.append(client);
   2604                 } else {
   2605                     isClientRemoved = true;
   2606                 }
   2607             }
   2608         }
   2609         if (modifiedClientList.length() == 0 && isRemovable) {
   2610             // the client list is empty. so remove it.
   2611             if (DBG) logd("Remove unknown network");
   2612             mGroups.remove(netId);
   2613             return true;
   2614         }
   2615 
   2616         if (!isClientRemoved) {
   2617             // specified p2p client is not found. already removed.
   2618             return false;
   2619         }
   2620 
   2621         if (DBG) logd("Modified client list: " + modifiedClientList);
   2622         if (modifiedClientList.length() == 0) {
   2623             modifiedClientList.append("\"\"");
   2624         }
   2625         mWifiNative.setNetworkVariable(netId,
   2626                 "p2p_client_list", modifiedClientList.toString());
   2627         mWifiNative.saveConfig();
   2628         return true;
   2629     }
   2630 
   2631     private void setWifiP2pInfoOnGroupFormation(InetAddress serverInetAddress) {
   2632         mWifiP2pInfo.groupFormed = true;
   2633         mWifiP2pInfo.isGroupOwner = mGroup.isGroupOwner();
   2634         mWifiP2pInfo.groupOwnerAddress = serverInetAddress;
   2635     }
   2636 
   2637     private void resetWifiP2pInfo() {
   2638         mWifiP2pInfo.groupFormed = false;
   2639         mWifiP2pInfo.isGroupOwner = false;
   2640         mWifiP2pInfo.groupOwnerAddress = null;
   2641     }
   2642 
   2643     private String getDeviceName(String deviceAddress) {
   2644         WifiP2pDevice d = mPeers.get(deviceAddress);
   2645         if (d != null) {
   2646                 return d.deviceName;
   2647         }
   2648         //Treat the address as name if there is no match
   2649         return deviceAddress;
   2650     }
   2651 
   2652     private String getPersistedDeviceName() {
   2653         String deviceName = Settings.Global.getString(mContext.getContentResolver(),
   2654                 Settings.Global.WIFI_P2P_DEVICE_NAME);
   2655         if (deviceName == null) {
   2656             /* We use the 4 digits of the ANDROID_ID to have a friendly
   2657              * default that has low likelihood of collision with a peer */
   2658             String id = Settings.Secure.getString(mContext.getContentResolver(),
   2659                     Settings.Secure.ANDROID_ID);
   2660             return "Android_" + id.substring(0,4);
   2661         }
   2662         return deviceName;
   2663     }
   2664 
   2665     private boolean setAndPersistDeviceName(String devName) {
   2666         if (devName == null) return false;
   2667 
   2668         if (!mWifiNative.setDeviceName(devName)) {
   2669             loge("Failed to set device name " + devName);
   2670             return false;
   2671         }
   2672 
   2673         mThisDevice.deviceName = devName;
   2674         mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName);
   2675 
   2676         Settings.Global.putString(mContext.getContentResolver(),
   2677                 Settings.Global.WIFI_P2P_DEVICE_NAME, devName);
   2678         sendThisDeviceChangedBroadcast();
   2679         return true;
   2680     }
   2681 
   2682     private boolean setWfdInfo(WifiP2pWfdInfo wfdInfo) {
   2683         boolean success;
   2684 
   2685         if (!wfdInfo.isWfdEnabled()) {
   2686             success = mWifiNative.setWfdEnable(false);
   2687         } else {
   2688             success =
   2689                 mWifiNative.setWfdEnable(true)
   2690                 && mWifiNative.setWfdDeviceInfo(wfdInfo.getDeviceInfoHex());
   2691         }
   2692 
   2693         if (!success) {
   2694             loge("Failed to set wfd properties");
   2695             return false;
   2696         }
   2697 
   2698         mThisDevice.wfdInfo = wfdInfo;
   2699         sendThisDeviceChangedBroadcast();
   2700         return true;
   2701     }
   2702 
   2703     private void initializeP2pSettings() {
   2704         mWifiNative.setPersistentReconnect(true);
   2705         mThisDevice.deviceName = getPersistedDeviceName();
   2706         mWifiNative.setDeviceName(mThisDevice.deviceName);
   2707         // DIRECT-XY-DEVICENAME (XY is randomly generated)
   2708         mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName);
   2709         mWifiNative.setDeviceType(mThisDevice.primaryDeviceType);
   2710         // Supplicant defaults to using virtual display with display
   2711         // which refers to a remote display. Use physical_display
   2712         mWifiNative.setConfigMethods("virtual_push_button physical_display keypad");
   2713         // STA has higher priority over P2P
   2714         mWifiNative.setConcurrencyPriority("sta");
   2715 
   2716         mThisDevice.deviceAddress = mWifiNative.p2pGetDeviceAddress();
   2717         updateThisDevice(WifiP2pDevice.AVAILABLE);
   2718         if (DBG) logd("DeviceAddress: " + mThisDevice.deviceAddress);
   2719 
   2720         mClientInfoList.clear();
   2721         mWifiNative.p2pFlush();
   2722         mWifiNative.p2pServiceFlush();
   2723         mServiceTransactionId = 0;
   2724         mServiceDiscReqId = null;
   2725 
   2726         String countryCode = Settings.Global.getString(mContext.getContentResolver(),
   2727                 Settings.Global.WIFI_COUNTRY_CODE);
   2728         if (countryCode != null && !countryCode.isEmpty()) {
   2729             mP2pStateMachine.sendMessage(SET_COUNTRY_CODE, countryCode);
   2730         }
   2731 
   2732         updatePersistentNetworks(RELOAD);
   2733     }
   2734 
   2735     private void updateThisDevice(int status) {
   2736         mThisDevice.status = status;
   2737         sendThisDeviceChangedBroadcast();
   2738     }
   2739 
   2740     private void handleGroupCreationFailure() {
   2741         resetWifiP2pInfo();
   2742         mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.FAILED, null, null);
   2743         sendP2pConnectionChangedBroadcast();
   2744 
   2745         // Remove only the peer we failed to connect to so that other devices discovered
   2746         // that have not timed out still remain in list for connection
   2747         boolean peersChanged = mPeers.remove(mPeersLostDuringConnection);
   2748         if (mSavedPeerConfig.deviceAddress != null &&
   2749                 mPeers.remove(mSavedPeerConfig.deviceAddress) != null) {
   2750             peersChanged = true;
   2751         }
   2752         if (peersChanged) {
   2753             sendPeersChangedBroadcast();
   2754         }
   2755 
   2756         mPeersLostDuringConnection.clear();
   2757         mServiceDiscReqId = null;
   2758         sendMessage(WifiP2pManager.DISCOVER_PEERS);
   2759     }
   2760 
   2761     private void handleGroupRemoved() {
   2762         if (mGroup.isGroupOwner()) {
   2763             stopDhcpServer(mGroup.getInterface());
   2764         } else {
   2765             if (DBG) logd("stop DHCP client");
   2766             mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
   2767             mDhcpStateMachine.doQuit();
   2768             mDhcpStateMachine = null;
   2769             try {
   2770                 mNwService.removeInterfaceFromLocalNetwork(mGroup.getInterface());
   2771             } catch (RemoteException e) {
   2772                 loge("Failed to remove iface from local network " + e);
   2773             }
   2774         }
   2775 
   2776         try {
   2777             mNwService.clearInterfaceAddresses(mGroup.getInterface());
   2778         } catch (Exception e) {
   2779             loge("Failed to clear addresses " + e);
   2780         }
   2781         NetworkUtils.resetConnections(mGroup.getInterface(), NetworkUtils.RESET_ALL_ADDRESSES);
   2782 
   2783         // Clear any timeout that was set. This is essential for devices
   2784         // that reuse the main p2p interface for a created group.
   2785         mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0);
   2786 
   2787         boolean peersChanged = false;
   2788         // Remove only peers part of the group, so that other devices discovered
   2789         // that have not timed out still remain in list for connection
   2790         for (WifiP2pDevice d : mGroup.getClientList()) {
   2791             if (mPeers.remove(d)) peersChanged = true;
   2792         }
   2793         if (mPeers.remove(mGroup.getOwner())) peersChanged = true;
   2794         if (mPeers.remove(mPeersLostDuringConnection)) peersChanged = true;
   2795         if (peersChanged) {
   2796             sendPeersChangedBroadcast();
   2797         }
   2798 
   2799         mGroup = null;
   2800         mPeersLostDuringConnection.clear();
   2801         mServiceDiscReqId = null;
   2802 
   2803         if (mTemporarilyDisconnectedWifi) {
   2804             mWifiChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST, 0);
   2805             mTemporarilyDisconnectedWifi = false;
   2806         }
   2807    }
   2808 
   2809     //State machine initiated requests can have replyTo set to null indicating
   2810     //there are no recipients, we ignore those reply actions
   2811     private void replyToMessage(Message msg, int what) {
   2812         if (msg.replyTo == null) return;
   2813         Message dstMsg = obtainMessage(msg);
   2814         dstMsg.what = what;
   2815         mReplyChannel.replyToMessage(msg, dstMsg);
   2816     }
   2817 
   2818     private void replyToMessage(Message msg, int what, int arg1) {
   2819         if (msg.replyTo == null) return;
   2820         Message dstMsg = obtainMessage(msg);
   2821         dstMsg.what = what;
   2822         dstMsg.arg1 = arg1;
   2823         mReplyChannel.replyToMessage(msg, dstMsg);
   2824     }
   2825 
   2826     private void replyToMessage(Message msg, int what, Object obj) {
   2827         if (msg.replyTo == null) return;
   2828         Message dstMsg = obtainMessage(msg);
   2829         dstMsg.what = what;
   2830         dstMsg.obj = obj;
   2831         mReplyChannel.replyToMessage(msg, dstMsg);
   2832     }
   2833 
   2834     /* arg2 on the source message has a hash code that needs to be retained in replies
   2835      * see WifiP2pManager for details */
   2836     private Message obtainMessage(Message srcMsg) {
   2837         Message msg = Message.obtain();
   2838         msg.arg2 = srcMsg.arg2;
   2839         return msg;
   2840     }
   2841 
   2842     @Override
   2843     protected void logd(String s) {
   2844         Slog.d(TAG, s);
   2845     }
   2846 
   2847     @Override
   2848     protected void loge(String s) {
   2849         Slog.e(TAG, s);
   2850     }
   2851 
   2852     /**
   2853      * Update service discovery request to wpa_supplicant.
   2854      */
   2855     private boolean updateSupplicantServiceRequest() {
   2856         clearSupplicantServiceRequest();
   2857 
   2858         StringBuffer sb = new StringBuffer();
   2859         for (ClientInfo c: mClientInfoList.values()) {
   2860             int key;
   2861             WifiP2pServiceRequest req;
   2862             for (int i=0; i < c.mReqList.size(); i++) {
   2863                 req = c.mReqList.valueAt(i);
   2864                 if (req != null) {
   2865                     sb.append(req.getSupplicantQuery());
   2866                 }
   2867             }
   2868         }
   2869 
   2870         if (sb.length() == 0) {
   2871             return false;
   2872         }
   2873 
   2874         mServiceDiscReqId = mWifiNative.p2pServDiscReq("00:00:00:00:00:00", sb.toString());
   2875         if (mServiceDiscReqId == null) {
   2876             return false;
   2877         }
   2878         return true;
   2879     }
   2880 
   2881     /**
   2882      * Clear service discovery request in wpa_supplicant
   2883      */
   2884     private void clearSupplicantServiceRequest() {
   2885         if (mServiceDiscReqId == null) return;
   2886 
   2887         mWifiNative.p2pServDiscCancelReq(mServiceDiscReqId);
   2888         mServiceDiscReqId = null;
   2889     }
   2890 
   2891     /* TODO: We could track individual service adds separately and avoid
   2892      * having to do update all service requests on every new request
   2893      */
   2894     private boolean addServiceRequest(Messenger m, WifiP2pServiceRequest req) {
   2895         clearClientDeadChannels();
   2896         ClientInfo clientInfo = getClientInfo(m, true);
   2897         if (clientInfo == null) {
   2898             return false;
   2899         }
   2900 
   2901         ++mServiceTransactionId;
   2902         //The Wi-Fi p2p spec says transaction id should be non-zero
   2903         if (mServiceTransactionId == 0) ++mServiceTransactionId;
   2904         req.setTransactionId(mServiceTransactionId);
   2905         clientInfo.mReqList.put(mServiceTransactionId, req);
   2906 
   2907         if (mServiceDiscReqId == null) {
   2908             return true;
   2909         }
   2910 
   2911         return updateSupplicantServiceRequest();
   2912     }
   2913 
   2914     private void removeServiceRequest(Messenger m, WifiP2pServiceRequest req) {
   2915         ClientInfo clientInfo = getClientInfo(m, false);
   2916         if (clientInfo == null) {
   2917             return;
   2918         }
   2919 
   2920         //Application does not have transaction id information
   2921         //go through stored requests to remove
   2922         boolean removed = false;
   2923         for (int i=0; i<clientInfo.mReqList.size(); i++) {
   2924             if (req.equals(clientInfo.mReqList.valueAt(i))) {
   2925                 removed = true;
   2926                 clientInfo.mReqList.removeAt(i);
   2927                 break;
   2928             }
   2929         }
   2930 
   2931         if (!removed) return;
   2932 
   2933         if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) {
   2934             if (DBG) logd("remove client information from framework");
   2935             mClientInfoList.remove(clientInfo.mMessenger);
   2936         }
   2937 
   2938         if (mServiceDiscReqId == null) {
   2939             return;
   2940         }
   2941 
   2942         updateSupplicantServiceRequest();
   2943     }
   2944 
   2945     private void clearServiceRequests(Messenger m) {
   2946 
   2947         ClientInfo clientInfo = getClientInfo(m, false);
   2948         if (clientInfo == null) {
   2949             return;
   2950         }
   2951 
   2952         if (clientInfo.mReqList.size() == 0) {
   2953             return;
   2954         }
   2955 
   2956         clientInfo.mReqList.clear();
   2957 
   2958         if (clientInfo.mServList.size() == 0) {
   2959             if (DBG) logd("remove channel information from framework");
   2960             mClientInfoList.remove(clientInfo.mMessenger);
   2961         }
   2962 
   2963         if (mServiceDiscReqId == null) {
   2964             return;
   2965         }
   2966 
   2967         updateSupplicantServiceRequest();
   2968     }
   2969 
   2970     private boolean addLocalService(Messenger m, WifiP2pServiceInfo servInfo) {
   2971         clearClientDeadChannels();
   2972         ClientInfo clientInfo = getClientInfo(m, true);
   2973         if (clientInfo == null) {
   2974             return false;
   2975         }
   2976 
   2977         if (!clientInfo.mServList.add(servInfo)) {
   2978             return false;
   2979         }
   2980 
   2981         if (!mWifiNative.p2pServiceAdd(servInfo)) {
   2982             clientInfo.mServList.remove(servInfo);
   2983             return false;
   2984         }
   2985 
   2986         return true;
   2987     }
   2988 
   2989     private void removeLocalService(Messenger m, WifiP2pServiceInfo servInfo) {
   2990         ClientInfo clientInfo = getClientInfo(m, false);
   2991         if (clientInfo == null) {
   2992             return;
   2993         }
   2994 
   2995         mWifiNative.p2pServiceDel(servInfo);
   2996 
   2997         clientInfo.mServList.remove(servInfo);
   2998         if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) {
   2999             if (DBG) logd("remove client information from framework");
   3000             mClientInfoList.remove(clientInfo.mMessenger);
   3001         }
   3002     }
   3003 
   3004     private void clearLocalServices(Messenger m) {
   3005         ClientInfo clientInfo = getClientInfo(m, false);
   3006         if (clientInfo == null) {
   3007             return;
   3008         }
   3009 
   3010         for (WifiP2pServiceInfo servInfo: clientInfo.mServList) {
   3011             mWifiNative.p2pServiceDel(servInfo);
   3012         }
   3013 
   3014         clientInfo.mServList.clear();
   3015         if (clientInfo.mReqList.size() == 0) {
   3016             if (DBG) logd("remove client information from framework");
   3017             mClientInfoList.remove(clientInfo.mMessenger);
   3018         }
   3019     }
   3020 
   3021     private void clearClientInfo(Messenger m) {
   3022         clearLocalServices(m);
   3023         clearServiceRequests(m);
   3024     }
   3025 
   3026     /**
   3027      * Send the service response to the WifiP2pManager.Channel.
   3028      *
   3029      * @param resp
   3030      */
   3031     private void sendServiceResponse(WifiP2pServiceResponse resp) {
   3032         for (ClientInfo c : mClientInfoList.values()) {
   3033             WifiP2pServiceRequest req = c.mReqList.get(resp.getTransactionId());
   3034             if (req != null) {
   3035                 Message msg = Message.obtain();
   3036                 msg.what = WifiP2pManager.RESPONSE_SERVICE;
   3037                 msg.arg1 = 0;
   3038                 msg.arg2 = 0;
   3039                 msg.obj = resp;
   3040                 try {
   3041                     c.mMessenger.send(msg);
   3042                 } catch (RemoteException e) {
   3043                     if (DBG) logd("detect dead channel");
   3044                     clearClientInfo(c.mMessenger);
   3045                     return;
   3046                 }
   3047             }
   3048         }
   3049     }
   3050 
   3051     /**
   3052      * We dont get notifications of clients that have gone away.
   3053      * We detect this actively when services are added and throw
   3054      * them away.
   3055      *
   3056      * TODO: This can be done better with full async channels.
   3057      */
   3058     private void clearClientDeadChannels() {
   3059         ArrayList<Messenger> deadClients = new ArrayList<Messenger>();
   3060 
   3061         for (ClientInfo c : mClientInfoList.values()) {
   3062             Message msg = Message.obtain();
   3063             msg.what = WifiP2pManager.PING;
   3064             msg.arg1 = 0;
   3065             msg.arg2 = 0;
   3066             msg.obj = null;
   3067             try {
   3068                 c.mMessenger.send(msg);
   3069             } catch (RemoteException e) {
   3070                 if (DBG) logd("detect dead channel");
   3071                 deadClients.add(c.mMessenger);
   3072             }
   3073         }
   3074 
   3075         for (Messenger m : deadClients) {
   3076             clearClientInfo(m);
   3077         }
   3078     }
   3079 
   3080     /**
   3081      * Return the specified ClientInfo.
   3082      * @param m Messenger
   3083      * @param createIfNotExist if true and the specified channel info does not exist,
   3084      * create new client info.
   3085      * @return the specified ClientInfo.
   3086      */
   3087     private ClientInfo getClientInfo(Messenger m, boolean createIfNotExist) {
   3088         ClientInfo clientInfo = mClientInfoList.get(m);
   3089 
   3090         if (clientInfo == null && createIfNotExist) {
   3091             if (DBG) logd("add a new client");
   3092             clientInfo = new ClientInfo(m);
   3093             mClientInfoList.put(m, clientInfo);
   3094         }
   3095 
   3096         return clientInfo;
   3097     }
   3098 
   3099     }
   3100 
   3101     /**
   3102      * Information about a particular client and we track the service discovery requests
   3103      * and the local services registered by the client.
   3104      */
   3105     private class ClientInfo {
   3106 
   3107         /*
   3108          * A reference to WifiP2pManager.Channel handler.
   3109          * The response of this request is notified to WifiP2pManager.Channel handler
   3110          */
   3111         private Messenger mMessenger;
   3112 
   3113         /*
   3114          * A service discovery request list.
   3115          */
   3116         private SparseArray<WifiP2pServiceRequest> mReqList;
   3117 
   3118         /*
   3119          * A local service information list.
   3120          */
   3121         private List<WifiP2pServiceInfo> mServList;
   3122 
   3123         private ClientInfo(Messenger m) {
   3124             mMessenger = m;
   3125             mReqList = new SparseArray();
   3126             mServList = new ArrayList<WifiP2pServiceInfo>();
   3127         }
   3128     }
   3129 }
   3130