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);
192 unregisterReceiver(mReceiver);
194 mLocalManager.unregisterCallback(this);
195 if (mScreenType == SCREEN_TYPE_SETTINGS) {
196 mNamePreference.pause();
197 mDiscoverableEnabler.pause();
203 protected void onUserLeaveHint() {
204 super.onUserLeaveHint();
205 mLocalManager.stopScanning();
208 private void addDevices() {
209 List<CachedBluetoothDevice> cachedDevices =
210 mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
211 for (CachedBluetoothDevice cachedDevice : cachedDevices) {
212 onDeviceAdded(cachedDevice);
217 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
218 Preference preference) {
220 if (KEY_BT_SCAN.equals(preference.getKey())) {
221 mLocalManager.startScanning(true);
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();
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);
240 btPreference.getCachedDevice().onClicked();
246 return super.onPreferenceTreeClick(preferenceScreen, preference);
250 public void onCreateContextMenu(ContextMenu menu, View v,
251 ContextMenuInfo menuInfo) {
252 //For device picker, disable Context Menu
253 if (mScreenType != SCREEN_TYPE_SETTINGS) {
256 CachedBluetoothDevice cachedDevice = getDeviceFromMenuInfo(menuInfo);
257 if (cachedDevice == null) return;
259 cachedDevice.onCreateContextMenu(menu);
263 public boolean onContextItemSelected(MenuItem item) {
264 CachedBluetoothDevice cachedDevice = getDeviceFromMenuInfo(item.getMenuInfo());
265 if (cachedDevice == null) return false;
267 cachedDevice.onContextItemSelected(item);
271 private CachedBluetoothDevice getDeviceFromMenuInfo(ContextMenuInfo menuInfo) {
272 if ((menuInfo == null) || !(menuInfo instanceof AdapterContextMenuInfo)) {
276 AdapterContextMenuInfo adapterMenuInfo = (AdapterContextMenuInfo) menuInfo;
277 Preference pref = (Preference) getPreferenceScreen().getRootAdapter().getItem(
278 adapterMenuInfo.position);
279 if (pref == null || !(pref instanceof BluetoothDevicePreference)) {
283 return ((BluetoothDevicePreference) pref).getCachedDevice();
286 public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
288 if (mDevicePreferenceMap.get(cachedDevice) != null) {
289 throw new IllegalStateException("Got onDeviceAdded, but cachedDevice already exists");
292 if (addDevicePreference(cachedDevice)) {
293 createDevicePreference(cachedDevice);
297 private boolean addDevicePreference(CachedBluetoothDevice cachedDevice) {
298 ParcelUuid[] uuids = cachedDevice.getDevice().getUuids();
299 BluetoothClass bluetoothClass = cachedDevice.getDevice().getBluetoothClass();
301 switch(mFilterType) {
302 case BluetoothDevicePicker.FILTER_TYPE_TRANSFER:
304 if (BluetoothUuid.containsAnyUuid(uuids,
305 LocalBluetoothProfileManager.OPP_PROFILE_UUIDS)) return true;
306 if (bluetoothClass != null
307 && bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_OPP)) {
311 case BluetoothDevicePicker.FILTER_TYPE_AUDIO:
313 if (BluetoothUuid.containsAnyUuid(uuids,
314 LocalBluetoothProfileManager.A2DP_PROFILE_UUIDS)) return true;
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;
321 if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) return true;
330 private void createDevicePreference(CachedBluetoothDevice cachedDevice) {
331 BluetoothDevicePreference preference = new BluetoothDevicePreference(this, cachedDevice);
332 mDeviceList.addPreference(preference);
333 mDevicePreferenceMap.put(cachedDevice, preference);
336 public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
337 BluetoothDevicePreference preference = mDevicePreferenceMap.remove(cachedDevice);
338 if (preference != null) {
339 mDeviceList.removePreference(preference);
343 public void onScanningStateChanged(boolean started) {
344 mDeviceList.setProgress(started);
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);
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);
362 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
363 sendBroadcast(intent);