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