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             WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes();
   1783             attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
   1784             dialog.getWindow().setAttributes(attrs);
   1785             dialog.show();
   1786             mFrequencyConflictDialog = dialog;
   1787         }
   1788 
   1789         @Override
   1790         public boolean processMessage(Message message) {
   1791             if (DBG) logd(getName() + message.toString());
   1792             switch (message.what) {
   1793                 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
   1794                 case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:
   1795                     loge(getName() + "group sucess during freq conflict!");
   1796                     break;
   1797                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
   1798                     loge(getName() + "group started after freq conflict, handle anyway");
   1799                     deferMessage(message);
   1800                     transitionTo(mGroupNegotiationState);
   1801                     break;
   1802                 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
   1803                 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
   1804                 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
   1805                     // Ignore failures since we retry again
   1806                     break;
   1807                 case DROP_WIFI_USER_REJECT:
   1808                     // User rejected dropping wifi in favour of p2p
   1809                     handleGroupCreationFailure();
   1810                     transitionTo(mInactiveState);
   1811                     break;
   1812                 case DROP_WIFI_USER_ACCEPT:
   1813                     // User accepted dropping wifi in favour of p2p
   1814                     mWifiChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST, 1);
   1815                     mTemporarilyDisconnectedWifi = true;
   1816                     break;
   1817                 case DISCONNECT_WIFI_RESPONSE:
   1818                     // Got a response from wifistatemachine, retry p2p
   1819                     if (DBG) logd(getName() + "Wifi disconnected, retry p2p");
   1820                     transitionTo(mInactiveState);
   1821                     sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
   1822                     break;
   1823                 default:
   1824                     return NOT_HANDLED;
   1825             }
   1826             return HANDLED;
   1827         }
   1828 
   1829         public void exit() {
   1830             if (mFrequencyConflictDialog != null) mFrequencyConflictDialog.dismiss();
   1831         }
   1832     }
   1833 
   1834     class GroupCreatedState extends State {
   1835         @Override
   1836         public void enter() {
   1837             if (DBG) logd(getName());
   1838             // Once connected, peer config details are invalid
   1839             mSavedPeerConfig.invalidate();
   1840             mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
   1841 
   1842             updateThisDevice(WifiP2pDevice.CONNECTED);
   1843 
   1844             //DHCP server has already been started if I am a group owner
   1845             if (mGroup.isGroupOwner()) {
   1846                 setWifiP2pInfoOnGroupFormation(NetworkUtils.numericToInetAddress(SERVER_ADDRESS));
   1847             }
   1848 
   1849             // In case of a negotiation group, connection changed is sent
   1850             // after a client joins. For autonomous, send now
   1851             if (mAutonomousGroup) {
   1852                 sendP2pConnectionChangedBroadcast();
   1853             }
   1854         }
   1855 
   1856         @Override
   1857         public boolean processMessage(Message message) {
   1858             if (DBG) logd(getName() + message.toString());
   1859             switch (message.what) {
   1860                 case WifiMonitor.AP_STA_CONNECTED_EVENT:
   1861                     WifiP2pDevice device = (WifiP2pDevice) message.obj;
   1862                     String deviceAddress = device.deviceAddress;
   1863                     // Clear timeout that was set when group was started.
   1864                     mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0);
   1865                     if (deviceAddress != null) {
   1866                         if (mPeers.get(deviceAddress) != null) {
   1867                             mGroup.addClient(mPeers.get(deviceAddress));
   1868                         } else {
   1869                             mGroup.addClient(deviceAddress);
   1870                         }
   1871                         mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED);
   1872                         if (DBG) logd(getName() + " ap sta connected");
   1873                         sendPeersChangedBroadcast();
   1874                     } else {
   1875                         loge("Connect on null device address, ignore");
   1876                     }
   1877                     sendP2pConnectionChangedBroadcast();
   1878                     break;
   1879                 case WifiMonitor.AP_STA_DISCONNECTED_EVENT:
   1880                     device = (WifiP2pDevice) message.obj;
   1881                     deviceAddress = device.deviceAddress;
   1882                     if (deviceAddress != null) {
   1883                         mPeers.updateStatus(deviceAddress, WifiP2pDevice.AVAILABLE);
   1884                         if (mGroup.removeClient(deviceAddress)) {
   1885                             if (DBG) logd("Removed client " + deviceAddress);
   1886                             if (!mAutonomousGroup && mGroup.isClientListEmpty()) {
   1887                                 logd("Client list empty, remove non-persistent p2p group");
   1888                                 mWifiNative.p2pGroupRemove(mGroup.getInterface());
   1889                                 // We end up sending connection changed broadcast
   1890                                 // when this happens at exit()
   1891                             } else {
   1892                                 // Notify when a client disconnects from group
   1893                                 sendP2pConnectionChangedBroadcast();
   1894                             }
   1895                         } else {
   1896                             if (DBG) logd("Failed to remove client " + deviceAddress);
   1897                             for (WifiP2pDevice c : mGroup.getClientList()) {
   1898                                 if (DBG) logd("client " + c.deviceAddress);
   1899                             }
   1900                         }
   1901                         sendPeersChangedBroadcast();
   1902                         if (DBG) logd(getName() + " ap sta disconnected");
   1903                     } else {
   1904                         loge("Disconnect on unknown device: " + device);
   1905                     }
   1906                     break;
   1907                 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
   1908                     DhcpResults dhcpResults = (DhcpResults) message.obj;
   1909                     if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS &&
   1910                             dhcpResults != null) {
   1911                         if (DBG) logd("DhcpResults: " + dhcpResults);
   1912                         setWifiP2pInfoOnGroupFormation(dhcpResults.serverAddress);
   1913                         sendP2pConnectionChangedBroadcast();
   1914                         //Turn on power save on client
   1915                         mWifiNative.setP2pPowerSave(mGroup.getInterface(), true);
   1916                         try {
   1917                             String iface = mGroup.getInterface();
   1918                             mNwService.addInterfaceToLocalNetwork(iface,
   1919                                                                   dhcpResults.getRoutes(iface));
   1920                         } catch (RemoteException e) {
   1921                             loge("Failed to add iface to local network " + e);
   1922                         }
   1923                     } else {
   1924                         loge("DHCP failed");
   1925                         mWifiNative.p2pGroupRemove(mGroup.getInterface());
   1926                     }
   1927                     break;
   1928                 case WifiP2pManager.REMOVE_GROUP:
   1929                     if (DBG) logd(getName() + " remove group");
   1930                     if (mWifiNative.p2pGroupRemove(mGroup.getInterface())) {
   1931                         transitionTo(mOngoingGroupRemovalState);
   1932                         replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED);
   1933                     } else {
   1934                         handleGroupRemoved();
   1935                         transitionTo(mInactiveState);
   1936                         replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
   1937                                 WifiP2pManager.ERROR);
   1938                     }
   1939                     break;
   1940                 /* We do not listen to NETWORK_DISCONNECTION_EVENT for group removal
   1941                  * handling since supplicant actually tries to reconnect after a temporary
   1942                  * disconnect until group idle time out. Eventually, a group removal event
   1943                  * will come when group has been removed.
   1944                  *
   1945                  * When there are connectivity issues during temporary disconnect, the application
   1946                  * will also just remove the group.
   1947                  *
   1948                  * Treating network disconnection as group removal causes race conditions since
   1949                  * supplicant would still maintain the group at that stage.
   1950                  */
   1951                 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
   1952                     if (DBG) logd(getName() + " group removed");
   1953                     handleGroupRemoved();
   1954                     transitionTo(mInactiveState);
   1955                     break;
   1956                 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
   1957                     device = (WifiP2pDevice) message.obj;
   1958                     //Device loss for a connected device indicates it is not in discovery any more
   1959                     if (mGroup.contains(device)) {
   1960                         if (DBG) logd("Add device to lost list " + device);
   1961                         mPeersLostDuringConnection.updateSupplicantDetails(device);
   1962                         return HANDLED;
   1963                     }
   1964                     // Do the regular device lost handling
   1965                     return NOT_HANDLED;
   1966                 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
   1967                     sendMessage(WifiP2pManager.REMOVE_GROUP);
   1968                     deferMessage(message);
   1969                     break;
   1970                     // This allows any client to join the GO during the
   1971                     // WPS window
   1972                 case WifiP2pManager.START_WPS:
   1973                     WpsInfo wps = (WpsInfo) message.obj;
   1974                     if (wps == null) {
   1975                         replyToMessage(message, WifiP2pManager.START_WPS_FAILED);
   1976                         break;
   1977                     }
   1978                     boolean ret = true;
   1979                     if (wps.setup == WpsInfo.PBC) {
   1980                         ret = mWifiNative.startWpsPbc(mGroup.getInterface(), null);
   1981                     } else {
   1982                         if (wps.pin == null) {
   1983                             String pin = mWifiNative.startWpsPinDisplay(mGroup.getInterface());
   1984                             try {
   1985                                 Integer.parseInt(pin);
   1986                                 notifyInvitationSent(pin, "any");
   1987                             } catch (NumberFormatException ignore) {
   1988                                 ret = false;
   1989                             }
   1990                         } else {
   1991                             ret = mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
   1992                                     wps.pin);
   1993                         }
   1994                     }
   1995                     replyToMessage(message, ret ? WifiP2pManager.START_WPS_SUCCEEDED :
   1996                             WifiP2pManager.START_WPS_FAILED);
   1997                     break;
   1998                 case WifiP2pManager.CONNECT:
   1999                     WifiP2pConfig config = (WifiP2pConfig) message.obj;
   2000                     if (isConfigInvalid(config)) {
   2001                         loge("Dropping connect requeset " + config);
   2002                         replyToMessage(message, WifiP2pManager.CONNECT_FAILED);
   2003                         break;
   2004                     }
   2005                     logd("Inviting device : " + config.deviceAddress);
   2006                     mSavedPeerConfig = config;
   2007                     if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) {
   2008                         mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED);
   2009                         sendPeersChangedBroadcast();
   2010                         replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
   2011                     } else {
   2012                         replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
   2013                                 WifiP2pManager.ERROR);
   2014                     }
   2015                     // TODO: figure out updating the status to declined when invitation is rejected
   2016                     break;
   2017                 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
   2018                     P2pStatus status = (P2pStatus)message.obj;
   2019                     if (status == P2pStatus.SUCCESS) {
   2020                         // invocation was succeeded.
   2021                         break;
   2022                     }
   2023                     loge("Invitation result " + status);
   2024                     if (status == P2pStatus.UNKNOWN_P2P_GROUP) {
   2025                         // target device has already removed the credential.
   2026                         // So, remove this credential accordingly.
   2027                         int netId = mGroup.getNetworkId();
   2028                         if (netId >= 0) {
   2029                             if (DBG) logd("Remove unknown client from the list");
   2030                             if (!removeClientFromList(netId,
   2031                                     mSavedPeerConfig.deviceAddress, false)) {
   2032                                 // not found the client on the list
   2033                                 loge("Already removed the client, ignore");
   2034                                 break;
   2035                             }
   2036                             // try invitation.
   2037                             sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
   2038                         }
   2039                     }
   2040                     break;
   2041                 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
   2042                 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
   2043                 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
   2044                     WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj;
   2045                     mSavedPeerConfig = new WifiP2pConfig();
   2046                     mSavedPeerConfig.deviceAddress = provDisc.device.deviceAddress;
   2047                     if (message.what == WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) {
   2048                         mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD;
   2049                     } else if (message.what == WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT) {
   2050                         mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;
   2051                         mSavedPeerConfig.wps.pin = provDisc.pin;
   2052                     } else {
   2053                         mSavedPeerConfig.wps.setup = WpsInfo.PBC;
   2054                     }
   2055                     transitionTo(mUserAuthorizingJoinState);
   2056                     break;
   2057                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
   2058                     loge("Duplicate group creation event notice, ignore");
   2059                     break;
   2060                 default:
   2061                     return NOT_HANDLED;
   2062             }
   2063             return HANDLED;
   2064         }
   2065 
   2066         public void exit() {
   2067             updateThisDevice(WifiP2pDevice.AVAILABLE);
   2068             resetWifiP2pInfo();
   2069             mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
   2070             sendP2pConnectionChangedBroadcast();
   2071         }
   2072     }
   2073 
   2074     class UserAuthorizingJoinState extends State {
   2075         @Override
   2076         public void enter() {
   2077             if (DBG) logd(getName());
   2078             notifyInvitationReceived();
   2079         }
   2080 
   2081         @Override
   2082         public boolean processMessage(Message message) {
   2083             if (DBG) logd(getName() + message.toString());
   2084             switch (message.what) {
   2085                 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
   2086                 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
   2087                 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
   2088                     //Ignore more client requests
   2089                     break;
   2090                 case PEER_CONNECTION_USER_ACCEPT:
   2091                     //Stop discovery to avoid failure due to channel switch
   2092                     mWifiNative.p2pStopFind();
   2093                     if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
   2094                         mWifiNative.startWpsPbc(mGroup.getInterface(), null);
   2095                     } else {
   2096                         mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
   2097                                 mSavedPeerConfig.wps.pin);
   2098                     }
   2099                     transitionTo(mGroupCreatedState);
   2100                     break;
   2101                 case PEER_CONNECTION_USER_REJECT:
   2102                     if (DBG) logd("User rejected incoming request");
   2103                     transitionTo(mGroupCreatedState);
   2104                     break;
   2105                 default:
   2106                     return NOT_HANDLED;
   2107             }
   2108             return HANDLED;
   2109         }
   2110 
   2111         @Override
   2112         public void exit() {
   2113             //TODO: dismiss dialog if not already done
   2114         }
   2115     }
   2116 
   2117     class OngoingGroupRemovalState extends State {
   2118         @Override
   2119         public void enter() {
   2120             if (DBG) logd(getName());
   2121         }
   2122 
   2123         @Override
   2124         public boolean processMessage(Message message) {
   2125             if (DBG) logd(getName() + message.toString());
   2126             switch (message.what) {
   2127                 // Group removal ongoing. Multiple calls
   2128                 // end up removing persisted network. Do nothing.
   2129                 case WifiP2pManager.REMOVE_GROUP:
   2130                     replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED);
   2131                     break;
   2132                 // Parent state will transition out of this state
   2133                 // when removal is complete
   2134                 default:
   2135                     return NOT_HANDLED;
   2136             }
   2137             return HANDLED;
   2138         }
   2139     }
   2140 
   2141     @Override
   2142     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   2143         super.dump(fd, pw, args);
   2144         pw.println("mWifiP2pInfo " + mWifiP2pInfo);
   2145         pw.println("mGroup " + mGroup);
   2146         pw.println("mSavedPeerConfig " + mSavedPeerConfig);
   2147         pw.println("mSavedP2pGroup " + mSavedP2pGroup);
   2148         pw.println();
   2149     }
   2150 
   2151     private void sendP2pStateChangedBroadcast(boolean enabled) {
   2152         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
   2153         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   2154         if (enabled) {
   2155             intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE,
   2156                     WifiP2pManager.WIFI_P2P_STATE_ENABLED);
   2157         } else {
   2158             intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE,
   2159                     WifiP2pManager.WIFI_P2P_STATE_DISABLED);
   2160         }
   2161         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   2162     }
   2163 
   2164     private void sendP2pDiscoveryChangedBroadcast(boolean started) {
   2165         if (mDiscoveryStarted == started) return;
   2166         mDiscoveryStarted = started;
   2167 
   2168         if (DBG) logd("discovery change broadcast " + started);
   2169 
   2170         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);
   2171         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   2172         intent.putExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE, started ?
   2173                 WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED :
   2174                 WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED);
   2175         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   2176     }
   2177 
   2178     private void sendThisDeviceChangedBroadcast() {
   2179         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
   2180         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   2181         intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE, new WifiP2pDevice(mThisDevice));
   2182         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   2183     }
   2184 
   2185     private void sendPeersChangedBroadcast() {
   2186         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
   2187         intent.putExtra(WifiP2pManager.EXTRA_P2P_DEVICE_LIST, new WifiP2pDeviceList(mPeers));
   2188         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   2189         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
   2190     }
   2191 
   2192     private void sendP2pConnectionChangedBroadcast() {
   2193         if (DBG) logd("sending p2p connection changed broadcast");
   2194         Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
   2195         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
   2196                 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
   2197         intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, new WifiP2pInfo(mWifiP2pInfo));
   2198         intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
   2199         intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, new WifiP2pGroup(mGroup));
   2200         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   2201         mWifiChannel.sendMessage(WifiP2pServiceImpl.P2P_CONNECTION_CHANGED,
   2202                 new NetworkInfo(mNetworkInfo));
   2203     }
   2204 
   2205     private void sendP2pPersistentGroupsChangedBroadcast() {
   2206         if (DBG) logd("sending p2p persistent groups changed broadcast");
   2207         Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION);
   2208         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   2209         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   2210     }
   2211 
   2212     private void startDhcpServer(String intf) {
   2213         InterfaceConfiguration ifcg = null;
   2214         try {
   2215             ifcg = mNwService.getInterfaceConfig(intf);
   2216             ifcg.setLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress(
   2217                         SERVER_ADDRESS), 24));
   2218             ifcg.setInterfaceUp();
   2219             mNwService.setInterfaceConfig(intf, ifcg);
   2220             /* This starts the dnsmasq server */
   2221             ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
   2222                     Context.CONNECTIVITY_SERVICE);
   2223             String[] tetheringDhcpRanges = cm.getTetheredDhcpRanges();
   2224             if (mNwService.isTetheringStarted()) {
   2225                 if (DBG) logd("Stop existing tethering and restart it");
   2226                 mNwService.stopTethering();
   2227             }
   2228             mNwService.tetherInterface(intf);
   2229             mNwService.startTethering(tetheringDhcpRanges);
   2230         } catch (Exception e) {
   2231             loge("Error configuring interface " + intf + ", :" + e);
   2232             return;
   2233         }
   2234 
   2235         logd("Started Dhcp server on " + intf);
   2236    }
   2237 
   2238     private void stopDhcpServer(String intf) {
   2239         try {
   2240             mNwService.untetherInterface(intf);
   2241             for (String temp : mNwService.listTetheredInterfaces()) {
   2242                 logd("List all interfaces " + temp);
   2243                 if (temp.compareTo(intf) != 0) {
   2244                     logd("Found other tethering interfaces, so keep tethering alive");
   2245                     return;
   2246                 }
   2247             }
   2248             mNwService.stopTethering();
   2249         } catch (Exception e) {
   2250             loge("Error stopping Dhcp server" + e);
   2251             return;
   2252         } finally {
   2253             logd("Stopped Dhcp server");
   2254         }
   2255     }
   2256 
   2257     private void notifyP2pEnableFailure() {
   2258         Resources r = Resources.getSystem();
   2259         AlertDialog dialog = new AlertDialog.Builder(mContext)
   2260             .setTitle(r.getString(R.string.wifi_p2p_dialog_title))
   2261             .setMessage(r.getString(R.string.wifi_p2p_failed_message))
   2262             .setPositiveButton(r.getString(R.string.ok), null)
   2263             .create();
   2264         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
   2265         WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes();
   2266         attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
   2267         dialog.getWindow().setAttributes(attrs);
   2268         dialog.show();
   2269     }
   2270 
   2271     private void addRowToDialog(ViewGroup group, int stringId, String value) {
   2272         Resources r = Resources.getSystem();
   2273         View row = LayoutInflater.from(mContext).inflate(R.layout.wifi_p2p_dialog_row,
   2274                 group, false);
   2275         ((TextView) row.findViewById(R.id.name)).setText(r.getString(stringId));
   2276         ((TextView) row.findViewById(R.id.value)).setText(value);
   2277         group.addView(row);
   2278     }
   2279 
   2280     private void notifyInvitationSent(String pin, String peerAddress) {
   2281         Resources r = Resources.getSystem();
   2282 
   2283         final View textEntryView = LayoutInflater.from(mContext)
   2284                 .inflate(R.layout.wifi_p2p_dialog, null);
   2285 
   2286         ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info);
   2287         addRowToDialog(group, R.string.wifi_p2p_to_message, getDeviceName(peerAddress));
   2288         addRowToDialog(group, R.string.wifi_p2p_show_pin_message, pin);
   2289 
   2290         AlertDialog dialog = new AlertDialog.Builder(mContext)
   2291             .setTitle(r.getString(R.string.wifi_p2p_invitation_sent_title))
   2292             .setView(textEntryView)
   2293             .setPositiveButton(r.getString(R.string.ok), null)
   2294             .create();
   2295         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
   2296         WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes();
   2297         attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
   2298         dialog.getWindow().setAttributes(attrs);
   2299         dialog.show();
   2300     }
   2301 
   2302     private void notifyInvitationReceived() {
   2303         Resources r = Resources.getSystem();
   2304         final WpsInfo wps = mSavedPeerConfig.wps;
   2305         final View textEntryView = LayoutInflater.from(mContext)
   2306                 .inflate(R.layout.wifi_p2p_dialog, null);
   2307 
   2308         ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info);
   2309         addRowToDialog(group, R.string.wifi_p2p_from_message, getDeviceName(
   2310                 mSavedPeerConfig.deviceAddress));
   2311 
   2312         final EditText pin = (EditText) textEntryView.findViewById(R.id.wifi_p2p_wps_pin);
   2313 
   2314         AlertDialog dialog = new AlertDialog.Builder(mContext)
   2315             .setTitle(r.getString(R.string.wifi_p2p_invitation_to_connect_title))
   2316             .setView(textEntryView)
   2317             .setPositiveButton(r.getString(R.string.accept), new OnClickListener() {
   2318                         public void onClick(DialogInterface dialog, int which) {
   2319                             if (wps.setup == WpsInfo.KEYPAD) {
   2320                                 mSavedPeerConfig.wps.pin = pin.getText().toString();
   2321                             }
   2322                             if (DBG) logd(getName() + " accept invitation " + mSavedPeerConfig);
   2323                             sendMessage(PEER_CONNECTION_USER_ACCEPT);
   2324                         }
   2325                     })
   2326             .setNegativeButton(r.getString(R.string.decline), new OnClickListener() {
   2327                         @Override
   2328                         public void onClick(DialogInterface dialog, int which) {
   2329                             if (DBG) logd(getName() + " ignore connect");
   2330                             sendMessage(PEER_CONNECTION_USER_REJECT);
   2331                         }
   2332                     })
   2333             .setOnCancelListener(new DialogInterface.OnCancelListener() {
   2334                         @Override
   2335                         public void onCancel(DialogInterface arg0) {
   2336                             if (DBG) logd(getName() + " ignore connect");
   2337                             sendMessage(PEER_CONNECTION_USER_REJECT);
   2338                         }
   2339                     })
   2340             .create();
   2341 
   2342         //make the enter pin area or the display pin area visible
   2343         switch (wps.setup) {
   2344             case WpsInfo.KEYPAD:
   2345                 if (DBG) logd("Enter pin section visible");
   2346                 textEntryView.findViewById(R.id.enter_pin_section).setVisibility(View.VISIBLE);
   2347                 break;
   2348             case WpsInfo.DISPLAY:
   2349                 if (DBG) logd("Shown pin section visible");
   2350                 addRowToDialog(group, R.string.wifi_p2p_show_pin_message, wps.pin);
   2351                 break;
   2352             default:
   2353                 break;
   2354         }
   2355 
   2356         if ((r.getConfiguration().uiMode & Configuration.UI_MODE_TYPE_APPLIANCE) ==
   2357                 Configuration.UI_MODE_TYPE_APPLIANCE) {
   2358             // For appliance devices, add a key listener which accepts.
   2359             dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
   2360 
   2361                 @Override
   2362                 public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
   2363                     // TODO: make the actual key come from a config value.
   2364                     if (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
   2365                         sendMessage(PEER_CONNECTION_USER_ACCEPT);
   2366                         dialog.dismiss();
   2367                         return true;
   2368                     }
   2369                     return false;
   2370                 }
   2371             });
   2372             // TODO: add timeout for this dialog.
   2373             // TODO: update UI in appliance mode to tell user what to do.
   2374         }
   2375 
   2376         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
   2377         WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes();
   2378         attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
   2379         dialog.getWindow().setAttributes(attrs);
   2380         dialog.show();
   2381     }
   2382 
   2383     /**
   2384      * Synchronize the persistent group list between
   2385      * wpa_supplicant and mGroups.
   2386      */
   2387     private void updatePersistentNetworks(boolean reload) {
   2388         String listStr = mWifiNative.listNetworks();
   2389         if (listStr == null) return;
   2390 
   2391         boolean isSaveRequired = false;
   2392         String[] lines = listStr.split("\n");
   2393         if (lines == null) return;
   2394 
   2395         if (reload) mGroups.clear();
   2396 
   2397         // Skip the first line, which is a header
   2398         for (int i = 1; i < lines.length; i++) {
   2399             String[] result = lines[i].split("\t");
   2400             if (result == null || result.length < 4) {
   2401                 continue;
   2402             }
   2403             // network-id | ssid | bssid | flags
   2404             int netId = -1;
   2405             String ssid = result[1];
   2406             String bssid = result[2];
   2407             String flags = result[3];
   2408             try {
   2409                 netId = Integer.parseInt(result[0]);
   2410             } catch(NumberFormatException e) {
   2411                 e.printStackTrace();
   2412                 continue;
   2413             }
   2414 
   2415             if (flags.indexOf("[CURRENT]") != -1) {
   2416                 continue;
   2417             }
   2418             if (flags.indexOf("[P2P-PERSISTENT]") == -1) {
   2419                 /*
   2420                  * The unused profile is sometimes remained when the p2p group formation is failed.
   2421                  * So, we clean up the p2p group here.
   2422                  */
   2423                 if (DBG) logd("clean up the unused persistent group. netId=" + netId);
   2424                 mWifiNative.removeNetwork(netId);
   2425                 isSaveRequired = true;
   2426                 continue;
   2427             }
   2428 
   2429             if (mGroups.contains(netId)) {
   2430                 continue;
   2431             }
   2432 
   2433             WifiP2pGroup group = new WifiP2pGroup();
   2434             group.setNetworkId(netId);
   2435             group.setNetworkName(ssid);
   2436             String mode = mWifiNative.getNetworkVariable(netId, "mode");
   2437             if (mode != null && mode.equals("3")) {
   2438                 group.setIsGroupOwner(true);
   2439             }
   2440             if (bssid.equalsIgnoreCase(mThisDevice.deviceAddress)) {
   2441                 group.setOwner(mThisDevice);
   2442             } else {
   2443                 WifiP2pDevice device = new WifiP2pDevice();
   2444                 device.deviceAddress = bssid;
   2445                 group.setOwner(device);
   2446             }
   2447             mGroups.add(group);
   2448             isSaveRequired = true;
   2449         }
   2450 
   2451         if (reload || isSaveRequired) {
   2452             mWifiNative.saveConfig();
   2453             sendP2pPersistentGroupsChangedBroadcast();
   2454         }
   2455     }
   2456 
   2457     /**
   2458      * A config is valid if it has a peer address that has already been
   2459      * discovered
   2460      * @return true if it is invalid, false otherwise
   2461      */
   2462     private boolean isConfigInvalid(WifiP2pConfig config) {
   2463         if (config == null) return true;
   2464         if (TextUtils.isEmpty(config.deviceAddress)) return true;
   2465         if (mPeers.get(config.deviceAddress) == null) return true;
   2466         return false;
   2467     }
   2468 
   2469     /* TODO: The supplicant does not provide group capability changes as an event.
   2470      * Having it pushed as an event would avoid polling for this information right
   2471      * before a connection
   2472      */
   2473     private WifiP2pDevice fetchCurrentDeviceDetails(WifiP2pConfig config) {
   2474         /* Fetch & update group capability from supplicant on the device */
   2475         int gc = mWifiNative.getGroupCapability(config.deviceAddress);
   2476         mPeers.updateGroupCapability(config.deviceAddress, gc);
   2477         return mPeers.get(config.deviceAddress);
   2478     }
   2479 
   2480     /**
   2481      * Start a p2p group negotiation and display pin if necessary
   2482      * @param config for the peer
   2483      */
   2484     private void p2pConnectWithPinDisplay(WifiP2pConfig config) {
   2485         WifiP2pDevice dev = fetchCurrentDeviceDetails(config);
   2486 
   2487         String pin = mWifiNative.p2pConnect(config, dev.isGroupOwner());
   2488         try {
   2489             Integer.parseInt(pin);
   2490             notifyInvitationSent(pin, config.deviceAddress);
   2491         } catch (NumberFormatException ignore) {
   2492             // do nothing if p2pConnect did not return a pin
   2493         }
   2494     }
   2495 
   2496     /**
   2497      * Reinvoke a persistent group.
   2498      *
   2499      * @param config for the peer
   2500      * @return true on success, false on failure
   2501      */
   2502     private boolean reinvokePersistentGroup(WifiP2pConfig config) {
   2503         WifiP2pDevice dev = fetchCurrentDeviceDetails(config);
   2504 
   2505         boolean join = dev.isGroupOwner();
   2506         String ssid = mWifiNative.p2pGetSsid(dev.deviceAddress);
   2507         if (DBG) logd("target ssid is " + ssid + " join:" + join);
   2508 
   2509         if (join && dev.isGroupLimit()) {
   2510             if (DBG) logd("target device reaches group limit.");
   2511 
   2512             // if the target group has reached the limit,
   2513             // try group formation.
   2514             join = false;
   2515         } else if (join) {
   2516             int netId = mGroups.getNetworkId(dev.deviceAddress, ssid);
   2517             if (netId >= 0) {
   2518                 // Skip WPS and start 4way handshake immediately.
   2519                 if (!mWifiNative.p2pGroupAdd(netId)) {
   2520                     return false;
   2521                 }
   2522                 return true;
   2523             }
   2524         }
   2525 
   2526         if (!join && dev.isDeviceLimit()) {
   2527             loge("target device reaches the device limit.");
   2528             return false;
   2529         }
   2530 
   2531         if (!join && dev.isInvitationCapable()) {
   2532             int netId = WifiP2pGroup.PERSISTENT_NET_ID;
   2533             if (config.netId >= 0) {
   2534                 if (config.deviceAddress.equals(mGroups.getOwnerAddr(config.netId))) {
   2535                     netId = config.netId;
   2536                 }
   2537             } else {
   2538                 netId = mGroups.getNetworkId(dev.deviceAddress);
   2539             }
   2540             if (netId < 0) {
   2541                 netId = getNetworkIdFromClientList(dev.deviceAddress);
   2542             }
   2543             if (DBG) logd("netId related with " + dev.deviceAddress + " = " + netId);
   2544             if (netId >= 0) {
   2545                 // Invoke the persistent group.
   2546                 if (mWifiNative.p2pReinvoke(netId, dev.deviceAddress)) {
   2547                     // Save network id. It'll be used when an invitation result event is received.
   2548                     config.netId = netId;
   2549                     return true;
   2550                 } else {
   2551                     loge("p2pReinvoke() failed, update networks");
   2552                     updatePersistentNetworks(RELOAD);
   2553                     return false;
   2554                 }
   2555             }
   2556         }
   2557 
   2558         return false;
   2559     }
   2560 
   2561     /**
   2562      * Return the network id of the group owner profile which has the p2p client with
   2563      * the specified device address in it's client list.
   2564      * If more than one persistent group of the same address is present in its client
   2565      * lists, return the first one.
   2566      *
   2567      * @param deviceAddress p2p device address.
   2568      * @return the network id. if not found, return -1.
   2569      */
   2570     private int getNetworkIdFromClientList(String deviceAddress) {
   2571         if (deviceAddress == null) return -1;
   2572 
   2573         Collection<WifiP2pGroup> groups = mGroups.getGroupList();
   2574         for (WifiP2pGroup group : groups) {
   2575             int netId = group.getNetworkId();
   2576             String[] p2pClientList = getClientList(netId);
   2577             if (p2pClientList == null) continue;
   2578             for (String client : p2pClientList) {
   2579                 if (deviceAddress.equalsIgnoreCase(client)) {
   2580                     return netId;
   2581                 }
   2582             }
   2583         }
   2584         return -1;
   2585     }
   2586 
   2587     /**
   2588      * Return p2p client list associated with the specified network id.
   2589      * @param netId network id.
   2590      * @return p2p client list. if not found, return null.
   2591      */
   2592     private String[] getClientList(int netId) {
   2593         String p2pClients = mWifiNative.getNetworkVariable(netId, "p2p_client_list");
   2594         if (p2pClients == null) {
   2595             return null;
   2596         }
   2597         return p2pClients.split(" ");
   2598     }
   2599 
   2600     /**
   2601      * Remove the specified p2p client from the specified profile.
   2602      * @param netId network id of the profile.
   2603      * @param addr p2p client address to be removed.
   2604      * @param isRemovable if true, remove the specified profile if its client list becomes empty.
   2605      * @return whether removing the specified p2p client is successful or not.
   2606      */
   2607     private boolean removeClientFromList(int netId, String addr, boolean isRemovable) {
   2608         StringBuilder modifiedClientList =  new StringBuilder();
   2609         String[] currentClientList = getClientList(netId);
   2610         boolean isClientRemoved = false;
   2611         if (currentClientList != null) {
   2612             for (String client : currentClientList) {
   2613                 if (!client.equalsIgnoreCase(addr)) {
   2614                     modifiedClientList.append(" ");
   2615                     modifiedClientList.append(client);
   2616                 } else {
   2617                     isClientRemoved = true;
   2618                 }
   2619             }
   2620         }
   2621         if (modifiedClientList.length() == 0 && isRemovable) {
   2622             // the client list is empty. so remove it.
   2623             if (DBG) logd("Remove unknown network");
   2624             mGroups.remove(netId);
   2625             return true;
   2626         }
   2627 
   2628         if (!isClientRemoved) {
   2629             // specified p2p client is not found. already removed.
   2630             return false;
   2631         }
   2632 
   2633         if (DBG) logd("Modified client list: " + modifiedClientList);
   2634         if (modifiedClientList.length() == 0) {
   2635             modifiedClientList.append("\"\"");
   2636         }
   2637         mWifiNative.setNetworkVariable(netId,
   2638                 "p2p_client_list", modifiedClientList.toString());
   2639         mWifiNative.saveConfig();
   2640         return true;
   2641     }
   2642 
   2643     private void setWifiP2pInfoOnGroupFormation(InetAddress serverInetAddress) {
   2644         mWifiP2pInfo.groupFormed = true;
   2645         mWifiP2pInfo.isGroupOwner = mGroup.isGroupOwner();
   2646         mWifiP2pInfo.groupOwnerAddress = serverInetAddress;
   2647     }
   2648 
   2649     private void resetWifiP2pInfo() {
   2650         mWifiP2pInfo.groupFormed = false;
   2651         mWifiP2pInfo.isGroupOwner = false;
   2652         mWifiP2pInfo.groupOwnerAddress = null;
   2653     }
   2654 
   2655     private String getDeviceName(String deviceAddress) {
   2656         WifiP2pDevice d = mPeers.get(deviceAddress);
   2657         if (d != null) {
   2658                 return d.deviceName;
   2659         }
   2660         //Treat the address as name if there is no match
   2661         return deviceAddress;
   2662     }
   2663 
   2664     private String getPersistedDeviceName() {
   2665         String deviceName = Settings.Global.getString(mContext.getContentResolver(),
   2666                 Settings.Global.WIFI_P2P_DEVICE_NAME);
   2667         if (deviceName == null) {
   2668             /* We use the 4 digits of the ANDROID_ID to have a friendly
   2669              * default that has low likelihood of collision with a peer */
   2670             String id = Settings.Secure.getString(mContext.getContentResolver(),
   2671                     Settings.Secure.ANDROID_ID);
   2672             return "Android_" + id.substring(0,4);
   2673         }
   2674         return deviceName;
   2675     }
   2676 
   2677     private boolean setAndPersistDeviceName(String devName) {
   2678         if (devName == null) return false;
   2679 
   2680         if (!mWifiNative.setDeviceName(devName)) {
   2681             loge("Failed to set device name " + devName);
   2682             return false;
   2683         }
   2684 
   2685         mThisDevice.deviceName = devName;
   2686         mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName);
   2687 
   2688         Settings.Global.putString(mContext.getContentResolver(),
   2689                 Settings.Global.WIFI_P2P_DEVICE_NAME, devName);
   2690         sendThisDeviceChangedBroadcast();
   2691         return true;
   2692     }
   2693 
   2694     private boolean setWfdInfo(WifiP2pWfdInfo wfdInfo) {
   2695         boolean success;
   2696 
   2697         if (!wfdInfo.isWfdEnabled()) {
   2698             success = mWifiNative.setWfdEnable(false);
   2699         } else {
   2700             success =
   2701                 mWifiNative.setWfdEnable(true)
   2702                 && mWifiNative.setWfdDeviceInfo(wfdInfo.getDeviceInfoHex());
   2703         }
   2704 
   2705         if (!success) {
   2706             loge("Failed to set wfd properties");
   2707             return false;
   2708         }
   2709 
   2710         mThisDevice.wfdInfo = wfdInfo;
   2711         sendThisDeviceChangedBroadcast();
   2712         return true;
   2713     }
   2714 
   2715     private void initializeP2pSettings() {
   2716         mWifiNative.setPersistentReconnect(true);
   2717         mThisDevice.deviceName = getPersistedDeviceName();
   2718         mWifiNative.setDeviceName(mThisDevice.deviceName);
   2719         // DIRECT-XY-DEVICENAME (XY is randomly generated)
   2720         mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName);
   2721         mWifiNative.setDeviceType(mThisDevice.primaryDeviceType);
   2722         // Supplicant defaults to using virtual display with display
   2723         // which refers to a remote display. Use physical_display
   2724         mWifiNative.setConfigMethods("virtual_push_button physical_display keypad");
   2725         // STA has higher priority over P2P
   2726         mWifiNative.setConcurrencyPriority("sta");
   2727 
   2728         mThisDevice.deviceAddress = mWifiNative.p2pGetDeviceAddress();
   2729         updateThisDevice(WifiP2pDevice.AVAILABLE);
   2730         if (DBG) logd("DeviceAddress: " + mThisDevice.deviceAddress);
   2731 
   2732         mClientInfoList.clear();
   2733         mWifiNative.p2pFlush();
   2734         mWifiNative.p2pServiceFlush();
   2735         mServiceTransactionId = 0;
   2736         mServiceDiscReqId = null;
   2737 
   2738         String countryCode = Settings.Global.getString(mContext.getContentResolver(),
   2739                 Settings.Global.WIFI_COUNTRY_CODE);
   2740         if (countryCode != null && !countryCode.isEmpty()) {
   2741             mP2pStateMachine.sendMessage(SET_COUNTRY_CODE, countryCode);
   2742         }
   2743 
   2744         updatePersistentNetworks(RELOAD);
   2745     }
   2746 
   2747     private void updateThisDevice(int status) {
   2748         mThisDevice.status = status;
   2749         sendThisDeviceChangedBroadcast();
   2750     }
   2751 
   2752     private void handleGroupCreationFailure() {
   2753         resetWifiP2pInfo();
   2754         mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.FAILED, null, null);
   2755         sendP2pConnectionChangedBroadcast();
   2756 
   2757         // Remove only the peer we failed to connect to so that other devices discovered
   2758         // that have not timed out still remain in list for connection
   2759         boolean peersChanged = mPeers.remove(mPeersLostDuringConnection);
   2760         if (TextUtils.isEmpty(mSavedPeerConfig.deviceAddress) == false &&
   2761                 mPeers.remove(mSavedPeerConfig.deviceAddress) != null) {
   2762             peersChanged = true;
   2763         }
   2764         if (peersChanged) {
   2765             sendPeersChangedBroadcast();
   2766         }
   2767 
   2768         mPeersLostDuringConnection.clear();
   2769         mServiceDiscReqId = null;
   2770         sendMessage(WifiP2pManager.DISCOVER_PEERS);
   2771     }
   2772 
   2773     private void handleGroupRemoved() {
   2774         if (mGroup.isGroupOwner()) {
   2775             stopDhcpServer(mGroup.getInterface());
   2776         } else {
   2777             if (DBG) logd("stop DHCP client");
   2778             mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
   2779             mDhcpStateMachine.doQuit();
   2780             mDhcpStateMachine = null;
   2781             try {
   2782                 mNwService.removeInterfaceFromLocalNetwork(mGroup.getInterface());
   2783             } catch (RemoteException e) {
   2784                 loge("Failed to remove iface from local network " + e);
   2785             }
   2786         }
   2787 
   2788         try {
   2789             mNwService.clearInterfaceAddresses(mGroup.getInterface());
   2790         } catch (Exception e) {
   2791             loge("Failed to clear addresses " + e);
   2792         }
   2793         NetworkUtils.resetConnections(mGroup.getInterface(), NetworkUtils.RESET_ALL_ADDRESSES);
   2794 
   2795         // Clear any timeout that was set. This is essential for devices
   2796         // that reuse the main p2p interface for a created group.
   2797         mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0);
   2798 
   2799         boolean peersChanged = false;
   2800         // Remove only peers part of the group, so that other devices discovered
   2801         // that have not timed out still remain in list for connection
   2802         for (WifiP2pDevice d : mGroup.getClientList()) {
   2803             if (mPeers.remove(d)) peersChanged = true;
   2804         }
   2805         if (mPeers.remove(mGroup.getOwner())) peersChanged = true;
   2806         if (mPeers.remove(mPeersLostDuringConnection)) peersChanged = true;
   2807         if (peersChanged) {
   2808             sendPeersChangedBroadcast();
   2809         }
   2810 
   2811         mGroup = null;
   2812         mPeersLostDuringConnection.clear();
   2813         mServiceDiscReqId = null;
   2814 
   2815         if (mTemporarilyDisconnectedWifi) {
   2816             mWifiChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST, 0);
   2817             mTemporarilyDisconnectedWifi = false;
   2818         }
   2819    }
   2820 
   2821     //State machine initiated requests can have replyTo set to null indicating
   2822     //there are no recipients, we ignore those reply actions
   2823     private void replyToMessage(Message msg, int what) {
   2824         if (msg.replyTo == null) return;
   2825         Message dstMsg = obtainMessage(msg);
   2826         dstMsg.what = what;
   2827         mReplyChannel.replyToMessage(msg, dstMsg);
   2828     }
   2829 
   2830     private void replyToMessage(Message msg, int what, int arg1) {
   2831         if (msg.replyTo == null) return;
   2832         Message dstMsg = obtainMessage(msg);
   2833         dstMsg.what = what;
   2834         dstMsg.arg1 = arg1;
   2835         mReplyChannel.replyToMessage(msg, dstMsg);
   2836     }
   2837 
   2838     private void replyToMessage(Message msg, int what, Object obj) {
   2839         if (msg.replyTo == null) return;
   2840         Message dstMsg = obtainMessage(msg);
   2841         dstMsg.what = what;
   2842         dstMsg.obj = obj;
   2843         mReplyChannel.replyToMessage(msg, dstMsg);
   2844     }
   2845 
   2846     /* arg2 on the source message has a hash code that needs to be retained in replies
   2847      * see WifiP2pManager for details */
   2848     private Message obtainMessage(Message srcMsg) {
   2849         Message msg = Message.obtain();
   2850         msg.arg2 = srcMsg.arg2;
   2851         return msg;
   2852     }
   2853 
   2854     @Override
   2855     protected void logd(String s) {
   2856         Slog.d(TAG, s);
   2857     }
   2858 
   2859     @Override
   2860     protected void loge(String s) {
   2861         Slog.e(TAG, s);
   2862     }
   2863 
   2864     /**
   2865      * Update service discovery request to wpa_supplicant.
   2866      */
   2867     private boolean updateSupplicantServiceRequest() {
   2868         clearSupplicantServiceRequest();
   2869 
   2870         StringBuffer sb = new StringBuffer();
   2871         for (ClientInfo c: mClientInfoList.values()) {
   2872             int key;
   2873             WifiP2pServiceRequest req;
   2874             for (int i=0; i < c.mReqList.size(); i++) {
   2875                 req = c.mReqList.valueAt(i);
   2876                 if (req != null) {
   2877                     sb.append(req.getSupplicantQuery());
   2878                 }
   2879             }
   2880         }
   2881 
   2882         if (sb.length() == 0) {
   2883             return false;
   2884         }
   2885 
   2886         mServiceDiscReqId = mWifiNative.p2pServDiscReq("00:00:00:00:00:00", sb.toString());
   2887         if (mServiceDiscReqId == null) {
   2888             return false;
   2889         }
   2890         return true;
   2891     }
   2892 
   2893     /**
   2894      * Clear service discovery request in wpa_supplicant
   2895      */
   2896     private void clearSupplicantServiceRequest() {
   2897         if (mServiceDiscReqId == null) return;
   2898 
   2899         mWifiNative.p2pServDiscCancelReq(mServiceDiscReqId);
   2900         mServiceDiscReqId = null;
   2901     }
   2902 
   2903     /* TODO: We could track individual service adds separately and avoid
   2904      * having to do update all service requests on every new request
   2905      */
   2906     private boolean addServiceRequest(Messenger m, WifiP2pServiceRequest req) {
   2907         clearClientDeadChannels();
   2908         ClientInfo clientInfo = getClientInfo(m, true);
   2909         if (clientInfo == null) {
   2910             return false;
   2911         }
   2912 
   2913         ++mServiceTransactionId;
   2914         //The Wi-Fi p2p spec says transaction id should be non-zero
   2915         if (mServiceTransactionId == 0) ++mServiceTransactionId;
   2916         req.setTransactionId(mServiceTransactionId);
   2917         clientInfo.mReqList.put(mServiceTransactionId, req);
   2918 
   2919         if (mServiceDiscReqId == null) {
   2920             return true;
   2921         }
   2922 
   2923         return updateSupplicantServiceRequest();
   2924     }
   2925 
   2926     private void removeServiceRequest(Messenger m, WifiP2pServiceRequest req) {
   2927         ClientInfo clientInfo = getClientInfo(m, false);
   2928         if (clientInfo == null) {
   2929             return;
   2930         }
   2931 
   2932         //Application does not have transaction id information
   2933         //go through stored requests to remove
   2934         boolean removed = false;
   2935         for (int i=0; i<clientInfo.mReqList.size(); i++) {
   2936             if (req.equals(clientInfo.mReqList.valueAt(i))) {
   2937                 removed = true;
   2938                 clientInfo.mReqList.removeAt(i);
   2939                 break;
   2940             }
   2941         }
   2942 
   2943         if (!removed) return;
   2944 
   2945         if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) {
   2946             if (DBG) logd("remove client information from framework");
   2947             mClientInfoList.remove(clientInfo.mMessenger);
   2948         }
   2949 
   2950         if (mServiceDiscReqId == null) {
   2951             return;
   2952         }
   2953 
   2954         updateSupplicantServiceRequest();
   2955     }
   2956 
   2957     private void clearServiceRequests(Messenger m) {
   2958 
   2959         ClientInfo clientInfo = getClientInfo(m, false);
   2960         if (clientInfo == null) {
   2961             return;
   2962         }
   2963 
   2964         if (clientInfo.mReqList.size() == 0) {
   2965             return;
   2966         }
   2967 
   2968         clientInfo.mReqList.clear();
   2969 
   2970         if (clientInfo.mServList.size() == 0) {
   2971             if (DBG) logd("remove channel information from framework");
   2972             mClientInfoList.remove(clientInfo.mMessenger);
   2973         }
   2974 
   2975         if (mServiceDiscReqId == null) {
   2976             return;
   2977         }
   2978 
   2979         updateSupplicantServiceRequest();
   2980     }
   2981 
   2982     private boolean addLocalService(Messenger m, WifiP2pServiceInfo servInfo) {
   2983         clearClientDeadChannels();
   2984         ClientInfo clientInfo = getClientInfo(m, true);
   2985         if (clientInfo == null) {
   2986             return false;
   2987         }
   2988 
   2989         if (!clientInfo.mServList.add(servInfo)) {
   2990             return false;
   2991         }
   2992 
   2993         if (!mWifiNative.p2pServiceAdd(servInfo)) {
   2994             clientInfo.mServList.remove(servInfo);
   2995             return false;
   2996         }
   2997 
   2998         return true;
   2999     }
   3000 
   3001     private void removeLocalService(Messenger m, WifiP2pServiceInfo servInfo) {
   3002         ClientInfo clientInfo = getClientInfo(m, false);
   3003         if (clientInfo == null) {
   3004             return;
   3005         }
   3006 
   3007         mWifiNative.p2pServiceDel(servInfo);
   3008 
   3009         clientInfo.mServList.remove(servInfo);
   3010         if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) {
   3011             if (DBG) logd("remove client information from framework");
   3012             mClientInfoList.remove(clientInfo.mMessenger);
   3013         }
   3014     }
   3015 
   3016     private void clearLocalServices(Messenger m) {
   3017         ClientInfo clientInfo = getClientInfo(m, false);
   3018         if (clientInfo == null) {
   3019             return;
   3020         }
   3021 
   3022         for (WifiP2pServiceInfo servInfo: clientInfo.mServList) {
   3023             mWifiNative.p2pServiceDel(servInfo);
   3024         }
   3025 
   3026         clientInfo.mServList.clear();
   3027         if (clientInfo.mReqList.size() == 0) {
   3028             if (DBG) logd("remove client information from framework");
   3029             mClientInfoList.remove(clientInfo.mMessenger);
   3030         }
   3031     }
   3032 
   3033     private void clearClientInfo(Messenger m) {
   3034         clearLocalServices(m);
   3035         clearServiceRequests(m);
   3036     }
   3037 
   3038     /**
   3039      * Send the service response to the WifiP2pManager.Channel.
   3040      *
   3041      * @param resp
   3042      */
   3043     private void sendServiceResponse(WifiP2pServiceResponse resp) {
   3044         for (ClientInfo c : mClientInfoList.values()) {
   3045             WifiP2pServiceRequest req = c.mReqList.get(resp.getTransactionId());
   3046             if (req != null) {
   3047                 Message msg = Message.obtain();
   3048                 msg.what = WifiP2pManager.RESPONSE_SERVICE;
   3049                 msg.arg1 = 0;
   3050                 msg.arg2 = 0;
   3051                 msg.obj = resp;
   3052                 try {
   3053                     c.mMessenger.send(msg);
   3054                 } catch (RemoteException e) {
   3055                     if (DBG) logd("detect dead channel");
   3056                     clearClientInfo(c.mMessenger);
   3057                     return;
   3058                 }
   3059             }
   3060         }
   3061     }
   3062 
   3063     /**
   3064      * We dont get notifications of clients that have gone away.
   3065      * We detect this actively when services are added and throw
   3066      * them away.
   3067      *
   3068      * TODO: This can be done better with full async channels.
   3069      */
   3070     private void clearClientDeadChannels() {
   3071         ArrayList<Messenger> deadClients = new ArrayList<Messenger>();
   3072 
   3073         for (ClientInfo c : mClientInfoList.values()) {
   3074             Message msg = Message.obtain();
   3075             msg.what = WifiP2pManager.PING;
   3076             msg.arg1 = 0;
   3077             msg.arg2 = 0;
   3078             msg.obj = null;
   3079             try {
   3080                 c.mMessenger.send(msg);
   3081             } catch (RemoteException e) {
   3082                 if (DBG) logd("detect dead channel");
   3083                 deadClients.add(c.mMessenger);
   3084             }
   3085         }
   3086 
   3087         for (Messenger m : deadClients) {
   3088             clearClientInfo(m);
   3089         }
   3090     }
   3091 
   3092     /**
   3093      * Return the specified ClientInfo.
   3094      * @param m Messenger
   3095      * @param createIfNotExist if true and the specified channel info does not exist,
   3096      * create new client info.
   3097      * @return the specified ClientInfo.
   3098      */
   3099     private ClientInfo getClientInfo(Messenger m, boolean createIfNotExist) {
   3100         ClientInfo clientInfo = mClientInfoList.get(m);
   3101 
   3102         if (clientInfo == null && createIfNotExist) {
   3103             if (DBG) logd("add a new client");
   3104             clientInfo = new ClientInfo(m);
   3105             mClientInfoList.put(m, clientInfo);
   3106         }
   3107 
   3108         return clientInfo;
   3109     }
   3110 
   3111     }
   3112 
   3113     /**
   3114      * Information about a particular client and we track the service discovery requests
   3115      * and the local services registered by the client.
   3116      */
   3117     private class ClientInfo {
   3118 
   3119         /*
   3120          * A reference to WifiP2pManager.Channel handler.
   3121          * The response of this request is notified to WifiP2pManager.Channel handler
   3122          */
   3123         private Messenger mMessenger;
   3124 
   3125         /*
   3126          * A service discovery request list.
   3127          */
   3128         private SparseArray<WifiP2pServiceRequest> mReqList;
   3129 
   3130         /*
   3131          * A local service information list.
   3132          */
   3133         private List<WifiP2pServiceInfo> mServList;
   3134 
   3135         private ClientInfo(Messenger m) {
   3136             mMessenger = m;
   3137             mReqList = new SparseArray();
   3138             mServList = new ArrayList<WifiP2pServiceInfo>();
   3139         }
   3140     }
   3141 }
   3142