WifiP2pSettings.java revision 9f86b5df783ed063d1142f0050edbddf4fe3c7c2
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 17package com.android.settings.wifi.p2p; 18 19import android.app.ActionBar; 20import android.app.Activity; 21import android.app.AlertDialog; 22import android.app.Dialog; 23import android.content.BroadcastReceiver; 24import android.content.Context; 25import android.content.DialogInterface; 26import android.content.DialogInterface.OnClickListener; 27import android.content.Intent; 28import android.content.IntentFilter; 29import android.net.NetworkInfo; 30import android.net.wifi.p2p.WifiP2pConfig; 31import android.net.wifi.p2p.WifiP2pDevice; 32import android.net.wifi.p2p.WifiP2pDeviceList; 33import android.net.wifi.p2p.WifiP2pGroup; 34import android.net.wifi.p2p.WifiP2pGroupList; 35import android.net.wifi.p2p.WifiP2pManager; 36import android.net.wifi.p2p.WifiP2pManager.GroupInfoListener; 37import android.net.wifi.p2p.WifiP2pManager.PersistentGroupInfoListener; 38import android.net.wifi.WpsInfo; 39import android.os.Bundle; 40import android.os.Handler; 41import android.os.SystemProperties; 42import android.preference.Preference; 43import android.preference.PreferenceActivity; 44import android.preference.PreferenceCategory; 45import android.preference.PreferenceGroup; 46import android.preference.PreferenceScreen; 47import android.text.TextUtils; 48import android.util.Log; 49import android.view.Gravity; 50import android.view.Menu; 51import android.view.MenuInflater; 52import android.view.MenuItem; 53import android.widget.EditText; 54import android.widget.Switch; 55import android.widget.Toast; 56 57import com.android.settings.R; 58import com.android.settings.SettingsPreferenceFragment; 59 60import java.util.Arrays; 61import java.util.List; 62import java.util.Collection; 63 64/* 65 * Displays Wi-fi p2p settings UI 66 */ 67public class WifiP2pSettings extends SettingsPreferenceFragment 68 implements PersistentGroupInfoListener, GroupInfoListener { 69 70 private static final String TAG = "WifiP2pSettings"; 71 private static final boolean DBG = false; 72 private static final int MENU_ID_SEARCH = Menu.FIRST; 73 private static final int MENU_ID_RENAME = Menu.FIRST + 1; 74 75 private final IntentFilter mIntentFilter = new IntentFilter(); 76 private WifiP2pManager mWifiP2pManager; 77 private WifiP2pManager.Channel mChannel; 78 private OnClickListener mRenameListener; 79 private OnClickListener mDisconnectListener; 80 private OnClickListener mCancelConnectListener; 81 private OnClickListener mDeleteGroupListener; 82 private WifiP2pPeer mSelectedWifiPeer; 83 private WifiP2pPersistentGroup mSelectedGroup; 84 private EditText mDeviceNameText; 85 86 private boolean mWifiP2pEnabled; 87 private boolean mWifiP2pSearching; 88 private int mConnectedDevices; 89 private WifiP2pGroup mConnectedGroup; 90 91 private PreferenceGroup mPeersGroup; 92 private PreferenceGroup mPersistentGroup; 93 private Preference mThisDevicePref; 94 95 private static final int DIALOG_DISCONNECT = 1; 96 private static final int DIALOG_CANCEL_CONNECT = 2; 97 private static final int DIALOG_RENAME = 3; 98 private static final int DIALOG_DELETE_GROUP = 4; 99 100 private static final String SAVE_DIALOG_PEER = "PEER_STATE"; 101 private static final String SAVE_DEVICE_NAME = "DEV_NAME"; 102 103 private WifiP2pDevice mThisDevice; 104 private WifiP2pDeviceList mPeers = new WifiP2pDeviceList(); 105 106 private String mSavedDeviceName; 107 108 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 109 @Override 110 public void onReceive(Context context, Intent intent) { 111 String action = intent.getAction(); 112 113 if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) { 114 mWifiP2pEnabled = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, 115 WifiP2pManager.WIFI_P2P_STATE_DISABLED) == WifiP2pManager.WIFI_P2P_STATE_ENABLED; 116 handleP2pStateChanged(); 117 } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) { 118 mPeers = (WifiP2pDeviceList) intent.getParcelableExtra( 119 WifiP2pManager.EXTRA_P2P_DEVICE_LIST); 120 handlePeersChanged(); 121 } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) { 122 if (mWifiP2pManager == null) return; 123 NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra( 124 WifiP2pManager.EXTRA_NETWORK_INFO); 125 if (mWifiP2pManager != null) { 126 mWifiP2pManager.requestGroupInfo(mChannel, WifiP2pSettings.this); 127 } 128 if (networkInfo.isConnected()) { 129 if (DBG) Log.d(TAG, "Connected"); 130 } else { 131 //start a search when we are disconnected 132 startSearch(); 133 } 134 } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) { 135 mThisDevice = (WifiP2pDevice) intent.getParcelableExtra( 136 WifiP2pManager.EXTRA_WIFI_P2P_DEVICE); 137 if (DBG) Log.d(TAG, "Update device info: " + mThisDevice); 138 updateDevicePref(); 139 } else if (WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action)) { 140 int discoveryState = intent.getIntExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE, 141 WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED); 142 if (DBG) Log.d(TAG, "Discovery state changed: " + discoveryState); 143 if (discoveryState == WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED) { 144 updateSearchMenu(true); 145 } else { 146 updateSearchMenu(false); 147 } 148 } else if (WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION.equals(action)) { 149 if (mWifiP2pManager != null) { 150 mWifiP2pManager.requestPersistentGroupInfo(mChannel, WifiP2pSettings.this); 151 } 152 } 153 } 154 }; 155 156 @Override 157 public void onActivityCreated(Bundle savedInstanceState) { 158 addPreferencesFromResource(R.xml.wifi_p2p_settings); 159 160 mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); 161 mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); 162 mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); 163 mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); 164 mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION); 165 mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION); 166 167 final Activity activity = getActivity(); 168 mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE); 169 if (mWifiP2pManager != null) { 170 mChannel = mWifiP2pManager.initialize(activity, getActivity().getMainLooper(), null); 171 if (mChannel == null) { 172 //Failure to set up connection 173 Log.e(TAG, "Failed to set up connection with wifi p2p service"); 174 mWifiP2pManager = null; 175 } 176 } else { 177 Log.e(TAG, "mWifiP2pManager is null !"); 178 } 179 180 if (savedInstanceState != null && savedInstanceState.containsKey(SAVE_DIALOG_PEER)) { 181 WifiP2pDevice device = savedInstanceState.getParcelable(SAVE_DIALOG_PEER); 182 mSelectedWifiPeer = new WifiP2pPeer(getActivity(), device); 183 } 184 if (savedInstanceState != null && savedInstanceState.containsKey(SAVE_DEVICE_NAME)) { 185 mSavedDeviceName = savedInstanceState.getString(SAVE_DEVICE_NAME); 186 } 187 188 mRenameListener = new OnClickListener() { 189 @Override 190 public void onClick(DialogInterface dialog, int which) { 191 if (which == DialogInterface.BUTTON_POSITIVE) { 192 if (mWifiP2pManager != null) { 193 mWifiP2pManager.setDeviceName(mChannel, 194 mDeviceNameText.getText().toString(), 195 new WifiP2pManager.ActionListener() { 196 public void onSuccess() { 197 if (DBG) Log.d(TAG, " device rename success"); 198 } 199 public void onFailure(int reason) { 200 Toast.makeText(getActivity(), 201 R.string.wifi_p2p_failed_rename_message, 202 Toast.LENGTH_LONG).show(); 203 } 204 }); 205 } 206 } 207 } 208 }; 209 210 //disconnect dialog listener 211 mDisconnectListener = new OnClickListener() { 212 @Override 213 public void onClick(DialogInterface dialog, int which) { 214 if (which == DialogInterface.BUTTON_POSITIVE) { 215 if (mWifiP2pManager != null) { 216 mWifiP2pManager.removeGroup(mChannel, new WifiP2pManager.ActionListener() { 217 public void onSuccess() { 218 if (DBG) Log.d(TAG, " remove group success"); 219 } 220 public void onFailure(int reason) { 221 if (DBG) Log.d(TAG, " remove group fail " + reason); 222 } 223 }); 224 } 225 } 226 } 227 }; 228 229 //cancel connect dialog listener 230 mCancelConnectListener = new OnClickListener() { 231 @Override 232 public void onClick(DialogInterface dialog, int which) { 233 if (which == DialogInterface.BUTTON_POSITIVE) { 234 if (mWifiP2pManager != null) { 235 mWifiP2pManager.cancelConnect(mChannel, 236 new WifiP2pManager.ActionListener() { 237 public void onSuccess() { 238 if (DBG) Log.d(TAG, " cancel connect success"); 239 } 240 public void onFailure(int reason) { 241 if (DBG) Log.d(TAG, " cancel connect fail " + reason); 242 } 243 }); 244 } 245 } 246 } 247 }; 248 249 //delete persistent group dialog listener 250 mDeleteGroupListener = new OnClickListener() { 251 @Override 252 public void onClick(DialogInterface dialog, int which) { 253 if (which == DialogInterface.BUTTON_POSITIVE) { 254 if (mWifiP2pManager != null) { 255 mWifiP2pManager.deletePersistentGroup(mChannel, 256 mSelectedGroup.getNetworkId(), 257 new WifiP2pManager.ActionListener() { 258 public void onSuccess() { 259 if (DBG) Log.d(TAG, " delete group success"); 260 } 261 public void onFailure(int reason) { 262 if (DBG) Log.d(TAG, " delete group fail " + reason); 263 } 264 }); 265 } 266 } 267 } 268 }; 269 270 setHasOptionsMenu(true); 271 272 final PreferenceScreen preferenceScreen = getPreferenceScreen(); 273 preferenceScreen.removeAll(); 274 275 preferenceScreen.setOrderingAsAdded(true); 276 mThisDevicePref = new Preference(getActivity()); 277 preferenceScreen.addPreference(mThisDevicePref); 278 279 mPeersGroup = new PreferenceCategory(getActivity()); 280 mPeersGroup.setTitle(R.string.wifi_p2p_peer_devices); 281 282 mPersistentGroup = new PreferenceCategory(getActivity()); 283 mPersistentGroup.setTitle(R.string.wifi_p2p_remembered_groups); 284 285 super.onActivityCreated(savedInstanceState); 286 } 287 288 @Override 289 public void onResume() { 290 super.onResume(); 291 getActivity().registerReceiver(mReceiver, mIntentFilter); 292 } 293 294 @Override 295 public void onPause() { 296 super.onPause(); 297 mWifiP2pManager.stopPeerDiscovery(mChannel, null); 298 getActivity().unregisterReceiver(mReceiver); 299 } 300 301 @Override 302 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 303 int textId = mWifiP2pSearching ? R.string.wifi_p2p_menu_searching : 304 R.string.wifi_p2p_menu_search; 305 menu.add(Menu.NONE, MENU_ID_SEARCH, 0, textId) 306 .setEnabled(mWifiP2pEnabled) 307 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 308 menu.add(Menu.NONE, MENU_ID_RENAME, 0, R.string.wifi_p2p_menu_rename) 309 .setEnabled(mWifiP2pEnabled) 310 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 311 super.onCreateOptionsMenu(menu, inflater); 312 } 313 314 @Override 315 public void onPrepareOptionsMenu(Menu menu) { 316 MenuItem searchMenu = menu.findItem(MENU_ID_SEARCH); 317 MenuItem renameMenu = menu.findItem(MENU_ID_RENAME); 318 if (mWifiP2pEnabled) { 319 searchMenu.setEnabled(true); 320 renameMenu.setEnabled(true); 321 } else { 322 searchMenu.setEnabled(false); 323 renameMenu.setEnabled(false); 324 } 325 326 if (mWifiP2pSearching) { 327 searchMenu.setTitle(R.string.wifi_p2p_menu_searching); 328 } else { 329 searchMenu.setTitle(R.string.wifi_p2p_menu_search); 330 } 331 } 332 333 @Override 334 public boolean onOptionsItemSelected(MenuItem item) { 335 switch (item.getItemId()) { 336 case MENU_ID_SEARCH: 337 startSearch(); 338 return true; 339 case MENU_ID_RENAME: 340 showDialog(DIALOG_RENAME); 341 return true; 342 } 343 return super.onOptionsItemSelected(item); 344 } 345 346 @Override 347 public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) { 348 if (preference instanceof WifiP2pPeer) { 349 mSelectedWifiPeer = (WifiP2pPeer) preference; 350 if (mSelectedWifiPeer.device.status == WifiP2pDevice.CONNECTED) { 351 showDialog(DIALOG_DISCONNECT); 352 } else if (mSelectedWifiPeer.device.status == WifiP2pDevice.INVITED) { 353 showDialog(DIALOG_CANCEL_CONNECT); 354 } else { 355 WifiP2pConfig config = new WifiP2pConfig(); 356 config.deviceAddress = mSelectedWifiPeer.device.deviceAddress; 357 358 int forceWps = SystemProperties.getInt("wifidirect.wps", -1); 359 360 if (forceWps != -1) { 361 config.wps.setup = forceWps; 362 } else { 363 if (mSelectedWifiPeer.device.wpsPbcSupported()) { 364 config.wps.setup = WpsInfo.PBC; 365 } else if (mSelectedWifiPeer.device.wpsKeypadSupported()) { 366 config.wps.setup = WpsInfo.KEYPAD; 367 } else { 368 config.wps.setup = WpsInfo.DISPLAY; 369 } 370 } 371 372 mWifiP2pManager.connect(mChannel, config, 373 new WifiP2pManager.ActionListener() { 374 public void onSuccess() { 375 if (DBG) Log.d(TAG, " connect success"); 376 } 377 public void onFailure(int reason) { 378 Log.e(TAG, " connect fail " + reason); 379 Toast.makeText(getActivity(), 380 R.string.wifi_p2p_failed_connect_message, 381 Toast.LENGTH_SHORT).show(); 382 } 383 }); 384 } 385 } else if (preference instanceof WifiP2pPersistentGroup) { 386 mSelectedGroup = (WifiP2pPersistentGroup) preference; 387 showDialog(DIALOG_DELETE_GROUP); 388 } 389 return super.onPreferenceTreeClick(screen, preference); 390 } 391 392 @Override 393 public Dialog onCreateDialog(int id) { 394 if (id == DIALOG_DISCONNECT) { 395 String deviceName = TextUtils.isEmpty(mSelectedWifiPeer.device.deviceName) ? 396 mSelectedWifiPeer.device.deviceAddress : 397 mSelectedWifiPeer.device.deviceName; 398 String msg; 399 if (mConnectedDevices > 1) { 400 msg = getActivity().getString(R.string.wifi_p2p_disconnect_multiple_message, 401 deviceName, mConnectedDevices - 1); 402 } else { 403 msg = getActivity().getString(R.string.wifi_p2p_disconnect_message, deviceName); 404 } 405 AlertDialog dialog = new AlertDialog.Builder(getActivity()) 406 .setTitle(R.string.wifi_p2p_disconnect_title) 407 .setMessage(msg) 408 .setPositiveButton(getActivity().getString(R.string.dlg_ok), mDisconnectListener) 409 .setNegativeButton(getActivity().getString(R.string.dlg_cancel), null) 410 .create(); 411 return dialog; 412 } else if (id == DIALOG_CANCEL_CONNECT) { 413 int stringId = R.string.wifi_p2p_cancel_connect_message; 414 String deviceName = TextUtils.isEmpty(mSelectedWifiPeer.device.deviceName) ? 415 mSelectedWifiPeer.device.deviceAddress : 416 mSelectedWifiPeer.device.deviceName; 417 418 AlertDialog dialog = new AlertDialog.Builder(getActivity()) 419 .setTitle(R.string.wifi_p2p_cancel_connect_title) 420 .setMessage(getActivity().getString(stringId, deviceName)) 421 .setPositiveButton(getActivity().getString(R.string.dlg_ok), mCancelConnectListener) 422 .setNegativeButton(getActivity().getString(R.string.dlg_cancel), null) 423 .create(); 424 return dialog; 425 } else if (id == DIALOG_RENAME) { 426 mDeviceNameText = new EditText(getActivity()); 427 if (mSavedDeviceName != null) { 428 mDeviceNameText.setText(mSavedDeviceName); 429 mDeviceNameText.setSelection(mSavedDeviceName.length()); 430 } else if (mThisDevice != null && !TextUtils.isEmpty(mThisDevice.deviceName)) { 431 mDeviceNameText.setText(mThisDevice.deviceName); 432 mDeviceNameText.setSelection(0, mThisDevice.deviceName.length()); 433 } 434 mSavedDeviceName = null; 435 AlertDialog dialog = new AlertDialog.Builder(getActivity()) 436 .setTitle(R.string.wifi_p2p_menu_rename) 437 .setView(mDeviceNameText) 438 .setPositiveButton(getActivity().getString(R.string.dlg_ok), mRenameListener) 439 .setNegativeButton(getActivity().getString(R.string.dlg_cancel), null) 440 .create(); 441 return dialog; 442 } else if (id == DIALOG_DELETE_GROUP) { 443 int stringId = R.string.wifi_p2p_delete_group_message; 444 445 AlertDialog dialog = new AlertDialog.Builder(getActivity()) 446 .setMessage(getActivity().getString(stringId)) 447 .setPositiveButton(getActivity().getString(R.string.dlg_ok), mDeleteGroupListener) 448 .setNegativeButton(getActivity().getString(R.string.dlg_cancel), null) 449 .create(); 450 return dialog; 451 } 452 return null; 453 } 454 455 @Override 456 public void onSaveInstanceState(Bundle outState) { 457 if (mSelectedWifiPeer != null) { 458 outState.putParcelable(SAVE_DIALOG_PEER, mSelectedWifiPeer.device); 459 } 460 if (mDeviceNameText != null) { 461 outState.putString(SAVE_DEVICE_NAME, mDeviceNameText.getText().toString()); 462 } 463 } 464 465 private void handlePeersChanged() { 466 mPeersGroup.removeAll(); 467 468 mConnectedDevices = 0; 469 if (DBG) Log.d(TAG, "List of available peers"); 470 for (WifiP2pDevice peer: mPeers.getDeviceList()) { 471 if (DBG) Log.d(TAG, "-> " + peer); 472 mPeersGroup.addPreference(new WifiP2pPeer(getActivity(), peer)); 473 if (peer.status == WifiP2pDevice.CONNECTED) mConnectedDevices++; 474 } 475 if (DBG) Log.d(TAG, " mConnectedDevices " + mConnectedDevices); 476 } 477 478 public void onPersistentGroupInfoAvailable(WifiP2pGroupList groups) { 479 mPersistentGroup.removeAll(); 480 481 for (WifiP2pGroup group: groups.getGroupList()) { 482 if (DBG) Log.d(TAG, " group " + group); 483 mPersistentGroup.addPreference(new WifiP2pPersistentGroup(getActivity(), group)); 484 } 485 } 486 487 public void onGroupInfoAvailable(WifiP2pGroup group) { 488 if (DBG) Log.d(TAG, " group " + group); 489 mConnectedGroup = group; 490 updateDevicePref(); 491 } 492 493 private void handleP2pStateChanged() { 494 updateSearchMenu(false); 495 if (mWifiP2pEnabled) { 496 final PreferenceScreen preferenceScreen = getPreferenceScreen(); 497 preferenceScreen.removeAll(); 498 499 preferenceScreen.setOrderingAsAdded(true); 500 preferenceScreen.addPreference(mThisDevicePref); 501 502 mPeersGroup.setEnabled(true); 503 preferenceScreen.addPreference(mPeersGroup); 504 505 mPersistentGroup.setEnabled(true); 506 preferenceScreen.addPreference(mPersistentGroup); 507 } 508 } 509 510 private void updateSearchMenu(boolean searching) { 511 mWifiP2pSearching = searching; 512 Activity activity = getActivity(); 513 if (activity != null) activity.invalidateOptionsMenu(); 514 } 515 516 private void startSearch() { 517 if (mWifiP2pManager != null && !mWifiP2pSearching) { 518 mWifiP2pManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() { 519 public void onSuccess() { 520 } 521 public void onFailure(int reason) { 522 if (DBG) Log.d(TAG, " discover fail " + reason); 523 } 524 }); 525 } 526 } 527 528 private void updateDevicePref() { 529 if (mThisDevice != null) { 530 if (TextUtils.isEmpty(mThisDevice.deviceName)) { 531 mThisDevicePref.setTitle(mThisDevice.deviceAddress); 532 } else { 533 mThisDevicePref.setTitle(mThisDevice.deviceName); 534 } 535 536 mThisDevicePref.setPersistent(false); 537 mThisDevicePref.setEnabled(true); 538 mThisDevicePref.setSelectable(false); 539 } 540 } 541} 542