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.settings.wifi.p2p;
18 
19 import android.app.Activity;
20 import android.app.Dialog;
21 import android.app.settings.SettingsEnums;
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.DialogInterface.OnClickListener;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.net.NetworkInfo;
29 import android.net.wifi.WpsInfo;
30 import android.net.wifi.p2p.WifiP2pConfig;
31 import android.net.wifi.p2p.WifiP2pDevice;
32 import android.net.wifi.p2p.WifiP2pDeviceList;
33 import android.net.wifi.p2p.WifiP2pGroup;
34 import android.net.wifi.p2p.WifiP2pGroupList;
35 import android.net.wifi.p2p.WifiP2pInfo;
36 import android.net.wifi.p2p.WifiP2pManager;
37 import android.net.wifi.p2p.WifiP2pManager.DeviceInfoListener;
38 import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
39 import android.net.wifi.p2p.WifiP2pManager.PersistentGroupInfoListener;
40 import android.os.Bundle;
41 import android.sysprop.TelephonyProperties;
42 import android.text.InputFilter;
43 import android.text.TextUtils;
44 import android.util.Log;
45 import android.view.LayoutInflater;
46 import android.view.Menu;
47 import android.view.MenuInflater;
48 import android.view.MenuItem;
49 import android.view.View;
50 import android.view.ViewGroup;
51 import android.widget.EditText;
52 import android.widget.Toast;
53 
54 import androidx.annotation.VisibleForTesting;
55 import androidx.appcompat.app.AlertDialog;
56 import androidx.preference.Preference;
57 import androidx.preference.PreferenceScreen;
58 
59 import com.android.settings.R;
60 import com.android.settings.dashboard.DashboardFragment;
61 import com.android.settingslib.core.AbstractPreferenceController;
62 
63 import java.util.ArrayList;
64 import java.util.List;
65 
66 /*
67  * Displays Wi-fi p2p settings UI
68  */
69 public class WifiP2pSettings extends DashboardFragment
70         implements PersistentGroupInfoListener, PeerListListener, DeviceInfoListener {
71 
72     private static final String TAG = "WifiP2pSettings";
73     private static final boolean DBG = false;
74     @VisibleForTesting static final int MENU_ID_SEARCH = Menu.FIRST;
75     @VisibleForTesting static final int MENU_ID_RENAME = Menu.FIRST + 1;
76 
77     private final IntentFilter mIntentFilter = new IntentFilter();
78     @VisibleForTesting WifiP2pManager mWifiP2pManager;
79     @VisibleForTesting static WifiP2pManager.Channel sChannel;
80     @VisibleForTesting OnClickListener mRenameListener;
81     @VisibleForTesting OnClickListener mDisconnectListener;
82     @VisibleForTesting OnClickListener mCancelConnectListener;
83     @VisibleForTesting OnClickListener mDeleteGroupListener;
84     @VisibleForTesting WifiP2pPeer mSelectedWifiPeer;
85     @VisibleForTesting WifiP2pPersistentGroup mSelectedGroup;
86     @VisibleForTesting String mSelectedGroupName;
87     private EditText mDeviceNameText;
88 
89     private boolean mWifiP2pEnabled;
90     @VisibleForTesting boolean mWifiP2pSearching;
91     @VisibleForTesting int mConnectedDevices;
92     @VisibleForTesting boolean mLastGroupFormed = false;
93     private boolean mIsIgnoreInitConnectionInfoCallback = false;
94 
95     @VisibleForTesting P2pPeerCategoryPreferenceController mPeerCategoryController;
96     @VisibleForTesting P2pPersistentCategoryPreferenceController mPersistentCategoryController;
97     @VisibleForTesting P2pThisDevicePreferenceController mThisDevicePreferenceController;
98 
99     @VisibleForTesting static final int DIALOG_DISCONNECT  = 1;
100     @VisibleForTesting static final int DIALOG_CANCEL_CONNECT = 2;
101     @VisibleForTesting static final int DIALOG_RENAME = 3;
102     @VisibleForTesting static final int DIALOG_DELETE_GROUP = 4;
103 
104     @VisibleForTesting static final String SAVE_DIALOG_PEER = "PEER_STATE";
105     @VisibleForTesting static final String SAVE_DEVICE_NAME = "DEV_NAME";
106     @VisibleForTesting static final String SAVE_SELECTED_GROUP = "GROUP_NAME";
107 
108     private WifiP2pDevice mThisDevice;
109     private WifiP2pDeviceList mPeers = new WifiP2pDeviceList();
110 
111     @VisibleForTesting String mSavedDeviceName;
112 
113     @VisibleForTesting
114     final BroadcastReceiver mReceiver = new BroadcastReceiver() {
115         @Override
116         public void onReceive(Context context, Intent intent) {
117             String action = intent.getAction();
118 
119             if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
120                 mWifiP2pEnabled = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE,
121                     WifiP2pManager.WIFI_P2P_STATE_DISABLED) == WifiP2pManager.WIFI_P2P_STATE_ENABLED;
122                 handleP2pStateChanged();
123             } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
124                 mPeers = (WifiP2pDeviceList) intent.getParcelableExtra(
125                         WifiP2pManager.EXTRA_P2P_DEVICE_LIST);
126                 handlePeersChanged();
127             } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
128                 if (mWifiP2pManager == null) return;
129                 NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(
130                         WifiP2pManager.EXTRA_NETWORK_INFO);
131                 WifiP2pInfo wifip2pinfo = (WifiP2pInfo) intent.getParcelableExtra(
132                         WifiP2pManager.EXTRA_WIFI_P2P_INFO);
133                 if (networkInfo.isConnected()) {
134                     if (DBG) Log.d(TAG, "Connected");
135                 } else if (mLastGroupFormed != true) {
136                     //start a search when we are disconnected
137                     //but not on group removed broadcast event
138                     startSearch();
139                 }
140                 mLastGroupFormed = wifip2pinfo.groupFormed;
141                 mIsIgnoreInitConnectionInfoCallback = true;
142             } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
143                 WifiP2pDevice device =
144                         (WifiP2pDevice) intent.getExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);
145                 if (device != null && device.status == WifiP2pDevice.UNAVAILABLE) {
146                     return;
147                 }
148                 // Do not use WifiP2pManager.EXTRA_WIFI_P2P_DEVICE from the extras, as the system
149                 // broadcast does not contain the device's MAC.
150                 // Requesting our own device info as an app holding the NETWORK_SETTINGS permission
151                 // ensures that the MAC address will be available in the result.
152                 if (DBG) Log.d(TAG, "This device changed. Requesting device info.");
153                 if (mWifiP2pManager != null && sChannel != null) {
154                     mWifiP2pManager.requestDeviceInfo(sChannel, WifiP2pSettings.this);
155                 }
156             } else if (WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action)) {
157                 int discoveryState = intent.getIntExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE,
158                     WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED);
159                 if (DBG) Log.d(TAG, "Discovery state changed: " + discoveryState);
160                 if (discoveryState == WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED) {
161                     updateSearchMenu(true);
162                 } else {
163                     updateSearchMenu(false);
164                 }
165             } else if (WifiP2pManager.ACTION_WIFI_P2P_PERSISTENT_GROUPS_CHANGED.equals(action)) {
166                 if (mWifiP2pManager != null && sChannel != null) {
167                     mWifiP2pManager.requestPersistentGroupInfo(sChannel, WifiP2pSettings.this);
168                 }
169             }
170         }
171     };
172 
173     @Override
getLogTag()174     protected String getLogTag() {
175         return TAG;
176     }
177 
178     @Override
getPreferenceScreenResId()179     protected int getPreferenceScreenResId() {
180         return R.xml.wifi_p2p_settings;
181     }
182 
183     @Override
getMetricsCategory()184     public int getMetricsCategory() {
185         return SettingsEnums.WIFI_P2P;
186     }
187 
188     @Override
getHelpResource()189     public int getHelpResource() {
190         return R.string.help_url_wifi_p2p;
191     }
192 
193     @Override
createPreferenceControllers(Context context)194     protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
195         final List<AbstractPreferenceController> controllers = new ArrayList<>();
196         mPersistentCategoryController =
197                 new P2pPersistentCategoryPreferenceController(context);
198         mPeerCategoryController =
199                 new P2pPeerCategoryPreferenceController(context);
200         mThisDevicePreferenceController = new P2pThisDevicePreferenceController(context);
201         controllers.add(mPersistentCategoryController);
202         controllers.add(mPeerCategoryController);
203         controllers.add(mThisDevicePreferenceController);
204         return controllers;
205     }
206 
207     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)208     public View onCreateView(LayoutInflater inflater, ViewGroup container,
209                              Bundle savedInstanceState) {
210         final View root = super.onCreateView(inflater, container, savedInstanceState);
211 
212         final Activity activity = getActivity();
213         if (mWifiP2pManager == null) {
214             mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
215         }
216 
217         if (mWifiP2pManager != null) {
218             if (!initChannel()) {
219                 //Failure to set up connection
220                 Log.e(TAG, "Failed to set up connection with wifi p2p service");
221                 mWifiP2pManager = null;
222             }
223         } else {
224             Log.e(TAG, "mWifiP2pManager is null !");
225         }
226 
227         if (savedInstanceState != null && savedInstanceState.containsKey(SAVE_DIALOG_PEER)) {
228             WifiP2pDevice device = savedInstanceState.getParcelable(SAVE_DIALOG_PEER);
229             mSelectedWifiPeer = new WifiP2pPeer(getPrefContext(), device);
230         }
231         if (savedInstanceState != null && savedInstanceState.containsKey(SAVE_DEVICE_NAME)) {
232             mSavedDeviceName = savedInstanceState.getString(SAVE_DEVICE_NAME);
233         }
234         if (savedInstanceState != null && savedInstanceState.containsKey(SAVE_SELECTED_GROUP)) {
235             mSelectedGroupName = savedInstanceState.getString(SAVE_SELECTED_GROUP);
236         }
237 
238         mRenameListener = new OnClickListener() {
239             @Override
240             public void onClick(DialogInterface dialog, int which) {
241                 if (which == DialogInterface.BUTTON_POSITIVE) {
242                     if (mWifiP2pManager != null && sChannel != null) {
243                         String name = mDeviceNameText.getText().toString();
244                         if (name != null) {
245                             for (int i = 0; i < name.length(); i++) {
246                                 char cur = name.charAt(i);
247                                 if(!Character.isDigit(cur) && !Character.isLetter(cur)
248                                         && cur != '-' && cur != '_' && cur != ' ') {
249                                     Toast.makeText(getActivity(),
250                                             R.string.wifi_p2p_failed_rename_message,
251                                             Toast.LENGTH_LONG).show();
252                                     return;
253                                 }
254                             }
255                         }
256                         mWifiP2pManager.setDeviceName(sChannel,
257                                 mDeviceNameText.getText().toString(),
258                                 new WifiP2pManager.ActionListener() {
259                             public void onSuccess() {
260                                 if (DBG) Log.d(TAG, " device rename success");
261                             }
262                             public void onFailure(int reason) {
263                                 Toast.makeText(getActivity(),
264                                         R.string.wifi_p2p_failed_rename_message,
265                                         Toast.LENGTH_LONG).show();
266                             }
267                         });
268                     }
269                 }
270             }
271         };
272 
273         //disconnect dialog listener
274         mDisconnectListener = new OnClickListener() {
275             @Override
276             public void onClick(DialogInterface dialog, int which) {
277                 if (which == DialogInterface.BUTTON_POSITIVE) {
278                     if (mWifiP2pManager != null && sChannel != null) {
279                         mWifiP2pManager.removeGroup(sChannel, new WifiP2pManager.ActionListener() {
280                             public void onSuccess() {
281                                 if (DBG) Log.d(TAG, " remove group success");
282                             }
283                             public void onFailure(int reason) {
284                                 if (DBG) Log.d(TAG, " remove group fail " + reason);
285                             }
286                         });
287                     }
288                 }
289             }
290         };
291 
292         //cancel connect dialog listener
293         mCancelConnectListener = new OnClickListener() {
294             @Override
295             public void onClick(DialogInterface dialog, int which) {
296                 if (which == DialogInterface.BUTTON_POSITIVE) {
297                     if (mWifiP2pManager != null && sChannel != null) {
298                         mWifiP2pManager.cancelConnect(sChannel,
299                                 new WifiP2pManager.ActionListener() {
300                             public void onSuccess() {
301                                 if (DBG) Log.d(TAG, " cancel connect success");
302                             }
303                             public void onFailure(int reason) {
304                                 if (DBG) Log.d(TAG, " cancel connect fail " + reason);
305                             }
306                         });
307                     }
308                 }
309             }
310         };
311 
312         //delete persistent group dialog listener
313         mDeleteGroupListener = new OnClickListener() {
314             @Override
315             public void onClick(DialogInterface dialog, int which) {
316                 if (which == DialogInterface.BUTTON_POSITIVE) {
317                     if (mWifiP2pManager != null && sChannel != null) {
318                         if (mSelectedGroup != null) {
319                             if (DBG) Log.d(TAG, " deleting group " + mSelectedGroup.getGroupName());
320                             mWifiP2pManager.deletePersistentGroup(sChannel,
321                                     mSelectedGroup.getNetworkId(),
322                                     new WifiP2pManager.ActionListener() {
323                                         public void onSuccess() {
324                                             if (DBG) Log.d(TAG, " delete group success");
325                                         }
326 
327                                         public void onFailure(int reason) {
328                                             if (DBG) Log.d(TAG, " delete group fail " + reason);
329                                         }
330                                     });
331                             mSelectedGroup = null;
332                         } else {
333                             if (DBG) Log.w(TAG, " No selected group to delete!");
334                         }
335                     }
336                 } else if (which == DialogInterface.BUTTON_NEGATIVE) {
337                     if (DBG) {
338                         Log.d(TAG, " forgetting selected group " + mSelectedGroup.getGroupName());
339                     }
340                     mSelectedGroup = null;
341                 }
342             }
343         };
344         return root;
345     }
346 
347     @Override
onStart()348     public void onStart() {
349         super.onStart();
350         mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
351         mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
352         mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
353         mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
354         mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);
355         mIntentFilter.addAction(WifiP2pManager.ACTION_WIFI_P2P_PERSISTENT_GROUPS_CHANGED);
356         final PreferenceScreen preferenceScreen = getPreferenceScreen();
357         if (mWifiP2pManager != null && initChannel()) {
358             // Register receiver after make sure channel exist
359             getActivity().registerReceiver(mReceiver, mIntentFilter);
360             mWifiP2pManager.requestPeers(sChannel, WifiP2pSettings.this);
361             mWifiP2pManager.requestDeviceInfo(sChannel, WifiP2pSettings.this);
362             mIsIgnoreInitConnectionInfoCallback = false;
363         }
364     }
365 
366     @Override
onStop()367     public void onStop() {
368         super.onStop();
369         if (mWifiP2pManager != null && sChannel != null) {
370             mWifiP2pManager.stopPeerDiscovery(sChannel, null);
371             if (!mLastGroupFormed) {
372                 // Close the channel when p2p doesn't connected.
373                 sChannel.close();
374                 sChannel = null;
375             }
376         }
377         getActivity().unregisterReceiver(mReceiver);
378     }
379 
380     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)381     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
382         int textId = mWifiP2pSearching ? R.string.wifi_p2p_menu_searching :
383                 R.string.wifi_p2p_menu_search;
384         menu.add(Menu.NONE, MENU_ID_SEARCH, 0, textId)
385             .setEnabled(mWifiP2pEnabled);
386         menu.add(Menu.NONE, MENU_ID_RENAME, 0, R.string.wifi_p2p_menu_rename)
387             .setEnabled(mWifiP2pEnabled);
388         super.onCreateOptionsMenu(menu, inflater);
389     }
390 
391     @Override
onPrepareOptionsMenu(Menu menu)392     public void onPrepareOptionsMenu(Menu menu) {
393         MenuItem searchMenu = menu.findItem(MENU_ID_SEARCH);
394         MenuItem renameMenu = menu.findItem(MENU_ID_RENAME);
395         if (mWifiP2pEnabled) {
396             searchMenu.setEnabled(true);
397             renameMenu.setEnabled(true);
398         } else {
399             searchMenu.setEnabled(false);
400             renameMenu.setEnabled(false);
401         }
402 
403         if (mWifiP2pSearching) {
404             searchMenu.setTitle(R.string.wifi_p2p_menu_searching);
405         } else {
406             searchMenu.setTitle(R.string.wifi_p2p_menu_search);
407         }
408     }
409 
410     @Override
onOptionsItemSelected(MenuItem item)411     public boolean onOptionsItemSelected(MenuItem item) {
412         switch (item.getItemId()) {
413             case MENU_ID_SEARCH:
414                 startSearch();
415                 return true;
416             case MENU_ID_RENAME:
417                 showDialog(DIALOG_RENAME);
418                 return true;
419         }
420         return super.onOptionsItemSelected(item);
421     }
422 
423     @Override
onPreferenceTreeClick(Preference preference)424     public boolean onPreferenceTreeClick(Preference preference) {
425         if (preference instanceof WifiP2pPeer) {
426             mSelectedWifiPeer = (WifiP2pPeer) preference;
427             if (mSelectedWifiPeer.device.status == WifiP2pDevice.CONNECTED) {
428                 showDialog(DIALOG_DISCONNECT);
429             } else if (mSelectedWifiPeer.device.status == WifiP2pDevice.INVITED) {
430                 showDialog(DIALOG_CANCEL_CONNECT);
431             } else {
432                 WifiP2pConfig config = new WifiP2pConfig();
433                 config.deviceAddress = mSelectedWifiPeer.device.deviceAddress;
434 
435                 int forceWps = TelephonyProperties.wps_info().orElse(-1);
436 
437                 if (forceWps != -1) {
438                     config.wps.setup = forceWps;
439                 } else {
440                     if (mSelectedWifiPeer.device.wpsPbcSupported()) {
441                         config.wps.setup = WpsInfo.PBC;
442                     } else if (mSelectedWifiPeer.device.wpsKeypadSupported()) {
443                         config.wps.setup = WpsInfo.KEYPAD;
444                     } else {
445                         config.wps.setup = WpsInfo.DISPLAY;
446                     }
447                 }
448                 if (mWifiP2pManager != null && sChannel != null) {
449                     mWifiP2pManager.connect(sChannel, config,
450                             new WifiP2pManager.ActionListener() {
451                                 public void onSuccess() {
452                                     if (DBG) Log.d(TAG, " connect success");
453                                 }
454                                 public void onFailure(int reason) {
455                                     Log.e(TAG, " connect fail " + reason);
456                                     Toast.makeText(getActivity(),
457                                             R.string.wifi_p2p_failed_connect_message,
458                                             Toast.LENGTH_SHORT).show();
459                                 }
460                         });
461                 }
462             }
463         } else if (preference instanceof WifiP2pPersistentGroup) {
464             mSelectedGroup = (WifiP2pPersistentGroup) preference;
465             showDialog(DIALOG_DELETE_GROUP);
466         }
467         return super.onPreferenceTreeClick(preference);
468     }
469 
470     @Override
onCreateDialog(int id)471     public Dialog onCreateDialog(int id) {
472         if (id == DIALOG_DISCONNECT) {
473             String deviceName = TextUtils.isEmpty(mSelectedWifiPeer.device.deviceName) ?
474                     mSelectedWifiPeer.device.deviceAddress :
475                     mSelectedWifiPeer.device.deviceName;
476             String msg;
477             if (mConnectedDevices > 1) {
478                 msg = getActivity().getString(R.string.wifi_p2p_disconnect_multiple_message,
479                         deviceName, mConnectedDevices - 1);
480             } else {
481                 msg = getActivity().getString(R.string.wifi_p2p_disconnect_message, deviceName);
482             }
483             AlertDialog dialog = new AlertDialog.Builder(getActivity())
484                 .setTitle(R.string.wifi_p2p_disconnect_title)
485                 .setMessage(msg)
486                 .setPositiveButton(getActivity().getString(R.string.dlg_ok), mDisconnectListener)
487                 .setNegativeButton(getActivity().getString(R.string.dlg_cancel), null)
488                 .create();
489             return dialog;
490         } else if (id == DIALOG_CANCEL_CONNECT) {
491             int stringId = R.string.wifi_p2p_cancel_connect_message;
492             String deviceName = TextUtils.isEmpty(mSelectedWifiPeer.device.deviceName) ?
493                     mSelectedWifiPeer.device.deviceAddress :
494                     mSelectedWifiPeer.device.deviceName;
495 
496             AlertDialog dialog = new AlertDialog.Builder(getActivity())
497                 .setTitle(R.string.wifi_p2p_cancel_connect_title)
498                 .setMessage(getActivity().getString(stringId, deviceName))
499                 .setPositiveButton(getActivity().getString(R.string.dlg_ok), mCancelConnectListener)
500                 .setNegativeButton(getActivity().getString(R.string.dlg_cancel), null)
501                 .create();
502             return dialog;
503         } else if (id == DIALOG_RENAME) {
504             final LayoutInflater layoutInflater = LayoutInflater.from(getPrefContext());
505             final View root = layoutInflater.inflate(R.layout.dialog_edittext, null /* root */);
506             mDeviceNameText = root.findViewById(R.id.edittext);
507             mDeviceNameText.setFilters(new InputFilter[] {new InputFilter.LengthFilter(22)});
508             if (mSavedDeviceName != null) {
509                 mDeviceNameText.setText(mSavedDeviceName);
510                 mDeviceNameText.setSelection(mSavedDeviceName.length());
511             } else if (mThisDevice != null && !TextUtils.isEmpty(mThisDevice.deviceName)) {
512                 mDeviceNameText.setText(mThisDevice.deviceName);
513                 mDeviceNameText.setSelection(0, mThisDevice.deviceName.length());
514             }
515             mSavedDeviceName = null;
516             AlertDialog dialog = new AlertDialog.Builder(getActivity())
517                 .setTitle(R.string.wifi_p2p_menu_rename)
518                 .setView(root)
519                 .setPositiveButton(getActivity().getString(R.string.dlg_ok), mRenameListener)
520                 .setNegativeButton(getActivity().getString(R.string.dlg_cancel), null)
521                 .create();
522             return dialog;
523         } else if (id == DIALOG_DELETE_GROUP) {
524             int stringId = R.string.wifi_p2p_delete_group_message;
525 
526             AlertDialog dialog = new AlertDialog.Builder(getActivity())
527                 .setMessage(getActivity().getString(stringId))
528                 .setPositiveButton(getActivity().getString(R.string.dlg_ok), mDeleteGroupListener)
529                 .setNegativeButton(getActivity().getString(R.string.dlg_cancel),
530                         mDeleteGroupListener).create();
531             return dialog;
532         }
533         return null;
534     }
535 
536     @Override
getDialogMetricsCategory(int dialogId)537     public int getDialogMetricsCategory(int dialogId) {
538         switch (dialogId) {
539             case DIALOG_DISCONNECT:
540                 return SettingsEnums.DIALOG_WIFI_P2P_DISCONNECT;
541             case DIALOG_CANCEL_CONNECT:
542                 return SettingsEnums.DIALOG_WIFI_P2P_CANCEL_CONNECT;
543             case DIALOG_RENAME:
544                 return SettingsEnums.DIALOG_WIFI_P2P_RENAME;
545             case DIALOG_DELETE_GROUP:
546                 return SettingsEnums.DIALOG_WIFI_P2P_DELETE_GROUP;
547         }
548         return 0;
549     }
550 
551     @Override
onSaveInstanceState(Bundle outState)552     public void onSaveInstanceState(Bundle outState) {
553         if (mSelectedWifiPeer != null) {
554             outState.putParcelable(SAVE_DIALOG_PEER, mSelectedWifiPeer.device);
555         }
556         if (mDeviceNameText != null) {
557             outState.putString(SAVE_DEVICE_NAME, mDeviceNameText.getText().toString());
558         }
559         if (mSelectedGroup != null) {
560             outState.putString(SAVE_SELECTED_GROUP, mSelectedGroup.getGroupName());
561         }
562     }
563 
handlePeersChanged()564     private void handlePeersChanged() {
565         mPeerCategoryController.removeAllChildren();
566 
567         mConnectedDevices = 0;
568         if (DBG) Log.d(TAG, "List of available peers");
569         for (WifiP2pDevice peer: mPeers.getDeviceList()) {
570             if (DBG) Log.d(TAG, "-> " + peer);
571             mPeerCategoryController.addChild(new WifiP2pPeer(getPrefContext(), peer));
572             if (peer.status == WifiP2pDevice.CONNECTED) mConnectedDevices++;
573         }
574         if (DBG) Log.d(TAG, " mConnectedDevices " + mConnectedDevices);
575     }
576 
577     @Override
onPersistentGroupInfoAvailable(WifiP2pGroupList groups)578     public void onPersistentGroupInfoAvailable(WifiP2pGroupList groups) {
579         mPersistentCategoryController.removeAllChildren();
580 
581         for (WifiP2pGroup group: groups.getGroupList()) {
582             if (DBG) Log.d(TAG, " group " + group);
583             WifiP2pPersistentGroup wppg = new WifiP2pPersistentGroup(getPrefContext(), group);
584             mPersistentCategoryController.addChild(wppg);
585             if (wppg.getGroupName().equals(mSelectedGroupName)) {
586                 if (DBG) Log.d(TAG, "Selecting group " + wppg.getGroupName());
587                 mSelectedGroup = wppg;
588                 mSelectedGroupName = null;
589             }
590         }
591         if (mSelectedGroupName != null) {
592             // Looks like there's a dialog pending getting user confirmation to delete the
593             // selected group. When user hits OK on that dialog, we won't do anything; but we
594             // shouldn't be in this situation in first place, because these groups are persistent
595             // groups and they shouldn't just get deleted!
596             Log.w(TAG, " Selected group " + mSelectedGroupName + " disappered on next query ");
597         }
598     }
599 
600     @Override
onPeersAvailable(WifiP2pDeviceList peers)601     public void onPeersAvailable(WifiP2pDeviceList peers) {
602         if (DBG) Log.d(TAG, "Requested peers are available");
603         mPeers = peers;
604         handlePeersChanged();
605     }
606 
607     @Override
onDeviceInfoAvailable(WifiP2pDevice wifiP2pDevice)608     public void onDeviceInfoAvailable(WifiP2pDevice wifiP2pDevice) {
609         mThisDevice = wifiP2pDevice;
610         if (DBG) Log.d(TAG, "Update device info: " + mThisDevice);
611         mThisDevicePreferenceController.updateDeviceName(mThisDevice);
612         if (wifiP2pDevice.status == WifiP2pDevice.UNAVAILABLE
613                 || wifiP2pDevice.status == WifiP2pDevice.FAILED) {
614             return;
615         }
616         onDeviceAvailable();
617     }
618 
onDeviceAvailable()619     private void onDeviceAvailable() {
620         if (mWifiP2pManager == null || sChannel == null) {
621             return;
622         }
623         mWifiP2pManager.requestNetworkInfo(sChannel, networkInfo -> {
624             if (sChannel == null) return;
625             mWifiP2pManager.requestConnectionInfo(sChannel, wifip2pinfo -> {
626                 if (!mIsIgnoreInitConnectionInfoCallback) {
627                     if (networkInfo.isConnected()) {
628                         if (DBG) {
629                             Log.d(TAG, "Connected");
630                         }
631                     } else if (!mLastGroupFormed) {
632                         // Find peers when p2p doesn't connected.
633                         startSearch();
634                     }
635                     mLastGroupFormed = wifip2pinfo.groupFormed;
636                 }
637             });
638         });
639     }
640 
handleP2pStateChanged()641     private void handleP2pStateChanged() {
642         mThisDevicePreferenceController.setEnabled(mWifiP2pEnabled);
643         mPersistentCategoryController.setEnabled(mWifiP2pEnabled);
644         mPeerCategoryController.setEnabled(mWifiP2pEnabled);
645         if (mWifiP2pEnabled) {
646             startSearch();
647         }
648         updateSearchMenu(mWifiP2pEnabled);
649     }
650 
updateSearchMenu(boolean searching)651     private void updateSearchMenu(boolean searching) {
652        mWifiP2pSearching = searching;
653        Activity activity = getActivity();
654        if (activity != null) activity.invalidateOptionsMenu();
655     }
656 
startSearch()657     private void startSearch() {
658         if (mWifiP2pManager != null && sChannel != null && !mWifiP2pSearching) {
659             mWifiP2pManager.discoverPeers(sChannel, new WifiP2pManager.ActionListener() {
660                 public void onSuccess() {
661                 }
662                 public void onFailure(int reason) {
663                     if (DBG) Log.d(TAG, " discover fail " + reason);
664                 }
665             });
666         }
667     }
668 
initChannel()669     private boolean initChannel() {
670         if (sChannel != null) {
671             return true;
672         }
673         if (mWifiP2pManager != null) {
674             sChannel = mWifiP2pManager.initialize(getActivity().getApplicationContext(),
675                     getActivity().getMainLooper(), null);
676         }
677         if (sChannel == null) {
678             Log.e(TAG, "Failed to set up connection with wifi p2p service");
679             return false;
680         }
681         return true;
682     }
683 }
684