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