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