2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings.bluetooth;
19 import com.android.settings.ProgressCategory;
20 import com.android.settings.R;
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;
43 import java.util.List;
44 import java.util.WeakHashMap;
47 * BluetoothSettings is the Settings screen for Bluetooth configuration and
48 * connection management.
50 public class BluetoothSettings extends PreferenceActivity
51 implements LocalBluetoothManager.Callback {
53 private static final String TAG = "BluetoothSettings";
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";
61 private static final int SCREEN_TYPE_SETTINGS = 0;
62 private static final int SCREEN_TYPE_DEVICEPICKER = 1;
64 private int mScreenType;
65 private int mFilterType;
66 private boolean mNeedAuth;
67 private String mLaunchPackage;
68 private String mLaunchClass;
70 private BluetoothDevice mSelectedDevice= null;
72 private LocalBluetoothManager mLocalManager;
74 private BluetoothEnabler mEnabler;
75 private BluetoothDiscoverableEnabler mDiscoverableEnabler;
77 private BluetoothNamePreference mNamePreference;
79 private ProgressCategory mDeviceList;
81 private WeakHashMap<CachedBluetoothDevice, BluetoothDevicePreference> mDevicePreferenceMap =
82 new WeakHashMap<CachedBluetoothDevice, BluetoothDevicePreference>();
84 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
86 public void onReceive(Context context, Intent intent) {
87 // TODO: put this in callback instead of receiving
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);
108 protected void onCreate(Bundle savedInstanceState) {
109 super.onCreate(savedInstanceState);
111 mLocalManager = LocalBluetoothManager.getInstance(this);
112 if (mLocalManager == null) finish();
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.
123 mFilterType = BluetoothDevicePicker.FILTER_TYPE_ALL;
124 Intent intent = getIntent();
125 String action = intent.getAction();
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);
135 setTitle(getString(R.string.device_picker));
136 addPreferencesFromResource(R.xml.device_picker);
138 addPreferencesFromResource(R.xml.bluetooth_settings);
140 mEnabler = new BluetoothEnabler(
142 (CheckBoxPreference) findPreference(KEY_BT_CHECKBOX));
144 mDiscoverableEnabler = new BluetoothDiscoverableEnabler(
146 (CheckBoxPreference) findPreference(KEY_BT_DISCOVERABLE));
148 mNamePreference = (BluetoothNamePreference) findPreference(KEY_BT_NAME);
150 mDeviceList = (ProgressCategory) findPreference(KEY_BT_DEVICE_LIST);
153 mDeviceList = (ProgressCategory) findPreference(KEY_BT_DEVICE_LIST);
155 registerForContextMenu(getListView());
159 protected void onResume() {
162 // Repopulate (which isn't too bad since it's cached in the settings
164 mDevicePreferenceMap.clear();
165 mDeviceList.removeAll();
168 if (mScreenType == SCREEN_TYPE_SETTINGS) {
170 mDiscoverableEnabler.resume();
171 mNamePreference.resume();
174 mLocalManager.registerCallback(this);
176 mDeviceList.setProgress(mLocalManager.getBluetoothAdapter().isDiscovering());
177 mLocalManager.startScanning(false);
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);
187 protected void onPause() {
190 mLocalManager.setForegroundActivity(null);
191 mDevicePreferenceMap.clear();
192 mDeviceList.removeAll();
193 unregisterReceiver(mReceiver);
195 mLocalManager.unregisterCallback(this);
196 if (mScreenType == SCREEN_TYPE_SETTINGS) {
197 mNamePreference.pause();
198 mDiscoverableEnabler.pause();
204 protected void onUserLeaveHint() {
205 super.onUserLeaveHint();
206 mLocalManager.stopScanning();
209 private void addDevices() {
210 List<CachedBluetoothDevice> cachedDevices =
211 mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
212 for (CachedBluetoothDevice cachedDevice : cachedDevices) {
213 onDeviceAdded(cachedDevice);
218 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
219 Preference preference) {
221 if (KEY_BT_SCAN.equals(preference.getKey())) {
222 mLocalManager.startScanning(true);
226 if (preference instanceof BluetoothDevicePreference) {
227 BluetoothDevicePreference btPreference = (BluetoothDevicePreference)preference;
228 if (mScreenType == SCREEN_TYPE_SETTINGS) {
229 btPreference.getCachedDevice().onClicked();
230 } else if (mScreenType == SCREEN_TYPE_DEVICEPICKER) {
231 CachedBluetoothDevice device = btPreference.getCachedDevice();
233 mSelectedDevice = device.getDevice();
234 mLocalManager.stopScanning();
235 mLocalManager.persistSelectedDeviceInPicker(mSelectedDevice.getAddress());
236 if ((device.getBondState() == BluetoothDevice.BOND_BONDED) ||
237 (mNeedAuth == false)) {
238 sendDevicePickedIntent(mSelectedDevice);
241 btPreference.getCachedDevice().onClicked();
247 return super.onPreferenceTreeClick(preferenceScreen, preference);
251 public void onCreateContextMenu(ContextMenu menu, View v,
252 ContextMenuInfo menuInfo) {
253 //For device picker, disable Context Menu
254 if (mScreenType != SCREEN_TYPE_SETTINGS) {
257 CachedBluetoothDevice cachedDevice = getDeviceFromMenuInfo(menuInfo);
258 if (cachedDevice == null) return;
260 cachedDevice.onCreateContextMenu(menu);
264 public boolean onContextItemSelected(MenuItem item) {
265 CachedBluetoothDevice cachedDevice = getDeviceFromMenuInfo(item.getMenuInfo());
266 if (cachedDevice == null) return false;
268 cachedDevice.onContextItemSelected(item);
272 private CachedBluetoothDevice getDeviceFromMenuInfo(ContextMenuInfo menuInfo) {
273 if ((menuInfo == null) || !(menuInfo instanceof AdapterContextMenuInfo)) {
277 AdapterContextMenuInfo adapterMenuInfo = (AdapterContextMenuInfo) menuInfo;
278 Preference pref = (Preference) getPreferenceScreen().getRootAdapter().getItem(
279 adapterMenuInfo.position);
280 if (pref == null || !(pref instanceof BluetoothDevicePreference)) {
284 return ((BluetoothDevicePreference) pref).getCachedDevice();
287 public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
289 if (mDevicePreferenceMap.get(cachedDevice) != null) {
290 throw new IllegalStateException("Got onDeviceAdded, but cachedDevice already exists");
293 if (addDevicePreference(cachedDevice)) {
294 createDevicePreference(cachedDevice);
298 private boolean addDevicePreference(CachedBluetoothDevice cachedDevice) {
299 ParcelUuid[] uuids = cachedDevice.getDevice().getUuids();
300 BluetoothClass bluetoothClass = cachedDevice.getDevice().getBluetoothClass();
302 switch(mFilterType) {
303 case BluetoothDevicePicker.FILTER_TYPE_TRANSFER:
305 if (BluetoothUuid.containsAnyUuid(uuids,
306 LocalBluetoothProfileManager.OPP_PROFILE_UUIDS)) return true;
307 if (bluetoothClass != null
308 && bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_OPP)) {
312 case BluetoothDevicePicker.FILTER_TYPE_AUDIO:
314 if (BluetoothUuid.containsAnyUuid(uuids,
315 LocalBluetoothProfileManager.A2DP_PROFILE_UUIDS)) return true;
317 if (BluetoothUuid.containsAnyUuid(uuids,
318 LocalBluetoothProfileManager.HEADSET_PROFILE_UUIDS)) return true;
319 } else if (bluetoothClass != null) {
320 if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) return true;
322 if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) return true;
331 private void createDevicePreference(CachedBluetoothDevice cachedDevice) {
332 BluetoothDevicePreference preference = new BluetoothDevicePreference(this, cachedDevice);
333 mDeviceList.addPreference(preference);
334 mDevicePreferenceMap.put(cachedDevice, preference);
337 public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
338 BluetoothDevicePreference preference = mDevicePreferenceMap.remove(cachedDevice);
339 if (preference != null) {
340 mDeviceList.removePreference(preference);
344 public void onScanningStateChanged(boolean started) {
345 mDeviceList.setProgress(started);
348 private void onBluetoothStateChanged(int bluetoothState) {
349 // When bluetooth is enabled (and we are in the activity, which we are),
350 // we should start a scan
351 if (bluetoothState == BluetoothAdapter.STATE_ON) {
352 mLocalManager.startScanning(false);
353 } else if (bluetoothState == BluetoothAdapter.STATE_OFF) {
354 mDeviceList.setProgress(false);
358 private void sendDevicePickedIntent(BluetoothDevice device) {
359 Intent intent = new Intent(BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
360 if (mLaunchPackage != null && mLaunchClass != null) {
361 intent.setClassName(mLaunchPackage, mLaunchClass);
363 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
364 sendBroadcast(intent);