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