OSDN Git Service

Stop scanning as soon as device is picked in the device picker.
[android-x86/packages-apps-Settings.git] / src / com / android / settings / bluetooth / BluetoothSettings.java
1 /*
2  * Copyright (C) 2008 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.bluetooth;
18
19 import com.android.settings.ProgressCategory;
20 import com.android.settings.R;
21
22 import android.bluetooth.BluetoothAdapter;
23 import android.bluetooth.BluetoothClass;
24 import android.bluetooth.BluetoothDevice;
25 import android.bluetooth.BluetoothDevicePicker;
26 import android.bluetooth.BluetoothUuid;
27 import android.content.BroadcastReceiver;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.IntentFilter;
31 import android.os.Bundle;
32 import android.os.ParcelUuid;
33 import android.preference.CheckBoxPreference;
34 import android.preference.Preference;
35 import android.preference.PreferenceActivity;
36 import android.preference.PreferenceScreen;
37 import android.view.ContextMenu;
38 import android.view.MenuItem;
39 import android.view.View;
40 import android.view.ContextMenu.ContextMenuInfo;
41 import android.widget.AdapterView.AdapterContextMenuInfo;
42
43 import java.util.List;
44 import java.util.WeakHashMap;
45
46 /**
47  * BluetoothSettings is the Settings screen for Bluetooth configuration and
48  * connection management.
49  */
50 public class BluetoothSettings extends PreferenceActivity
51         implements LocalBluetoothManager.Callback {
52
53     private static final String TAG = "BluetoothSettings";
54
55     private static final String KEY_BT_CHECKBOX = "bt_checkbox";
56     private static final String KEY_BT_DISCOVERABLE = "bt_discoverable";
57     private static final String KEY_BT_DEVICE_LIST = "bt_device_list";
58     private static final String KEY_BT_NAME = "bt_name";
59     private static final String KEY_BT_SCAN = "bt_scan";
60
61     private static final int SCREEN_TYPE_SETTINGS = 0;
62     private static final int SCREEN_TYPE_DEVICEPICKER = 1;
63
64     private int mScreenType;
65     private int mFilterType;
66     private boolean mNeedAuth;
67     private String mLaunchPackage;
68     private String mLaunchClass;
69
70     private BluetoothDevice mSelectedDevice= null;
71
72     private LocalBluetoothManager mLocalManager;
73
74     private BluetoothEnabler mEnabler;
75     private BluetoothDiscoverableEnabler mDiscoverableEnabler;
76
77     private BluetoothNamePreference mNamePreference;
78
79     private ProgressCategory mDeviceList;
80
81     private WeakHashMap<CachedBluetoothDevice, BluetoothDevicePreference> mDevicePreferenceMap =
82             new WeakHashMap<CachedBluetoothDevice, BluetoothDevicePreference>();
83
84     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
85         @Override
86         public void onReceive(Context context, Intent intent) {
87             // TODO: put this in callback instead of receiving
88
89             if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
90                 onBluetoothStateChanged(mLocalManager.getBluetoothState());
91             } else if (intent.getAction().equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)
92                     && mScreenType == SCREEN_TYPE_DEVICEPICKER) {
93                 int bondState = intent
94                         .getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);
95                 if (bondState == BluetoothDevice.BOND_BONDED) {
96                     BluetoothDevice device = intent
97                             .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
98                     if (device.equals(mSelectedDevice)) {
99                         sendDevicePickedIntent(device);
100                         finish();
101                     }
102                 }
103             }
104         }
105     };
106
107     @Override
108     protected void onCreate(Bundle savedInstanceState) {
109         super.onCreate(savedInstanceState);
110
111         mLocalManager = LocalBluetoothManager.getInstance(this);
112         if (mLocalManager == null) finish();
113
114         // Note:
115         // If an application wish to show the BT device list, it can send an
116         // intent to Settings application with below extra data:
117         // -DEVICE_PICKER_FILTER_TYPE: the type of BT devices that want to show.
118         // -DEVICE_PICKER_LAUNCH_PACKAGE: the package which the application belongs to.
119         // -DEVICE_PICKER_LAUNCH_CLASS: the class which will receive user's selected
120         // result from the BT list.
121         // -DEVICE_PICKER_NEED_AUTH: to show if bonding procedure needed.
122
123         mFilterType = BluetoothDevicePicker.FILTER_TYPE_ALL;
124         Intent intent = getIntent();
125         String action = intent.getAction();
126
127         if (action.equals(BluetoothDevicePicker.ACTION_LAUNCH)) {
128             mScreenType = SCREEN_TYPE_DEVICEPICKER;
129             mNeedAuth = intent.getBooleanExtra(BluetoothDevicePicker.EXTRA_NEED_AUTH, false);
130             mFilterType = intent.getIntExtra(BluetoothDevicePicker.EXTRA_FILTER_TYPE,
131                     BluetoothDevicePicker.FILTER_TYPE_ALL);
132             mLaunchPackage = intent.getStringExtra(BluetoothDevicePicker.EXTRA_LAUNCH_PACKAGE);
133             mLaunchClass = intent.getStringExtra(BluetoothDevicePicker.EXTRA_LAUNCH_CLASS);
134
135             setTitle(getString(R.string.device_picker));
136             addPreferencesFromResource(R.xml.device_picker);
137         } else {
138             addPreferencesFromResource(R.xml.bluetooth_settings);
139
140             mEnabler = new BluetoothEnabler(
141                     this,
142                     (CheckBoxPreference) findPreference(KEY_BT_CHECKBOX));
143
144             mDiscoverableEnabler = new BluetoothDiscoverableEnabler(
145                     this,
146                     (CheckBoxPreference) findPreference(KEY_BT_DISCOVERABLE));
147
148             mNamePreference = (BluetoothNamePreference) findPreference(KEY_BT_NAME);
149
150             mDeviceList = (ProgressCategory) findPreference(KEY_BT_DEVICE_LIST);
151         }
152
153         mDeviceList = (ProgressCategory) findPreference(KEY_BT_DEVICE_LIST);
154
155         registerForContextMenu(getListView());
156     }
157
158     @Override
159     protected void onResume() {
160         super.onResume();
161
162         // Repopulate (which isn't too bad since it's cached in the settings
163         // bluetooth manager
164         mDevicePreferenceMap.clear();
165         mDeviceList.removeAll();
166         addDevices();
167
168         if (mScreenType == SCREEN_TYPE_SETTINGS) {
169             mEnabler.resume();
170             mDiscoverableEnabler.resume();
171             mNamePreference.resume();
172         }
173
174         mLocalManager.registerCallback(this);
175
176         mDeviceList.setProgress(mLocalManager.getBluetoothAdapter().isDiscovering());
177         mLocalManager.startScanning(false);
178
179         IntentFilter intentFilter = new IntentFilter();
180         intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
181         intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
182         registerReceiver(mReceiver, intentFilter);
183         mLocalManager.setForegroundActivity(this);
184     }
185
186     @Override
187     protected void onPause() {
188         super.onPause();
189
190         mLocalManager.setForegroundActivity(null);
191
192         unregisterReceiver(mReceiver);
193
194         mLocalManager.unregisterCallback(this);
195         if (mScreenType == SCREEN_TYPE_SETTINGS) {
196             mNamePreference.pause();
197             mDiscoverableEnabler.pause();
198             mEnabler.pause();
199         }
200     }
201
202     @Override
203     protected void onUserLeaveHint() {
204         super.onUserLeaveHint();
205         mLocalManager.stopScanning();
206     }
207
208     private void addDevices() {
209         List<CachedBluetoothDevice> cachedDevices =
210                 mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
211         for (CachedBluetoothDevice cachedDevice : cachedDevices) {
212             onDeviceAdded(cachedDevice);
213         }
214     }
215
216     @Override
217     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
218             Preference preference) {
219
220         if (KEY_BT_SCAN.equals(preference.getKey())) {
221             mLocalManager.startScanning(true);
222             return true;
223         }
224
225         if (preference instanceof BluetoothDevicePreference) {
226             BluetoothDevicePreference btPreference = (BluetoothDevicePreference)preference;
227             if (mScreenType == SCREEN_TYPE_SETTINGS) {
228                 btPreference.getCachedDevice().onClicked();
229             } else if (mScreenType == SCREEN_TYPE_DEVICEPICKER) {
230                 CachedBluetoothDevice device = btPreference.getCachedDevice();
231
232                 mSelectedDevice = device.getDevice();
233                 mLocalManager.stopScanning();
234                 mLocalManager.persistSelectedDeviceInPicker(mSelectedDevice.getAddress());
235                 if ((device.getBondState() == BluetoothDevice.BOND_BONDED) ||
236                         (mNeedAuth == false)) {
237                     sendDevicePickedIntent(mSelectedDevice);
238                     finish();
239                 } else {
240                     btPreference.getCachedDevice().onClicked();
241                 }
242             }
243             return true;
244         }
245
246         return super.onPreferenceTreeClick(preferenceScreen, preference);
247     }
248
249     @Override
250     public void onCreateContextMenu(ContextMenu menu, View v,
251             ContextMenuInfo menuInfo) {
252         //For device picker, disable Context Menu
253         if (mScreenType != SCREEN_TYPE_SETTINGS) {
254             return;
255         }
256         CachedBluetoothDevice cachedDevice = getDeviceFromMenuInfo(menuInfo);
257         if (cachedDevice == null) return;
258
259         cachedDevice.onCreateContextMenu(menu);
260     }
261
262     @Override
263     public boolean onContextItemSelected(MenuItem item) {
264         CachedBluetoothDevice cachedDevice = getDeviceFromMenuInfo(item.getMenuInfo());
265         if (cachedDevice == null) return false;
266
267         cachedDevice.onContextItemSelected(item);
268         return true;
269     }
270
271     private CachedBluetoothDevice getDeviceFromMenuInfo(ContextMenuInfo menuInfo) {
272         if ((menuInfo == null) || !(menuInfo instanceof AdapterContextMenuInfo)) {
273             return null;
274         }
275
276         AdapterContextMenuInfo adapterMenuInfo = (AdapterContextMenuInfo) menuInfo;
277         Preference pref = (Preference) getPreferenceScreen().getRootAdapter().getItem(
278                 adapterMenuInfo.position);
279         if (pref == null || !(pref instanceof BluetoothDevicePreference)) {
280             return null;
281         }
282
283         return ((BluetoothDevicePreference) pref).getCachedDevice();
284     }
285
286     public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
287
288         if (mDevicePreferenceMap.get(cachedDevice) != null) {
289             throw new IllegalStateException("Got onDeviceAdded, but cachedDevice already exists");
290         }
291
292         if (addDevicePreference(cachedDevice)) {
293             createDevicePreference(cachedDevice);
294         }
295      }
296
297     private boolean addDevicePreference(CachedBluetoothDevice cachedDevice) {
298         ParcelUuid[] uuids = cachedDevice.getDevice().getUuids();
299         BluetoothClass bluetoothClass = cachedDevice.getDevice().getBluetoothClass();
300
301         switch(mFilterType) {
302         case BluetoothDevicePicker.FILTER_TYPE_TRANSFER:
303             if (uuids != null)
304                 if (BluetoothUuid.containsAnyUuid(uuids,
305                         LocalBluetoothProfileManager.OPP_PROFILE_UUIDS))  return true;
306                 if (bluetoothClass != null
307                         && bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_OPP)) {
308                     return true;
309                 }
310             break;
311         case BluetoothDevicePicker.FILTER_TYPE_AUDIO:
312             if (uuids != null) {
313                 if (BluetoothUuid.containsAnyUuid(uuids,
314                         LocalBluetoothProfileManager.A2DP_PROFILE_UUIDS))  return true;
315
316                 if (BluetoothUuid.containsAnyUuid(uuids,
317                         LocalBluetoothProfileManager.HEADSET_PROFILE_UUIDS))  return true;
318             } else if (bluetoothClass != null) {
319                 if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) return true;
320
321                 if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) return true;
322             }
323             break;
324         default:
325             return true;
326         }
327         return false;
328     }
329
330     private void createDevicePreference(CachedBluetoothDevice cachedDevice) {
331         BluetoothDevicePreference preference = new BluetoothDevicePreference(this, cachedDevice);
332         mDeviceList.addPreference(preference);
333         mDevicePreferenceMap.put(cachedDevice, preference);
334     }
335
336     public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
337         BluetoothDevicePreference preference = mDevicePreferenceMap.remove(cachedDevice);
338         if (preference != null) {
339             mDeviceList.removePreference(preference);
340         }
341     }
342
343     public void onScanningStateChanged(boolean started) {
344         mDeviceList.setProgress(started);
345     }
346
347     private void onBluetoothStateChanged(int bluetoothState) {
348         // When bluetooth is enabled (and we are in the activity, which we are),
349         // we should start a scan
350         if (bluetoothState == BluetoothAdapter.STATE_ON) {
351             mLocalManager.startScanning(false);
352         } else if (bluetoothState == BluetoothAdapter.STATE_OFF) {
353             mDeviceList.setProgress(false);
354         }
355     }
356
357     private void sendDevicePickedIntent(BluetoothDevice device) {
358         Intent intent = new Intent(BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
359         if (mLaunchPackage != null && mLaunchClass != null) {
360             intent.setClassName(mLaunchPackage, mLaunchClass);
361         }
362         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
363         sendBroadcast(intent);
364     }
365 }