summaryrefslogtreecommitdiffstats
path: root/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/com')
-rw-r--r--src/com/android/settings/TetherSettings.java37
-rw-r--r--src/com/android/settings/WirelessSettings.java5
-rw-r--r--src/com/android/settings/bluetooth/A2dpProfile.java166
-rw-r--r--src/com/android/settings/bluetooth/BluetoothCallback.java29
-rw-r--r--src/com/android/settings/bluetooth/BluetoothDeviceFilter.java159
-rw-r--r--src/com/android/settings/bluetooth/BluetoothDevicePreference.java210
-rw-r--r--src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java72
-rw-r--r--src/com/android/settings/bluetooth/BluetoothDiscoveryReceiver.java47
-rw-r--r--src/com/android/settings/bluetooth/BluetoothEnabler.java22
-rw-r--r--src/com/android/settings/bluetooth/BluetoothEventManager.java398
-rw-r--r--src/com/android/settings/bluetooth/BluetoothEventRedirector.java257
-rw-r--r--src/com/android/settings/bluetooth/BluetoothFindNearby.java29
-rw-r--r--src/com/android/settings/bluetooth/BluetoothNamePreference.java92
-rw-r--r--src/com/android/settings/bluetooth/BluetoothPairingDialog.java260
-rw-r--r--src/com/android/settings/bluetooth/BluetoothPairingRequest.java36
-rw-r--r--src/com/android/settings/bluetooth/BluetoothProfilePreference.java19
-rw-r--r--src/com/android/settings/bluetooth/BluetoothSettings.java60
-rw-r--r--src/com/android/settings/bluetooth/CachedBluetoothDevice.java490
-rw-r--r--src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java232
-rw-r--r--src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java174
-rw-r--r--src/com/android/settings/bluetooth/DevicePickerActivity.java2
-rw-r--r--src/com/android/settings/bluetooth/DevicePickerFragment.java40
-rw-r--r--src/com/android/settings/bluetooth/DeviceProfilesSettings.java211
-rw-r--r--src/com/android/settings/bluetooth/DockEventReceiver.java31
-rw-r--r--src/com/android/settings/bluetooth/DockService.java721
-rw-r--r--src/com/android/settings/bluetooth/HeadsetProfile.java198
-rw-r--r--src/com/android/settings/bluetooth/HidProfile.java155
-rw-r--r--src/com/android/settings/bluetooth/LocalBluetoothAdapter.java216
-rw-r--r--src/com/android/settings/bluetooth/LocalBluetoothManager.java382
-rw-r--r--src/com/android/settings/bluetooth/LocalBluetoothPreferences.java157
-rw-r--r--src/com/android/settings/bluetooth/LocalBluetoothProfile.java76
-rw-r--r--src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java895
-rw-r--r--src/com/android/settings/bluetooth/OppProfile.java92
-rw-r--r--src/com/android/settings/bluetooth/PanProfile.java135
-rw-r--r--src/com/android/settings/bluetooth/RequestPermissionActivity.java82
-rw-r--r--src/com/android/settings/bluetooth/RequestPermissionHelperActivity.java35
-rw-r--r--src/com/android/settings/bluetooth/SettingsBtStatus.java81
-rw-r--r--src/com/android/settings/bluetooth/Utf8ByteLengthFilter.java84
-rw-r--r--src/com/android/settings/bluetooth/Utils.java99
-rw-r--r--src/com/android/settings/widget/SettingsAppWidgetProvider.java35
40 files changed, 3503 insertions, 3018 deletions
diff --git a/src/com/android/settings/TetherSettings.java b/src/com/android/settings/TetherSettings.java
index 2ff32541d..af831576b 100644
--- a/src/com/android/settings/TetherSettings.java
+++ b/src/com/android/settings/TetherSettings.java
@@ -35,8 +35,6 @@ import android.os.Environment;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceScreen;
-import android.view.LayoutInflater;
-import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.webkit.WebView;
@@ -49,7 +47,6 @@ import java.util.Locale;
* Displays preferences for Tethering.
*/
public class TetherSettings extends SettingsPreferenceFragment {
- private static final String TAG = "TetheringSettings";
private static final String USB_TETHER_SETTINGS = "usb_tether_settings";
private static final String ENABLE_WIFI_AP = "enable_wifi_ap";
@@ -66,8 +63,6 @@ public class TetherSettings extends SettingsPreferenceFragment {
private WebView mView;
private CheckBoxPreference mUsbTether;
- private CheckBoxPreference mEnableWifiAp;
- private PreferenceScreen mWifiApSettings;
private WifiApEnabler mWifiApEnabler;
private CheckBoxPreference mBluetoothTether;
@@ -95,9 +90,9 @@ public class TetherSettings extends SettingsPreferenceFragment {
BluetoothProfile.PAN);
}
-
- mEnableWifiAp = (CheckBoxPreference) findPreference(ENABLE_WIFI_AP);
- mWifiApSettings = (PreferenceScreen) findPreference(WIFI_AP_SETTINGS);
+ CheckBoxPreference enableWifiAp =
+ (CheckBoxPreference) findPreference(ENABLE_WIFI_AP);
+ Preference wifiApSettings = findPreference(WIFI_AP_SETTINGS);
mUsbTether = (CheckBoxPreference) findPreference(USB_TETHER_SETTINGS);
mBluetoothTether = (CheckBoxPreference) findPreference(ENABLE_BLUETOOTH_TETHERING);
mTetherHelp = (PreferenceScreen) findPreference(TETHERING_HELP);
@@ -118,8 +113,8 @@ public class TetherSettings extends SettingsPreferenceFragment {
}
if (!wifiAvailable) {
- getPreferenceScreen().removePreference(mEnableWifiAp);
- getPreferenceScreen().removePreference(mWifiApSettings);
+ getPreferenceScreen().removePreference(enableWifiAp);
+ getPreferenceScreen().removePreference(wifiApSettings);
}
if (!bluetoothAvailable) {
@@ -132,7 +127,7 @@ public class TetherSettings extends SettingsPreferenceFragment {
}
}
- mWifiApEnabler = new WifiApEnabler(activity, mEnableWifiAp);
+ mWifiApEnabler = new WifiApEnabler(activity, enableWifiAp);
mView = new WebView(activity);
}
@@ -154,22 +149,22 @@ public class TetherSettings extends SettingsPreferenceFragment {
// check for the full language + country resource, if not there, try just language
final AssetManager am = getActivity().getAssets();
String path = HELP_PATH.replace("%y", locale.getLanguage().toLowerCase());
- path = path.replace("%z", "_"+locale.getCountry().toLowerCase());
+ path = path.replace("%z", '_'+locale.getCountry().toLowerCase());
boolean useCountry = true;
InputStream is = null;
try {
is = am.open(path);
- } catch (Exception e) {
+ } catch (Exception ignored) {
useCountry = false;
} finally {
if (is != null) {
try {
is.close();
- } catch (Exception e) {}
+ } catch (Exception ignored) {}
}
}
String url = HELP_URL.replace("%y", locale.getLanguage().toLowerCase());
- url = url.replace("%z", (useCountry ? "_"+locale.getCountry().toLowerCase() : ""));
+ url = url.replace("%z", useCountry ? '_'+locale.getCountry().toLowerCase() : "");
if ((mUsbRegexs.length != 0) && (mWifiRegexs.length == 0)) {
url = url.replace("%x", USB_HELP_MODIFIER);
} else if ((mWifiRegexs.length != 0) && (mUsbRegexs.length == 0)) {
@@ -271,10 +266,8 @@ public class TetherSettings extends SettingsPreferenceFragment {
String[] errored) {
ConnectivityManager cm =
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
- boolean usbTethered = false;
boolean usbAvailable = false;
int usbError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
- boolean usbErrored = false;
boolean massStorageActive =
Environment.MEDIA_SHARED.equals(Environment.getExternalStorageState());
for (String s : available) {
@@ -287,11 +280,13 @@ public class TetherSettings extends SettingsPreferenceFragment {
}
}
}
+ boolean usbTethered = false;
for (String s : tethered) {
for (String regex : mUsbRegexs) {
if (s.matches(regex)) usbTethered = true;
}
}
+ boolean usbErrored = false;
for (String s: errored) {
for (String regex : mUsbRegexs) {
if (s.matches(regex)) usbErrored = true;
@@ -329,25 +324,23 @@ public class TetherSettings extends SettingsPreferenceFragment {
String[] errored) {
ConnectivityManager cm =
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
- boolean bluetoothTethered = false;
- boolean bluetoothAvailable = false;
int bluetoothError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
- boolean bluetoothErrored = false;
for (String s : available) {
for (String regex : mBluetoothRegexs) {
if (s.matches(regex)) {
- bluetoothAvailable = true;
if (bluetoothError == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
bluetoothError = cm.getLastTetherError(s);
}
}
}
}
+ boolean bluetoothTethered = false;
for (String s : tethered) {
for (String regex : mBluetoothRegexs) {
if (s.matches(regex)) bluetoothTethered = true;
}
}
+ boolean bluetoothErrored = false;
for (String s: errored) {
for (String regex : mBluetoothRegexs) {
if (s.matches(regex)) bluetoothErrored = true;
@@ -458,7 +451,7 @@ public class TetherSettings extends SettingsPreferenceFragment {
return super.onPreferenceTreeClick(screen, preference);
}
- private String findIface(String[] ifaces, String[] regexes) {
+ private static String findIface(String[] ifaces, String[] regexes) {
for (String iface : ifaces) {
for (String regex : regexes) {
if (iface.matches(regex)) {
diff --git a/src/com/android/settings/WirelessSettings.java b/src/com/android/settings/WirelessSettings.java
index b1b7e6ec1..4b927491c 100644
--- a/src/com/android/settings/WirelessSettings.java
+++ b/src/com/android/settings/WirelessSettings.java
@@ -19,6 +19,8 @@ package com.android.settings;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyProperties;
import com.android.settings.bluetooth.BluetoothEnabler;
+import com.android.settings.bluetooth.LocalBluetoothAdapter;
+import com.android.settings.bluetooth.LocalBluetoothManager;
import com.android.settings.wifi.WifiEnabler;
import com.android.settings.nfc.NfcEnabler;
@@ -103,7 +105,8 @@ public class WirelessSettings extends SettingsPreferenceFragment {
mAirplaneModeEnabler = new AirplaneModeEnabler(activity, airplane);
mAirplaneModePreference = (CheckBoxPreference) findPreference(KEY_TOGGLE_AIRPLANE);
mWifiEnabler = new WifiEnabler(activity, wifi);
- mBtEnabler = new BluetoothEnabler(activity, bt);
+ mBtEnabler = new BluetoothEnabler(activity,
+ LocalBluetoothManager.getInstance(activity).getBluetoothAdapter(), bt);
mNfcEnabler = new NfcEnabler(activity, nfc);
String toggleable = Settings.System.getString(activity.getContentResolver(),
diff --git a/src/com/android/settings/bluetooth/A2dpProfile.java b/src/com/android/settings/bluetooth/A2dpProfile.java
new file mode 100644
index 000000000..96225d87c
--- /dev/null
+++ b/src/com/android/settings/bluetooth/A2dpProfile.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+
+import com.android.settings.R;
+
+import java.util.List;
+
+/**
+ * A2dpProfile handles Bluetooth A2DP.
+ * TODO: add null checks around calls to mService object.
+ */
+final class A2dpProfile implements LocalBluetoothProfile {
+ private BluetoothA2dp mService;
+
+ static final ParcelUuid[] SINK_UUIDS = {
+ BluetoothUuid.AudioSink,
+ BluetoothUuid.AdvAudioDist,
+ };
+
+ static final String NAME = "A2DP";
+
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 1;
+
+ // These callbacks run on the main thread.
+ private final class A2dpServiceListener
+ implements BluetoothProfile.ServiceListener {
+
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ mService = (BluetoothA2dp) proxy;
+ }
+
+ public void onServiceDisconnected(int profile) {
+ mService = null;
+ }
+ }
+
+ A2dpProfile(Context context) {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ adapter.getProfileProxy(context, new A2dpServiceListener(),
+ BluetoothProfile.A2DP);
+ }
+
+ public boolean isConnectable() {
+ return true;
+ }
+
+ public boolean isAutoConnectable() {
+ return true;
+ }
+
+ private List<BluetoothDevice> getConnectedDevices() {
+ return mService.getDevicesMatchingConnectionStates(
+ new int[] {BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTING});
+ }
+
+ public boolean connect(BluetoothDevice device) {
+ List<BluetoothDevice> sinks = getConnectedDevices();
+ if (sinks != null) {
+ for (BluetoothDevice sink : sinks) {
+ mService.disconnect(sink);
+ }
+ }
+ return mService.connect(device);
+ }
+
+ public boolean disconnect(BluetoothDevice device) {
+ return mService.disconnect(device);
+ }
+
+ public int getConnectionStatus(BluetoothDevice device) {
+ return mService.getConnectionState(device);
+ }
+
+ public boolean isPreferred(BluetoothDevice device) {
+ return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ }
+
+ public int getPreferred(BluetoothDevice device) {
+ return mService.getPriority(device);
+ }
+
+ public void setPreferred(BluetoothDevice device, boolean preferred) {
+ if (preferred) {
+ if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ } else {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ }
+ }
+
+ boolean isA2dpPlaying() {
+ List<BluetoothDevice> sinks = mService.getConnectedDevices();
+ if (!sinks.isEmpty()) {
+ if (mService.isA2dpPlaying(sinks.get(0))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isProfileReady() {
+ return mService != null;
+ }
+
+ public String toString() {
+ return NAME;
+ }
+
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ public int getNameResource() {
+ return R.string.bluetooth_profile_a2dp;
+ }
+
+ public int getDisconnectResource() {
+ return R.string.bluetooth_disconnect_a2dp_profile;
+ }
+
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ int state = mService.getConnectionState(device);
+ switch (state) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ return R.string.bluetooth_a2dp_profile_summary_use_for;
+
+ case BluetoothProfile.STATE_CONNECTED:
+ return R.string.bluetooth_a2dp_profile_summary_connected;
+
+ default:
+ return Utils.getConnectionStateSummary(state);
+ }
+ }
+
+ public int getDrawableResource(BluetoothClass btClass) {
+ return R.drawable.ic_bt_headphones_a2dp;
+ }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothCallback.java b/src/com/android/settings/bluetooth/BluetoothCallback.java
new file mode 100644
index 000000000..3ce9adfef
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BluetoothCallback.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+/**
+ * BluetoothCallback provides a callback interface for the settings
+ * UI to receive events from {@link BluetoothEventManager}.
+ */
+interface BluetoothCallback {
+ void onBluetoothStateChanged(int bluetoothState);
+ void onScanningStateChanged(boolean started);
+ void onDeviceAdded(CachedBluetoothDevice cachedDevice);
+ void onDeviceDeleted(CachedBluetoothDevice cachedDevice);
+ void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState);
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceFilter.java b/src/com/android/settings/bluetooth/BluetoothDeviceFilter.java
new file mode 100644
index 000000000..00e342ced
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceFilter.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothUuid;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+/**
+ * BluetoothDeviceFilter contains a static method that returns a
+ * Filter object that returns whether or not the BluetoothDevice
+ * passed to it matches the specified filter type constant from
+ * {@link android.bluetooth.BluetoothDevicePicker}.
+ */
+final class BluetoothDeviceFilter {
+ private static final String TAG = "BluetoothDeviceFilter";
+
+ /** The filter interface to external classes. */
+ interface Filter {
+ boolean matches(BluetoothDevice device);
+ }
+
+ /** All filter singleton (referenced directly). */
+ static final Filter ALL_FILTER = new AllFilter();
+
+ /** Bonded devices only filter (referenced directly). */
+ static final Filter BONDED_DEVICE_FILTER = new BondedDeviceFilter();
+
+ /** Table of singleton filter objects. */
+ private static final Filter[] FILTERS = {
+ ALL_FILTER, // FILTER_TYPE_ALL
+ new AudioFilter(), // FILTER_TYPE_AUDIO
+ new TransferFilter(), // FILTER_TYPE_TRANSFER
+ new PanuFilter(), // FILTER_TYPE_PANU
+ new NapFilter() // FILTER_TYPE_NAP
+ };
+
+ /** Private constructor. */
+ private BluetoothDeviceFilter() {
+ }
+
+ /**
+ * Returns the singleton {@link Filter} object for the specified type,
+ * or {@link #ALL_FILTER} if the type value is out of range.
+ *
+ * @param filterType a constant from BluetoothDevicePicker
+ * @return a singleton object implementing the {@link Filter} interface.
+ */
+ static Filter getFilter(int filterType) {
+ if (filterType >= 0 && filterType < FILTERS.length) {
+ return FILTERS[filterType];
+ } else {
+ Log.w(TAG, "Invalid filter type " + filterType + " for device picker");
+ return ALL_FILTER;
+ }
+ }
+
+ /** Filter that matches all devices. */
+ private static final class AllFilter implements Filter {
+ public boolean matches(BluetoothDevice device) {
+ return true;
+ }
+ }
+
+ /** Filter that matches only bonded devices. */
+ private static final class BondedDeviceFilter implements Filter {
+ public boolean matches(BluetoothDevice device) {
+ return device.getBondState() == BluetoothDevice.BOND_BONDED;
+ }
+ }
+
+ /** Parent class of filters based on UUID and/or Bluetooth class. */
+ private abstract static class ClassUuidFilter implements Filter {
+ abstract boolean matches(ParcelUuid[] uuids, BluetoothClass btClass);
+
+ public boolean matches(BluetoothDevice device) {
+ return matches(device.getUuids(), device.getBluetoothClass());
+ }
+ }
+
+ /** Filter that matches devices that support AUDIO profiles. */
+ private static final class AudioFilter extends ClassUuidFilter {
+ @Override
+ boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
+ if (uuids != null) {
+ if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS)) {
+ return true;
+ }
+ if (BluetoothUuid.containsAnyUuid(uuids, HeadsetProfile.UUIDS)) {
+ return true;
+ }
+ } else if (btClass != null) {
+ if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP) ||
+ btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /** Filter that matches devices that support Object Transfer. */
+ private static final class TransferFilter extends ClassUuidFilter {
+ @Override
+ boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
+ if (uuids != null) {
+ if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) {
+ return true;
+ }
+ }
+ return btClass != null
+ && btClass.doesClassMatch(BluetoothClass.PROFILE_OPP);
+ }
+ }
+
+ /** Filter that matches devices that support PAN User (PANU) profile. */
+ private static final class PanuFilter extends ClassUuidFilter {
+ @Override
+ boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
+ if (uuids != null) {
+ if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.PANU)) {
+ return true;
+ }
+ }
+ return btClass != null
+ && btClass.doesClassMatch(BluetoothClass.PROFILE_PANU);
+ }
+ }
+
+ /** Filter that matches devices that support NAP profile. */
+ private static final class NapFilter extends ClassUuidFilter {
+ @Override
+ boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
+ if (uuids != null) {
+ if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP)) {
+ return true;
+ }
+ }
+ return btClass != null
+ && btClass.doesClassMatch(BluetoothClass.PROFILE_NAP);
+ }
+ }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
index 6a0b8811c..5f791d942 100644
--- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
+++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
@@ -16,27 +16,32 @@
package com.android.settings.bluetooth;
-import com.android.settings.R;
-
+import android.app.AlertDialog;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
import android.content.Context;
+import android.content.DialogInterface;
import android.graphics.drawable.Drawable;
import android.preference.Preference;
+import android.text.TextUtils;
+import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
import android.view.View.OnClickListener;
+import android.view.ViewGroup;
import android.widget.ImageView;
-import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
+import com.android.settings.R;
-import java.util.Map;
+import java.util.List;
/**
* BluetoothDevicePreference is the preference type used to display each remote
* Bluetooth device in the Bluetooth Settings screen.
*/
-public class BluetoothDevicePreference extends Preference implements
+public final class BluetoothDevicePreference extends Preference implements
CachedBluetoothDevice.Callback, OnClickListener {
private static final String TAG = "BluetoothDevicePreference";
@@ -48,11 +53,7 @@ public class BluetoothDevicePreference extends Preference implements
private OnClickListener mOnSettingsClickListener;
- /**
- * Cached local copy of whether the device is busy. This is only updated
- * from {@link #onDeviceAttributesChanged()}.
- */
- private boolean mIsBusy;
+ private AlertDialog mDisconnectDialog;
public BluetoothDevicePreference(Context context, CachedBluetoothDevice cachedDevice) {
super(context);
@@ -60,19 +61,19 @@ public class BluetoothDevicePreference extends Preference implements
if (sDimAlpha == Integer.MIN_VALUE) {
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true);
- sDimAlpha = (int) ((outValue.getFloat() * 255) * 0.5);
+ sDimAlpha = (int) (outValue.getFloat() * 255);
}
mCachedDevice = cachedDevice;
setWidgetLayoutResource(R.layout.preference_bluetooth);
- cachedDevice.registerCallback(this);
+ mCachedDevice.registerCallback(this);
onDeviceAttributesChanged();
}
- public CachedBluetoothDevice getCachedDevice() {
+ CachedBluetoothDevice getCachedDevice() {
return mCachedDevice;
}
@@ -84,42 +85,30 @@ public class BluetoothDevicePreference extends Preference implements
protected void onPrepareForRemoval() {
super.onPrepareForRemoval();
mCachedDevice.unregisterCallback(this);
+ if (mDisconnectDialog != null) {
+ mDisconnectDialog.dismiss();
+ mDisconnectDialog = null;
+ }
}
public void onDeviceAttributesChanged() {
-
/*
* The preference framework takes care of making sure the value has
- * changed before proceeding.
+ * changed before proceeding. It will also call notifyChanged() if
+ * any preference info has changed from the previous value.
*/
-
setTitle(mCachedDevice.getName());
- /*
- * TODO: Showed "Paired" even though it was "Connected". This may be
- * related to BluetoothHeadset not bound to the actual
- * BluetoothHeadsetService when we got here.
- */
- setSummary(mCachedDevice.getSummary());
+ setSummary(getConnectionSummary());
// Used to gray out the item
- mIsBusy = mCachedDevice.isBusy();
-
- // Data has changed
- notifyChanged();
+ setEnabled(!mCachedDevice.isBusy());
- // This could affect ordering, so notify that also
+ // This could affect ordering, so notify that
notifyHierarchyChanged();
}
@Override
- public boolean isEnabled() {
- // Temp fix until we have 2053751 fixed in the framework
- setEnabled(true);
- return super.isEnabled() && !mIsBusy;
- }
-
- @Override
protected void onBindView(View view) {
// Disable this view if the bluetooth enable/disable preference view is off
if (null != findPreferenceInHierarchy("bt_checkbox")) {
@@ -129,17 +118,17 @@ public class BluetoothDevicePreference extends Preference implements
super.onBindView(view);
ImageView btClass = (ImageView) view.findViewById(android.R.id.icon);
- btClass.setImageResource(mCachedDevice.getBtClassDrawable());
- btClass.setAlpha(!mIsBusy ? 255 : sDimAlpha);
+ btClass.setImageResource(getBtClassDrawable());
+ btClass.setAlpha(isEnabled() ? 255 : sDimAlpha);
mDeviceSettings = (ImageView) view.findViewById(R.id.deviceDetails);
if (mOnSettingsClickListener != null) {
mDeviceSettings.setOnClickListener(this);
mDeviceSettings.setTag(mCachedDevice);
- mDeviceSettings.setAlpha(!mIsBusy ? 255 : sDimAlpha);
+ mDeviceSettings.setAlpha(isEnabled() ? 255 : sDimAlpha);
} else { // Hide the settings icon and divider
mDeviceSettings.setVisibility(View.GONE);
- ImageView divider = (ImageView) view.findViewById(R.id.divider);
+ View divider = view.findViewById(R.id.divider);
if (divider != null) {
divider.setVisibility(View.GONE);
}
@@ -148,24 +137,40 @@ public class BluetoothDevicePreference extends Preference implements
LayoutInflater inflater = (LayoutInflater)
getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ViewGroup profilesGroup = (ViewGroup) view.findViewById(R.id.profileIcons);
- Map<Profile, Drawable> profileIcons = mCachedDevice.getProfileIcons();
- for (Profile profile : profileIcons.keySet()) {
- Drawable icon = profileIcons.get(profile);
- inflater.inflate(R.layout.profile_icon_small, profilesGroup, true);
- ImageView imageView =
- (ImageView) profilesGroup.getChildAt(profilesGroup.getChildCount() - 1);
- imageView.setImageDrawable(icon);
- boolean profileEnabled = mCachedDevice.isConnectedProfile(profile);
- imageView.setAlpha(profileEnabled ? 255 : sDimAlpha);
+ for (LocalBluetoothProfile profile : mCachedDevice.getProfiles()) {
+ int iconResource = profile.getDrawableResource(mCachedDevice.getBtClass());
+ if (iconResource != 0) {
+ Drawable icon = getContext().getResources().getDrawable(iconResource);
+ inflater.inflate(R.layout.profile_icon_small, profilesGroup, true);
+ ImageView imageView =
+ (ImageView) profilesGroup.getChildAt(profilesGroup.getChildCount() - 1);
+ imageView.setImageDrawable(icon);
+ boolean profileEnabled = mCachedDevice.isConnectedProfile(profile);
+ imageView.setAlpha(profileEnabled ? 255 : sDimAlpha);
+ }
}
}
public void onClick(View v) {
if (v == mDeviceSettings) {
- if (mOnSettingsClickListener != null) mOnSettingsClickListener.onClick(v);
+ if (mOnSettingsClickListener != null) {
+ mOnSettingsClickListener.onClick(v);
+ }
}
}
+ public boolean equals(Object o) {
+ if ((o == null) || !(o instanceof BluetoothDevicePreference)) {
+ return false;
+ }
+ return mCachedDevice.equals(
+ ((BluetoothDevicePreference) o).mCachedDevice);
+ }
+
+ public int hashCode() {
+ return mCachedDevice.hashCode();
+ }
+
@Override
public int compareTo(Preference another) {
if (!(another instanceof BluetoothDevicePreference)) {
@@ -173,7 +178,112 @@ public class BluetoothDevicePreference extends Preference implements
return 1;
}
- return mCachedDevice.compareTo(((BluetoothDevicePreference) another).mCachedDevice);
+ return mCachedDevice
+ .compareTo(((BluetoothDevicePreference) another).mCachedDevice);
+ }
+
+ void onClicked() {
+ int bondState = mCachedDevice.getBondState();
+
+ if (mCachedDevice.isConnected()) {
+ askDisconnect();
+ } else if (bondState == BluetoothDevice.BOND_BONDED) {
+ mCachedDevice.connect(true);
+ } else if (bondState == BluetoothDevice.BOND_NONE) {
+ pair();
+ }
+ }
+
+ // Show disconnect confirmation dialog for a device.
+ private void askDisconnect() {
+ Context context = getContext();
+ String name = mCachedDevice.getName();
+ if (TextUtils.isEmpty(name)) {
+ name = context.getString(R.string.bluetooth_device);
+ }
+ String message = context.getString(R.string.bluetooth_disconnect_blank, name);
+
+ DialogInterface.OnClickListener disconnectListener = new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ mCachedDevice.disconnect();
+ }
+ };
+
+ mDisconnectDialog = Utils.showDisconnectDialog(context,
+ mDisconnectDialog, disconnectListener, name, message);
+ }
+
+ private void pair() {
+ if (!mCachedDevice.startPairing()) {
+ Utils.showError(getContext(), mCachedDevice.getName(),
+ R.string.bluetooth_pairing_error_message);
+ }
+ }
+
+ private int getConnectionSummary() {
+ final CachedBluetoothDevice cachedDevice = mCachedDevice;
+ final BluetoothDevice device = cachedDevice.getDevice();
+
+ // if any profiles are connected or busy, return that status
+ for (LocalBluetoothProfile profile : cachedDevice.getProfiles()) {
+ int connectionStatus = profile.getConnectionStatus(device);
+
+ if (connectionStatus != BluetoothProfile.STATE_DISCONNECTED) {
+ return Utils.getConnectionStateSummary(connectionStatus);
+ }
+ }
+
+ switch (cachedDevice.getBondState()) {
+ case BluetoothDevice.BOND_BONDED:
+ return R.string.bluetooth_paired;
+ case BluetoothDevice.BOND_BONDING:
+ return R.string.bluetooth_pairing;
+ case BluetoothDevice.BOND_NONE:
+ return R.string.bluetooth_not_connected;
+ default:
+ return 0;
+ }
}
+ private int getBtClassDrawable() {
+ BluetoothClass btClass = mCachedDevice.getBtClass();
+ if (btClass != null) {
+ switch (btClass.getMajorDeviceClass()) {
+ case BluetoothClass.Device.Major.COMPUTER:
+ return R.drawable.ic_bt_laptop;
+
+ case BluetoothClass.Device.Major.PHONE:
+ return R.drawable.ic_bt_cellphone;
+
+ case BluetoothClass.Device.Major.PERIPHERAL:
+ return HidProfile.getHidClassDrawable(btClass);
+
+ case BluetoothClass.Device.Major.IMAGING:
+ return R.drawable.ic_bt_imaging;
+
+ default:
+ // unrecognized device class; continue
+ }
+ } else {
+ Log.w(TAG, "mBtClass is null");
+ }
+
+ List<LocalBluetoothProfile> profiles = mCachedDevice.getProfiles();
+ for (LocalBluetoothProfile profile : profiles) {
+ int resId = profile.getDrawableResource(btClass);
+ if (resId != 0) {
+ return resId;
+ }
+ }
+ if (btClass != null) {
+ if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) {
+ return R.drawable.ic_bt_headphones_a2dp;
+
+ }
+ if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
+ return R.drawable.ic_bt_headset_hfp;
+ }
+ }
+ return 0;
+ }
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java b/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java
index 166e4aea0..40bf5bc3a 100644
--- a/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java
+++ b/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java
@@ -16,41 +16,34 @@
package com.android.settings.bluetooth;
-import com.android.settings.R;
-
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.SharedPreferences;
import android.os.Handler;
import android.os.SystemProperties;
+import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
-import android.preference.CheckBoxPreference;
-import android.provider.Settings;
-import android.util.Log;
+
+import com.android.settings.R;
/**
* BluetoothDiscoverableEnabler is a helper to manage the "Discoverable"
* checkbox. It sets/unsets discoverability and keeps track of how much time
* until the the discoverability is automatically turned off.
*/
-public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChangeListener {
- private static final String TAG = "BluetoothDiscoverableEnabler";
+final class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChangeListener {
private static final String SYSTEM_PROPERTY_DISCOVERABLE_TIMEOUT =
"debug.bt.discoverable_time";
- static final int DISCOVERABLE_TIMEOUT_TWO_MINUTES = 120;
- static final int DISCOVERABLE_TIMEOUT_FIVE_MINUTES = 300;
- static final int DISCOVERABLE_TIMEOUT_ONE_HOUR = 3600;
+ private static final int DISCOVERABLE_TIMEOUT_TWO_MINUTES = 120;
+ private static final int DISCOVERABLE_TIMEOUT_FIVE_MINUTES = 300;
+ private static final int DISCOVERABLE_TIMEOUT_ONE_HOUR = 3600;
static final int DISCOVERABLE_TIMEOUT_NEVER = 0;
- static final String SHARED_PREFERENCES_KEY_DISCOVERABLE_END_TIMESTAMP =
- "discoverable_end_timestamp";
-
private static final String VALUE_DISCOVERABLE_TIMEOUT_TWO_MINUTES = "twomin";
private static final String VALUE_DISCOVERABLE_TIMEOUT_FIVE_MINUTES = "fivemin";
private static final String VALUE_DISCOVERABLE_TIMEOUT_ONE_HOUR = "onehour";
@@ -63,7 +56,7 @@ public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChan
private final CheckBoxPreference mCheckBoxPreference;
private final ListPreference mTimeoutListPreference;
- private final LocalBluetoothManager mLocalManager;
+ private final LocalBluetoothAdapter mLocalAdapter;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
@@ -84,7 +77,7 @@ public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChan
}
};
- public BluetoothDiscoverableEnabler(Context context,
+ BluetoothDiscoverableEnabler(Context context, LocalBluetoothAdapter adapter,
CheckBoxPreference checkBoxPreference, ListPreference timeoutListPreference) {
mContext = context;
mUiHandler = new Handler();
@@ -95,15 +88,15 @@ public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChan
// we actually want to persist this since can't infer from BT device state
mTimeoutListPreference.setPersistent(true);
- mLocalManager = LocalBluetoothManager.getInstance(context);
- if (mLocalManager == null) {
+ mLocalAdapter = adapter;
+ if (adapter == null) {
// Bluetooth not supported
checkBoxPreference.setEnabled(false);
}
}
public void resume() {
- if (mLocalManager == null) {
+ if (mLocalAdapter == null) {
return;
}
@@ -111,11 +104,11 @@ public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChan
mContext.registerReceiver(mReceiver, filter);
mCheckBoxPreference.setOnPreferenceChangeListener(this);
mTimeoutListPreference.setOnPreferenceChangeListener(this);
- handleModeChanged(mLocalManager.getBluetoothAdapter().getScanMode());
+ handleModeChanged(mLocalAdapter.getScanMode());
}
public void pause() {
- if (mLocalManager == null) {
+ if (mLocalAdapter == null) {
return;
}
@@ -137,43 +130,37 @@ public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChan
return true;
}
- private void setEnabled(final boolean enable) {
- BluetoothAdapter manager = mLocalManager.getBluetoothAdapter();
-
+ private void setEnabled(boolean enable) {
if (enable) {
int timeout = getDiscoverableTimeout();
- manager.setDiscoverableTimeout(timeout);
+ mLocalAdapter.setDiscoverableTimeout(timeout);
long endTimestamp = System.currentTimeMillis() + timeout * 1000L;
- persistDiscoverableEndTimestamp(endTimestamp);
+ LocalBluetoothPreferences.persistDiscoverableEndTimestamp(mContext, endTimestamp);
updateCountdownSummary();
- manager.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, timeout);
+ mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, timeout);
} else {
- manager.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
+ mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
}
}
private void updateTimerDisplay(int timeout) {
if (getDiscoverableTimeout() == DISCOVERABLE_TIMEOUT_NEVER) {
mCheckBoxPreference.setSummaryOn(
- mContext.getResources()
- .getString(R.string.bluetooth_is_discoverable_always));
+ mContext.getString(R.string.bluetooth_is_discoverable_always));
} else {
mCheckBoxPreference.setSummaryOn(
- mContext.getResources()
- .getString(R.string.bluetooth_is_discoverable, timeout));
+ mContext.getString(R.string.bluetooth_is_discoverable, timeout));
}
}
private int getDiscoverableTimeout() {
int timeout = SystemProperties.getInt(SYSTEM_PROPERTY_DISCOVERABLE_TIMEOUT, -1);
if (timeout < 0) {
- String timeoutValue = null;
- if (mTimeoutListPreference != null && mTimeoutListPreference.getValue() != null) {
- timeoutValue = mTimeoutListPreference.getValue().toString();
- } else {
+ String timeoutValue = mTimeoutListPreference.getValue();
+ if (timeoutValue == null) {
mTimeoutListPreference.setValue(VALUE_DISCOVERABLE_TIMEOUT_TWO_MINUTES);
return DISCOVERABLE_TIMEOUT_TWO_MINUTES;
}
@@ -192,12 +179,6 @@ public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChan
return timeout;
}
- private void persistDiscoverableEndTimestamp(long endTimestamp) {
- SharedPreferences.Editor editor = mLocalManager.getSharedPreferences().edit();
- editor.putLong(SHARED_PREFERENCES_KEY_DISCOVERABLE_END_TIMESTAMP, endTimestamp);
- editor.apply();
- }
-
private void handleModeChanged(int mode) {
if (mode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
mCheckBoxPreference.setChecked(true);
@@ -208,14 +189,13 @@ public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChan
}
private void updateCountdownSummary() {
- int mode = mLocalManager.getBluetoothAdapter().getScanMode();
+ int mode = mLocalAdapter.getScanMode();
if (mode != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
return;
}
long currentTimestamp = System.currentTimeMillis();
- long endTimestamp = mLocalManager.getSharedPreferences().getLong(
- SHARED_PREFERENCES_KEY_DISCOVERABLE_END_TIMESTAMP, 0);
+ long endTimestamp = LocalBluetoothPreferences.getDiscoverableEndTimestamp(mContext);
if (currentTimestamp > endTimestamp) {
// We're still in discoverable mode, but maybe there isn't a timeout.
@@ -231,6 +211,4 @@ public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChan
mUiHandler.postDelayed(mUpdateCountdownSummaryRunnable, 1000);
}
}
-
-
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDiscoveryReceiver.java b/src/com/android/settings/bluetooth/BluetoothDiscoveryReceiver.java
new file mode 100644
index 000000000..fbb682756
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BluetoothDiscoveryReceiver.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+/**
+ * BluetoothDiscoveryReceiver updates a timestamp when the
+ * Bluetooth adapter starts or finishes discovery mode. This
+ * is used to decide whether to open an alert dialog or
+ * create a notification when we receive a pairing request.
+ *
+ * <p>Note that the discovery start/finish intents are also handled
+ * by {@link BluetoothEventManager} to update the UI, if visible.
+ */
+public final class BluetoothDiscoveryReceiver extends BroadcastReceiver {
+ private static final String TAG = "BluetoothDiscoveryReceiver";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.v(TAG, "Received: " + action);
+
+ if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED) ||
+ action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
+ LocalBluetoothPreferences.persistDiscoveringTimestamp(context);
+ }
+ }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothEnabler.java b/src/com/android/settings/bluetooth/BluetoothEnabler.java
index a7b9d713e..9aeb1b939 100644
--- a/src/com/android/settings/bluetooth/BluetoothEnabler.java
+++ b/src/com/android/settings/bluetooth/BluetoothEnabler.java
@@ -34,13 +34,14 @@ import android.widget.Toast;
* preference. It turns on/off Bluetooth and ensures the summary of the
* preference reflects the current state.
*/
-public class BluetoothEnabler implements Preference.OnPreferenceChangeListener {
+public final class BluetoothEnabler implements Preference.OnPreferenceChangeListener {
private final Context mContext;
private final CheckBoxPreference mCheckBox;
private final CharSequence mOriginalSummary;
- private final LocalBluetoothManager mLocalManager;
+ private final LocalBluetoothAdapter mLocalAdapter;
private final IntentFilter mIntentFilter;
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -49,14 +50,15 @@ public class BluetoothEnabler implements Preference.OnPreferenceChangeListener {
}
};
- public BluetoothEnabler(Context context, CheckBoxPreference checkBox) {
+ public BluetoothEnabler(Context context, LocalBluetoothAdapter adapter,
+ CheckBoxPreference checkBox) {
mContext = context;
mCheckBox = checkBox;
mOriginalSummary = checkBox.getSummary();
checkBox.setPersistent(false);
- mLocalManager = LocalBluetoothManager.getInstance(context);
- if (mLocalManager == null) {
+ mLocalAdapter = adapter;
+ if (adapter == null) {
// Bluetooth is not supported
checkBox.setEnabled(false);
}
@@ -64,19 +66,19 @@ public class BluetoothEnabler implements Preference.OnPreferenceChangeListener {
}
public void resume() {
- if (mLocalManager == null) {
+ if (mLocalAdapter == null) {
return;
}
// Bluetooth state is not sticky, so set it manually
- handleStateChanged(mLocalManager.getBluetoothState());
+ handleStateChanged(mLocalAdapter.getBluetoothState());
mContext.registerReceiver(mReceiver, mIntentFilter);
mCheckBox.setOnPreferenceChangeListener(this);
}
public void pause() {
- if (mLocalManager == null) {
+ if (mLocalAdapter == null) {
return;
}
@@ -95,14 +97,14 @@ public class BluetoothEnabler implements Preference.OnPreferenceChangeListener {
return false;
}
- mLocalManager.setBluetoothEnabled(enable);
+ mLocalAdapter.setBluetoothEnabled(enable);
mCheckBox.setEnabled(false);
// Don't update UI to opposite state until we're sure
return false;
}
- /* package */ void handleStateChanged(int state) {
+ void handleStateChanged(int state) {
switch (state) {
case BluetoothAdapter.STATE_TURNING_ON:
mCheckBox.setSummary(R.string.wifi_starting);
diff --git a/src/com/android/settings/bluetooth/BluetoothEventManager.java b/src/com/android/settings/bluetooth/BluetoothEventManager.java
new file mode 100644
index 000000000..70e35f984
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BluetoothEventManager.java
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import com.android.settings.R;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * BluetoothEventManager receives broadcasts and callbacks from the Bluetooth
+ * API and dispatches the event on the UI thread to the right class in the
+ * Settings.
+ */
+final class BluetoothEventManager {
+ private static final String TAG = "BluetoothEventManager";
+
+ private final LocalBluetoothAdapter mLocalAdapter;
+ private final CachedBluetoothDeviceManager mDeviceManager;
+ private LocalBluetoothProfileManager mProfileManager;
+ private final IntentFilter mIntentFilter;
+ private final Map<String, Handler> mHandlerMap;
+
+ private final Collection<BluetoothCallback> mCallbacks =
+ new ArrayList<BluetoothCallback>();
+
+ interface Handler {
+ void onReceive(Context context, Intent intent, BluetoothDevice device);
+ }
+
+ void addHandler(String action, Handler handler) {
+ mHandlerMap.put(action, handler);
+ mIntentFilter.addAction(action);
+ }
+
+ // Set profile manager after construction due to circular dependency
+ void setProfileManager(LocalBluetoothProfileManager manager) {
+ mProfileManager = manager;
+ }
+
+ BluetoothEventManager(LocalBluetoothAdapter adapter,
+ CachedBluetoothDeviceManager deviceManager) {
+ mLocalAdapter = adapter;
+ mDeviceManager = deviceManager;
+ mIntentFilter = new IntentFilter();
+ mHandlerMap = new HashMap<String, Handler>();
+
+ // Bluetooth on/off broadcasts
+ addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler());
+
+ // Discovery broadcasts
+ addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));
+ addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));
+ addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
+ addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler());
+ addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());
+
+ // Pairing broadcasts
+ addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());
+ addHandler(BluetoothDevice.ACTION_PAIRING_CANCEL, new PairingCancelHandler());
+
+ // Fine-grained state broadcasts
+ addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());
+ addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());
+
+ // Dock event broadcasts
+ addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());
+ }
+
+ /**
+ * A Bluetooth-related activity is now in the foreground. Register to
+ * start receiving Bluetooth events.
+ * @param context a Context object for the current Activity
+ */
+ void resume(Context context) {
+ if (mLocalAdapter.syncBluetoothState()) {
+ // adapter state changed while we were paused: send callbacks
+ int newState = mLocalAdapter.getState();
+ synchronized (mCallbacks) {
+ for (BluetoothCallback callback : mCallbacks) {
+ callback.onBluetoothStateChanged(newState);
+ }
+ }
+ }
+ context.registerReceiver(mBroadcastReceiver, mIntentFilter);
+ }
+
+ void pause(Context context) {
+ context.unregisterReceiver(mBroadcastReceiver);
+ }
+
+ /** Register to start receiving callbacks for Bluetooth events. */
+ void registerCallback(BluetoothCallback callback) {
+ synchronized (mCallbacks) {
+ mCallbacks.add(callback);
+ }
+ }
+
+ /** Unregister to stop receiving callbacks for Bluetooth events. */
+ void unregisterCallback(BluetoothCallback callback) {
+ synchronized (mCallbacks) {
+ mCallbacks.remove(callback);
+ }
+ }
+
+ // This can't be called from a broadcast receiver where the filter is set in the Manifest.
+ private static String getDockedDeviceAddress(Context context) {
+ // This works only because these broadcast intents are "sticky"
+ Intent i = context.registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT));
+ if (i != null) {
+ int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED);
+ if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+ BluetoothDevice device = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ if (device != null) {
+ return device.getAddress();
+ }
+ }
+ }
+ return null;
+ }
+
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.v(TAG, "Received " + intent.getAction());
+
+ String action = intent.getAction();
+ BluetoothDevice device = intent
+ .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+
+ Handler handler = mHandlerMap.get(action);
+ if (handler != null) {
+ handler.onReceive(context, intent, device);
+ }
+ }
+ };
+
+ private class AdapterStateChangedHandler implements Handler {
+ public void onReceive(Context context, Intent intent,
+ BluetoothDevice device) {
+ int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+ BluetoothAdapter.ERROR);
+ // update local profiles and get paired devices
+ mLocalAdapter.setBluetoothStateInt(state);
+ // send callback to update UI and possibly start scanning
+ synchronized (mCallbacks) {
+ for (BluetoothCallback callback : mCallbacks) {
+ callback.onBluetoothStateChanged(state);
+ }
+ }
+ }
+ }
+
+ private class ScanningStateChangedHandler implements Handler {
+ private final boolean mStarted;
+
+ ScanningStateChangedHandler(boolean started) {
+ mStarted = started;
+ }
+ public void onReceive(Context context, Intent intent,
+ BluetoothDevice device) {
+ synchronized (mCallbacks) {
+ for (BluetoothCallback callback : mCallbacks) {
+ callback.onScanningStateChanged(mStarted);
+ }
+ }
+ mDeviceManager.onScanningStateChanged(mStarted);
+ LocalBluetoothPreferences.persistDiscoveringTimestamp(context);
+ }
+ }
+
+ private class DeviceFoundHandler implements Handler {
+ public void onReceive(Context context, Intent intent,
+ BluetoothDevice device) {
+ short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
+ BluetoothClass btClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
+ String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
+ // TODO Pick up UUID. They should be available for 2.1 devices.
+ // Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
+ CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+ if (cachedDevice == null) {
+ cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
+ Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "
+ + cachedDevice);
+ // callback to UI to create Preference for new device
+ dispatchDeviceAdded(cachedDevice);
+ }
+ cachedDevice.setRssi(rssi);
+ cachedDevice.setBtClass(btClass);
+ cachedDevice.setName(name);
+ cachedDevice.setVisible(true);
+ }
+ }
+
+ private void dispatchDeviceAdded(CachedBluetoothDevice cachedDevice) {
+ synchronized (mCallbacks) {
+ for (BluetoothCallback callback : mCallbacks) {
+ callback.onDeviceAdded(cachedDevice);
+ }
+ }
+ }
+
+ private class DeviceDisappearedHandler implements Handler {
+ public void onReceive(Context context, Intent intent,
+ BluetoothDevice device) {
+ CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+ if (cachedDevice == null) {
+ Log.w(TAG, "received ACTION_DISAPPEARED for an unknown device: " + device);
+ return;
+ }
+ if (mDeviceManager.onDeviceDisappeared(cachedDevice)) {
+ synchronized (mCallbacks) {
+ for (BluetoothCallback callback : mCallbacks) {
+ callback.onDeviceDeleted(cachedDevice);
+ }
+ }
+ }
+ }
+ }
+
+ private class NameChangedHandler implements Handler {
+ public void onReceive(Context context, Intent intent,
+ BluetoothDevice device) {
+ mDeviceManager.onDeviceNameUpdated(device);
+ }
+ }
+
+ private class BondStateChangedHandler implements Handler {
+ public void onReceive(Context context, Intent intent,
+ BluetoothDevice device) {
+ if (device == null) {
+ Log.e(TAG, "ACTION_BOND_STATE_CHANGED with no EXTRA_DEVICE");
+ return;
+ }
+ int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
+ BluetoothDevice.ERROR);
+ CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+ if (cachedDevice == null) {
+ Log.w(TAG, "CachedBluetoothDevice for device " + device +
+ " not found, calling readPairedDevices().");
+ if (!readPairedDevices()) {
+ Log.e(TAG, "Got bonding state changed for " + device +
+ ", but we have no record of that device.");
+ return;
+ }
+ cachedDevice = mDeviceManager.findDevice(device);
+ if (cachedDevice == null) {
+ Log.e(TAG, "Got bonding state changed for " + device +
+ ", but device not added in cache.");
+ return;
+ }
+ }
+
+ synchronized (mCallbacks) {
+ for (BluetoothCallback callback : mCallbacks) {
+ callback.onDeviceBondStateChanged(cachedDevice, bondState);
+ }
+ }
+ cachedDevice.onBondingStateChanged(bondState);
+
+ if (bondState == BluetoothDevice.BOND_NONE) {
+ if (device.isBluetoothDock()) {
+ // After a dock is unpaired, we will forget the settings
+ LocalBluetoothPreferences
+ .removeDockAutoConnectSetting(context, device.getAddress());
+
+ // if the device is undocked, remove it from the list as well
+ if (!device.getAddress().equals(getDockedDeviceAddress(context))) {
+ mDeviceManager.onDeviceDisappeared(cachedDevice);
+ }
+ }
+ int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
+ BluetoothDevice.ERROR);
+
+ showUnbondMessage(context, cachedDevice.getName(), reason);
+ }
+ }
+
+ /**
+ * Called when we have reached the unbonded state.
+ *
+ * @param reason one of the error reasons from
+ * BluetoothDevice.UNBOND_REASON_*
+ */
+ private void showUnbondMessage(Context context, String name, int reason) {
+ int errorMsg;
+
+ switch(reason) {
+ case BluetoothDevice.UNBOND_REASON_AUTH_FAILED:
+ errorMsg = R.string.bluetooth_pairing_pin_error_message;
+ break;
+ case BluetoothDevice.UNBOND_REASON_AUTH_REJECTED:
+ errorMsg = R.string.bluetooth_pairing_rejected_error_message;
+ break;
+ case BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN:
+ errorMsg = R.string.bluetooth_pairing_device_down_error_message;
+ break;
+ case BluetoothDevice.UNBOND_REASON_DISCOVERY_IN_PROGRESS:
+ case BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT:
+ case BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS:
+ case BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED:
+ errorMsg = R.string.bluetooth_pairing_error_message;
+ break;
+ default:
+ Log.w(TAG, "showUnbondMessage: Not displaying any message for reason: " + reason);
+ return;
+ }
+ Utils.showError(context, name, errorMsg);
+ }
+ }
+
+ private class ClassChangedHandler implements Handler {
+ public void onReceive(Context context, Intent intent,
+ BluetoothDevice device) {
+ mDeviceManager.onBtClassChanged(device);
+ }
+ }
+
+ private class UuidChangedHandler implements Handler {
+ public void onReceive(Context context, Intent intent,
+ BluetoothDevice device) {
+ mDeviceManager.onUuidChanged(device);
+ }
+ }
+
+ private class PairingCancelHandler implements Handler {
+ public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+ if (device == null) {
+ Log.e(TAG, "ACTION_PAIRING_CANCEL with no EXTRA_DEVICE");
+ return;
+ }
+ int errorMsg = R.string.bluetooth_pairing_error_message;
+ CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+ Utils.showError(context, cachedDevice.getName(), errorMsg);
+ }
+ }
+
+ private class DockEventHandler implements Handler {
+ public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+ // Remove if unpair device upon undocking
+ int anythingButUnDocked = Intent.EXTRA_DOCK_STATE_UNDOCKED + 1;
+ int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, anythingButUnDocked);
+ if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+ if (device != null && device.getBondState() == BluetoothDevice.BOND_NONE) {
+ CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+ if (cachedDevice != null) {
+ mDeviceManager.onDeviceDisappeared(cachedDevice);
+ }
+ }
+ }
+ }
+ }
+
+ boolean readPairedDevices() {
+ Set<BluetoothDevice> bondedDevices = mLocalAdapter.getBondedDevices();
+ if (bondedDevices == null) {
+ return false;
+ }
+
+ boolean deviceAdded = false;
+ for (BluetoothDevice device : bondedDevices) {
+ CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+ if (cachedDevice == null) {
+ cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
+ dispatchDeviceAdded(cachedDevice);
+ deviceAdded = true;
+ }
+ }
+
+ return deviceAdded;
+ }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothEventRedirector.java b/src/com/android/settings/bluetooth/BluetoothEventRedirector.java
deleted file mode 100644
index 31747504c..000000000
--- a/src/com/android/settings/bluetooth/BluetoothEventRedirector.java
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.bluetooth;
-
-import com.android.settings.R;
-import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
-
-import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothClass;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothInputDevice;
-import android.bluetooth.BluetoothPan;
-import android.bluetooth.BluetoothProfile;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.os.Handler;
-import android.util.Log;
-
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-/**
- * BluetoothEventRedirector receives broadcasts and callbacks from the Bluetooth
- * API and dispatches the event on the UI thread to the right class in the
- * Settings.
- */
-class BluetoothEventRedirector {
- private static final String TAG = "BluetoothEventRedirector";
-
- /* package */ final LocalBluetoothManager mManager;
-
- private final ThreadPoolExecutor mSerialExecutor = new ThreadPoolExecutor(
- 0, 1, 1000L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
-
- private final Handler mHandler = new Handler();
-
- private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.v(TAG, "Received " + intent.getAction());
-
- String action = intent.getAction();
- BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-
- if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
- int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
- BluetoothAdapter.ERROR);
- mManager.setBluetoothStateInt(state);
- } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED)) {
- PendingResult pr = goAsync(); // so loading shared prefs doesn't kill animation
- persistDiscoveringTimestamp(pr, true);
- } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
- PendingResult pr = goAsync(); // so loading shared prefs doesn't kill animation
- persistDiscoveringTimestamp(pr, false);
- } else if (action.equals(BluetoothDevice.ACTION_FOUND)) {
- short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
- BluetoothClass btClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
- String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
- // TODO Pick up UUID. They should be available for 2.1 devices.
- // Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
- mManager.getCachedDeviceManager().onDeviceAppeared(device, rssi, btClass, name);
-
- } else if (action.equals(BluetoothDevice.ACTION_DISAPPEARED)) {
- mManager.getCachedDeviceManager().onDeviceDisappeared(device);
-
- } else if (action.equals(BluetoothDevice.ACTION_NAME_CHANGED)) {
- mManager.getCachedDeviceManager().onDeviceNameUpdated(device);
-
- } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
- int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
- BluetoothDevice.ERROR);
- CachedBluetoothDeviceManager cachedDeviceMgr = mManager.getCachedDeviceManager();
- cachedDeviceMgr.onBondingStateChanged(device, bondState);
- if (bondState == BluetoothDevice.BOND_NONE) {
- if (device.isBluetoothDock()) {
- // After a dock is unpaired, we will forget the
- // settings
- mManager.removeDockAutoConnectSetting(device.getAddress());
-
- // if the device is undocked, remove it from the list as
- // well
- if (!device.getAddress().equals(getDockedDeviceAddress(context))) {
- cachedDeviceMgr.onDeviceDisappeared(device);
- }
- }
- int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
- BluetoothDevice.ERROR);
- cachedDeviceMgr.showUnbondMessage(device, reason);
- }
-
- } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
- int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
- int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
- if (newState == BluetoothProfile.STATE_DISCONNECTED &&
- oldState == BluetoothProfile.STATE_CONNECTING) {
- Log.i(TAG, "Failed to connect BT headset");
- }
-
- mManager.getCachedDeviceManager().onProfileStateChanged(device,
- Profile.HEADSET, newState);
- } else if (action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
- int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
- int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
- if (newState == BluetoothProfile.STATE_DISCONNECTED &&
- oldState == BluetoothProfile.STATE_CONNECTING) {
- Log.i(TAG, "Failed to connect BT A2DP");
- }
-
- mManager.getCachedDeviceManager().onProfileStateChanged(device,
- Profile.A2DP, newState);
- } else if (action.equals(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED)) {
- final int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
- final int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
- if (newState == BluetoothProfile.STATE_DISCONNECTED &&
- oldState == BluetoothProfile.STATE_CONNECTING) {
- Log.i(TAG, "Failed to connect BT HID");
- }
-
- mManager.getCachedDeviceManager().onProfileStateChanged(device,
- Profile.HID, newState);
-
- } else if (action.equals(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED)) {
- final int role = intent.getIntExtra(
- BluetoothPan.EXTRA_LOCAL_ROLE, 0);
- if (role == BluetoothPan.LOCAL_PANU_ROLE) {
- final int newState = intent.getIntExtra(
- BluetoothPan.EXTRA_STATE, 0);
- final int oldState = intent.getIntExtra(
- BluetoothPan.EXTRA_PREVIOUS_STATE, 0);
- if (newState == BluetoothPan.STATE_DISCONNECTED &&
- oldState == BluetoothPan.STATE_CONNECTING) {
- Log.i(TAG, "Failed to connect BT PAN");
- }
- mManager.getCachedDeviceManager().onProfileStateChanged(device,
- Profile.PAN, newState);
- }
- } else if (action.equals(BluetoothDevice.ACTION_CLASS_CHANGED)) {
- mManager.getCachedDeviceManager().onBtClassChanged(device);
-
- } else if (action.equals(BluetoothDevice.ACTION_UUID)) {
- mManager.getCachedDeviceManager().onUuidChanged(device);
-
- } else if (action.equals(BluetoothDevice.ACTION_PAIRING_CANCEL)) {
- int errorMsg = R.string.bluetooth_pairing_error_message;
- mManager.showError(device, errorMsg);
-
- } else if (action.equals(Intent.ACTION_DOCK_EVENT)) {
- // Remove if unpair device upon undocking
- int anythingButUnDocked = Intent.EXTRA_DOCK_STATE_UNDOCKED + 1;
- int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, anythingButUnDocked);
- if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
- if (device != null && device.getBondState() == BluetoothDevice.BOND_NONE) {
- mManager.getCachedDeviceManager().onDeviceDisappeared(device);
- }
- }
- }
- }
- };
-
- public BluetoothEventRedirector(LocalBluetoothManager localBluetoothManager) {
- mManager = localBluetoothManager;
- }
-
- public void registerReceiver() {
- IntentFilter filter = new IntentFilter();
-
- // Bluetooth on/off broadcasts
- filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
-
- // Discovery broadcasts
- filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
- filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
- filter.addAction(BluetoothDevice.ACTION_DISAPPEARED);
- filter.addAction(BluetoothDevice.ACTION_FOUND);
- filter.addAction(BluetoothDevice.ACTION_NAME_CHANGED);
-
- // Pairing broadcasts
- filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
- filter.addAction(BluetoothDevice.ACTION_PAIRING_CANCEL);
-
- // Fine-grained state broadcasts
- filter.addAction(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
- filter.addAction(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
- filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
- filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
- filter.addAction(BluetoothDevice.ACTION_CLASS_CHANGED);
- filter.addAction(BluetoothDevice.ACTION_UUID);
-
- // Dock event broadcasts
- filter.addAction(Intent.ACTION_DOCK_EVENT);
-
- mManager.getContext().registerReceiver(mBroadcastReceiver, filter);
- }
-
- public void stop() {
- mManager.getContext().unregisterReceiver(mBroadcastReceiver);
- }
-
- // This can't be called from a broadcast receiver where the filter is set in the Manifest.
- /* package */ String getDockedDeviceAddress(Context context) {
- // This works only because these broadcast intents are "sticky"
- Intent i = context.registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT));
- if (i != null) {
- int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED);
- if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
- BluetoothDevice device = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- if (device != null) {
- return device.getAddress();
- }
- }
- }
- return null;
- }
-
- /* package */ void persistDiscoveringTimestamp(
- final BroadcastReceiver.PendingResult pr, final boolean newState) {
- // Load the shared preferences and edit it on a background
- // thread (but serialized!), but then post back to the main
- // thread to run the onScanningStateChanged callbacks which
- // update the UI...
- mSerialExecutor.submit(new Runnable() {
- public void run() {
- SharedPreferences.Editor editor = mManager.getSharedPreferences().edit();
- editor.putLong(
- LocalBluetoothManager.SHARED_PREFERENCES_KEY_DISCOVERING_TIMESTAMP,
- System.currentTimeMillis());
- editor.apply();
- mHandler.post(new Runnable() {
- public void run() {
- mManager.onScanningStateChanged(newState);
- pr.finish();
- }
- });
- }
- });
- }
-}
diff --git a/src/com/android/settings/bluetooth/BluetoothFindNearby.java b/src/com/android/settings/bluetooth/BluetoothFindNearby.java
index f1b876e76..066f4f611 100644
--- a/src/com/android/settings/bluetooth/BluetoothFindNearby.java
+++ b/src/com/android/settings/bluetooth/BluetoothFindNearby.java
@@ -16,21 +16,18 @@
package com.android.settings.bluetooth;
-import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.util.Log;
import com.android.settings.R;
/**
* Fragment to scan and show the discoverable devices.
*/
-public class BluetoothFindNearby extends DeviceListPreferenceFragment {
+public final class BluetoothFindNearby extends DeviceListPreferenceFragment {
- private static final String TAG = "BluetoothFindNearby";
-
- void addPreferencesForActivity(Activity activity) {
+ @Override
+ void addPreferencesForActivity() {
addPreferencesFromResource(R.xml.device_picker);
}
@@ -38,35 +35,37 @@ public class BluetoothFindNearby extends DeviceListPreferenceFragment {
public void onResume() {
super.onResume();
if (mSelectedDevice != null) {
- CachedBluetoothDevice device =
- mLocalManager.getCachedDeviceManager().findDevice(mSelectedDevice);
- if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
+ CachedBluetoothDeviceManager manager = mLocalManager.getCachedDeviceManager();
+ CachedBluetoothDevice device = manager.findDevice(mSelectedDevice);
+ if (device != null && device.getBondState() == BluetoothDevice.BOND_BONDED) {
// selected device was paired, so return from this screen
finish();
return;
}
}
- mLocalManager.startScanning(true);
+ mLocalAdapter.startScanning(true);
}
+ @Override
void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
- mLocalManager.stopScanning();
+ mLocalAdapter.stopScanning();
super.onDevicePreferenceClick(btPreference);
}
- public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice,
- int bondState) {
+ public void onDeviceBondStateChanged(CachedBluetoothDevice
+ cachedDevice, int bondState) {
if (bondState == BluetoothDevice.BOND_BONDED) {
// return from scan screen after successful auto-pairing
finish();
}
}
- void onBluetoothStateChanged(int bluetoothState) {
+ @Override
+ public void onBluetoothStateChanged(int bluetoothState) {
super.onBluetoothStateChanged(bluetoothState);
if (bluetoothState == BluetoothAdapter.STATE_ON) {
- mLocalManager.startScanning(false);
+ mLocalAdapter.startScanning(false);
}
}
}
diff --git a/src/com/android/settings/bluetooth/BluetoothNamePreference.java b/src/com/android/settings/bluetooth/BluetoothNamePreference.java
index c99ab4c99..f41689ef7 100644
--- a/src/com/android/settings/bluetooth/BluetoothNamePreference.java
+++ b/src/com/android/settings/bluetooth/BluetoothNamePreference.java
@@ -22,12 +22,12 @@ import android.app.Dialog;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.preference.EditTextPreference;
import android.text.Editable;
import android.text.InputFilter;
-import android.text.Spanned;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.widget.Button;
@@ -38,13 +38,13 @@ import android.widget.EditText;
* Bluetooth name. It asks the user for a name, and persists it via the
* Bluetooth API.
*/
-public class BluetoothNamePreference extends EditTextPreference implements TextWatcher {
- private static final String TAG = "BluetoothNamePreference";
+public final class BluetoothNamePreference extends EditTextPreference implements TextWatcher {
+// private static final String TAG = "BluetoothNamePreference";
private static final int BLUETOOTH_NAME_MAX_LENGTH_BYTES = 248;
- private LocalBluetoothManager mLocalManager;
+ private final LocalBluetoothAdapter mLocalAdapter;
- private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -61,7 +61,7 @@ public class BluetoothNamePreference extends EditTextPreference implements TextW
public BluetoothNamePreference(Context context, AttributeSet attrs) {
super(context, attrs);
- mLocalManager = LocalBluetoothManager.getInstance(context);
+ mLocalAdapter = LocalBluetoothManager.getInstance(context).getBluetoothAdapter();
setSummaryToName();
}
@@ -97,16 +97,17 @@ public class BluetoothNamePreference extends EditTextPreference implements TextW
}
private void setSummaryToName() {
- BluetoothAdapter adapter = mLocalManager.getBluetoothAdapter();
- if (adapter.isEnabled()) {
- setSummary(adapter.getName());
+ if (mLocalAdapter != null && mLocalAdapter.isEnabled()) {
+ setSummary(mLocalAdapter.getName());
}
}
@Override
protected boolean persistString(String value) {
- BluetoothAdapter adapter = mLocalManager.getBluetoothAdapter();
- adapter.setName(value);
+ // Persist with Bluez instead of shared preferences
+ if (mLocalAdapter != null) {
+ mLocalAdapter.setName(value);
+ }
return true;
}
@@ -116,8 +117,8 @@ public class BluetoothNamePreference extends EditTextPreference implements TextW
// The dialog should be created by now
EditText et = getEditText();
- if (et != null) {
- et.setText(mLocalManager.getBluetoothAdapter().getName());
+ if (et != null && mLocalAdapter != null) {
+ et.setText(mLocalAdapter.getName());
}
}
@@ -125,7 +126,7 @@ public class BluetoothNamePreference extends EditTextPreference implements TextW
public void afterTextChanged(Editable s) {
Dialog d = getDialog();
if (d instanceof AlertDialog) {
- ((AlertDialog) d).getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(s.length() > 0);
+ ((AlertDialog) d).getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(s.length() > 0);
}
}
@@ -139,67 +140,4 @@ public class BluetoothNamePreference extends EditTextPreference implements TextW
// not used
}
- /**
- * This filter will constrain edits so that the text length is not
- * greater than the specified number of bytes using UTF-8 encoding.
- * <p>The JNI method used by {@link android.server.BluetoothService}
- * to convert UTF-16 to UTF-8 doesn't support surrogate pairs,
- * therefore code points outside of the basic multilingual plane
- * (0000-FFFF) will be encoded as a pair of 3-byte UTF-8 characters,
- * rather than a single 4-byte UTF-8 encoding. Dalvik implements this
- * conversion in {@code convertUtf16ToUtf8()} in
- * {@code dalvik/vm/UtfString.c}.
- * <p>This JNI method is unlikely to change in the future due to
- * backwards compatibility requirements. It's also unclear whether
- * the installed base of Bluetooth devices would correctly handle the
- * encoding of surrogate pairs in UTF-8 as 4 bytes rather than 6.
- * However, this filter will still work in scenarios where surrogate
- * pairs are encoded as 4 bytes, with the caveat that the maximum
- * length will be constrained more conservatively than necessary.
- */
- public static class Utf8ByteLengthFilter implements InputFilter {
- private int mMaxBytes;
-
- public Utf8ByteLengthFilter(int maxBytes) {
- mMaxBytes = maxBytes;
- }
-
- public CharSequence filter(CharSequence source, int start, int end,
- Spanned dest, int dstart, int dend) {
- int srcByteCount = 0;
- // count UTF-8 bytes in source substring
- for (int i = start; i < end; i++) {
- char c = source.charAt(i);
- srcByteCount += (c < 0x0080) ? 1 : (c < 0x0800 ? 2 : 3);
- }
- int destLen = dest.length();
- int destByteCount = 0;
- // count UTF-8 bytes in destination excluding replaced section
- for (int i = 0; i < destLen; i++) {
- if (i < dstart || i >= dend) {
- char c = dest.charAt(i);
- destByteCount += (c < 0x0080) ? 1 : (c < 0x0800 ? 2 : 3);
- }
- }
- int keepBytes = mMaxBytes - destByteCount;
- if (keepBytes <= 0) {
- return "";
- } else if (keepBytes >= srcByteCount) {
- return null; // use original dest string
- } else {
- // find end position of largest sequence that fits in keepBytes
- for (int i = start; i < end; i++) {
- char c = source.charAt(i);
- keepBytes -= (c < 0x0080) ? 1 : (c < 0x0800 ? 2 : 3);
- if (keepBytes < 0) {
- return source.subSequence(start, i);
- }
- }
- // If the entire substring fits, we should have returned null
- // above, so this line should not be reached. If for some
- // reason it is, return null to use the original dest string.
- return null;
- }
- }
- }
}
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDialog.java b/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
index 1822e73f8..1b443c497 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
@@ -42,33 +42,37 @@ import com.android.settings.R;
* BluetoothPairingDialog asks the user to enter a PIN / Passkey / simple confirmation
* for pairing with a remote Bluetooth device. It is an activity that appears as a dialog.
*/
-public class BluetoothPairingDialog extends AlertActivity implements DialogInterface.OnClickListener,
+public final class BluetoothPairingDialog extends AlertActivity implements DialogInterface.OnClickListener,
TextWatcher {
private static final String TAG = "BluetoothPairingDialog";
private static final int BLUETOOTH_PIN_MAX_LENGTH = 16;
private static final int BLUETOOTH_PASSKEY_MAX_LENGTH = 6;
- private LocalBluetoothManager mLocalManager;
private BluetoothDevice mDevice;
private int mType;
private String mPairingKey;
private EditText mPairingView;
private Button mOkButton;
- private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ /**
+ * Dismiss the dialog if the bond state changes to bonded or none,
+ * or if pairing was canceled for {@link #mDevice}.
+ */
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) {
+ String action = intent.getAction();
+ if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
BluetoothDevice.ERROR);
if (bondState == BluetoothDevice.BOND_BONDED ||
bondState == BluetoothDevice.BOND_NONE) {
- dismissDialog();
+ dismiss();
}
- } else if(BluetoothDevice.ACTION_PAIRING_CANCEL.equals(intent.getAction())) {
+ } else if (BluetoothDevice.ACTION_PAIRING_CANCEL.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device == null || device.equals(mDevice)) {
- dismissDialog();
+ dismiss();
}
}
}
@@ -81,48 +85,63 @@ public class BluetoothPairingDialog extends AlertActivity implements DialogInter
Intent intent = getIntent();
if (!intent.getAction().equals(BluetoothDevice.ACTION_PAIRING_REQUEST))
{
- Log.e(TAG,
- "Error: this activity may be started only with intent " +
+ Log.e(TAG, "Error: this activity may be started only with intent " +
BluetoothDevice.ACTION_PAIRING_REQUEST);
finish();
+ return;
}
- mLocalManager = LocalBluetoothManager.getInstance(this);
+ LocalBluetoothManager manager = LocalBluetoothManager.getInstance(this);
+ if (manager == null) {
+ Log.e(TAG, "Error: BluetoothAdapter not supported by system");
+ finish();
+ return;
+ }
+ CachedBluetoothDeviceManager deviceManager = manager.getCachedDeviceManager();
+
mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
mType = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR);
- if (mType == BluetoothDevice.PAIRING_VARIANT_PIN) {
- createUserEntryDialog();
- } else if (mType == BluetoothDevice.PAIRING_VARIANT_PASSKEY) {
- createUserEntryDialog();
- } else if (mType == BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION){
- int passkey =
- intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, BluetoothDevice.ERROR);
- if (passkey == BluetoothDevice.ERROR) {
- Log.e(TAG, "Invalid ConfirmationPasskey received, not showing any dialog");
- return;
- }
- mPairingKey = String.format("%06d", passkey);
- createConfirmationDialog();
- } else if (mType == BluetoothDevice.PAIRING_VARIANT_CONSENT) {
- createConsentDialog();
- } else if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY ||
- mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN) {
- int pairingKey =
- intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, BluetoothDevice.ERROR);
- if (pairingKey == BluetoothDevice.ERROR) {
- Log.e(TAG, "Invalid Confirmation Passkey or PIN received, not showing any dialog");
- return;
- }
- if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY) {
- mPairingKey = String.format("%06d", pairingKey);
- } else {
- mPairingKey = String.format("%04d", pairingKey);
- }
- createDisplayPasskeyOrPinDialog();
- } else if (mType == BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT) {
- createConsentDialog();
- } else {
- Log.e(TAG, "Incorrect pairing type received, not showing any dialog");
+
+ switch (mType) {
+ case BluetoothDevice.PAIRING_VARIANT_PIN:
+ case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
+ createUserEntryDialog(deviceManager);
+ break;
+
+ case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
+ int passkey =
+ intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, BluetoothDevice.ERROR);
+ if (passkey == BluetoothDevice.ERROR) {
+ Log.e(TAG, "Invalid Confirmation Passkey received, not showing any dialog");
+ return;
+ }
+ mPairingKey = String.format("%06d", passkey);
+ createConfirmationDialog(deviceManager);
+ break;
+
+ case BluetoothDevice.PAIRING_VARIANT_CONSENT:
+ case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
+ createConsentDialog(deviceManager);
+ break;
+
+ case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY:
+ case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN:
+ int pairingKey =
+ intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, BluetoothDevice.ERROR);
+ if (pairingKey == BluetoothDevice.ERROR) {
+ Log.e(TAG, "Invalid Confirmation Passkey or PIN received, not showing any dialog");
+ return;
+ }
+ if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY) {
+ mPairingKey = String.format("%06d", pairingKey);
+ } else {
+ mPairingKey = String.format("%04d", pairingKey);
+ }
+ createDisplayPasskeyOrPinDialog(deviceManager);
+ break;
+
+ default:
+ Log.e(TAG, "Incorrect pairing type received, not showing any dialog");
}
/*
@@ -133,67 +152,79 @@ public class BluetoothPairingDialog extends AlertActivity implements DialogInter
registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED));
}
- private void createUserEntryDialog() {
+ private void createUserEntryDialog(CachedBluetoothDeviceManager deviceManager) {
final AlertController.AlertParams p = mAlertParams;
p.mIconId = android.R.drawable.ic_dialog_info;
p.mTitle = getString(R.string.bluetooth_pairing_request);
- p.mView = createView();
+ p.mView = createView(deviceManager);
p.mPositiveButtonText = getString(android.R.string.ok);
p.mPositiveButtonListener = this;
p.mNegativeButtonText = getString(android.R.string.cancel);
p.mNegativeButtonListener = this;
setupAlert();
- mOkButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
+ mOkButton = mAlert.getButton(BUTTON_POSITIVE);
mOkButton.setEnabled(false);
}
- private View createView() {
+ private View createView(CachedBluetoothDeviceManager deviceManager) {
View view = getLayoutInflater().inflate(R.layout.bluetooth_pin_entry, null);
-
- String name = mLocalManager.getCachedDeviceManager().getName(mDevice);
+ String name = deviceManager.getName(mDevice);
TextView messageView = (TextView) view.findViewById(R.id.message);
mPairingView = (EditText) view.findViewById(R.id.text);
mPairingView.addTextChangedListener(this);
- if (mType == BluetoothDevice.PAIRING_VARIANT_PIN) {
- messageView.setText(getString(R.string.bluetooth_enter_pin_msg, name));
- // Maximum of 16 characters in a PIN adb sync
- mPairingView.setFilters(new InputFilter[] {
- new LengthFilter(BLUETOOTH_PIN_MAX_LENGTH) });
- } else if (mType == BluetoothDevice.PAIRING_VARIANT_PASSKEY){
- messageView.setText(getString(R.string.bluetooth_enter_passkey_msg, name));
- // Maximum of 6 digits for passkey
- mPairingView.setInputType(InputType.TYPE_CLASS_NUMBER |
- InputType.TYPE_NUMBER_FLAG_SIGNED);
- mPairingView.setFilters(new InputFilter[] {
- new LengthFilter(BLUETOOTH_PASSKEY_MAX_LENGTH)});
- } else if (mType == BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION) {
- mPairingView.setVisibility(View.GONE);
- messageView.setText(getString(R.string.bluetooth_confirm_passkey_msg, name,
- mPairingKey));
- } else if (mType == BluetoothDevice.PAIRING_VARIANT_CONSENT) {
- mPairingView.setVisibility(View.GONE);
- messageView.setText(getString(R.string.bluetooth_incoming_pairing_msg, name));
- } else if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY ||
- mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN) {
- mPairingView.setVisibility(View.GONE);
- messageView.setText(getString(R.string.bluetooth_display_passkey_pin_msg, name,
- mPairingKey));
- } else if (mType == BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT) {
- mPairingView.setVisibility(View.GONE);
- messageView.setText(getString(R.string.bluetooth_incoming_pairing_msg, name));
- } else {
- Log.e(TAG, "Incorrect pairing type received, not creating view");
+ switch (mType) {
+ case BluetoothDevice.PAIRING_VARIANT_PIN:
+ messageView.setText(getString(R.string.bluetooth_enter_pin_msg, name));
+ // Maximum of 16 characters in a PIN adb sync
+ mPairingView.setFilters(new InputFilter[] {
+ new LengthFilter(BLUETOOTH_PIN_MAX_LENGTH) });
+ break;
+
+ case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
+ messageView.setText(getString(R.string.bluetooth_enter_passkey_msg, name));
+ // Maximum of 6 digits for passkey
+ mPairingView.setInputType(InputType.TYPE_CLASS_NUMBER |
+ InputType.TYPE_NUMBER_FLAG_SIGNED);
+ mPairingView.setFilters(new InputFilter[] {
+ new LengthFilter(BLUETOOTH_PASSKEY_MAX_LENGTH)});
+ break;
+
+ case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
+ mPairingView.setVisibility(View.GONE);
+ messageView.setText(getString(R.string.bluetooth_confirm_passkey_msg, name,
+ mPairingKey));
+ break;
+
+ case BluetoothDevice.PAIRING_VARIANT_CONSENT:
+ mPairingView.setVisibility(View.GONE);
+ messageView.setText(getString(R.string.bluetooth_incoming_pairing_msg, name));
+ break;
+
+ case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY:
+ case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN:
+ mPairingView.setVisibility(View.GONE);
+ messageView.setText(getString(R.string.bluetooth_display_passkey_pin_msg, name,
+ mPairingKey));
+ break;
+
+ case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
+ mPairingView.setVisibility(View.GONE);
+ messageView.setText(getString(R.string.bluetooth_incoming_pairing_msg, name));
+ break;
+
+ default:
+ Log.e(TAG, "Incorrect pairing type received, not creating view");
}
return view;
}
- private void createConfirmationDialog() {
+ private void createConfirmationDialog(CachedBluetoothDeviceManager deviceManager) {
final AlertController.AlertParams p = mAlertParams;
p.mIconId = android.R.drawable.ic_dialog_info;
p.mTitle = getString(R.string.bluetooth_pairing_request);
- p.mView = createView();
+ p.mView = createView(deviceManager);
p.mPositiveButtonText = getString(R.string.bluetooth_pairing_accept);
p.mPositiveButtonListener = this;
p.mNegativeButtonText = getString(R.string.bluetooth_pairing_decline);
@@ -201,11 +232,11 @@ public class BluetoothPairingDialog extends AlertActivity implements DialogInter
setupAlert();
}
- private void createConsentDialog() {
+ private void createConsentDialog(CachedBluetoothDeviceManager deviceManager) {
final AlertController.AlertParams p = mAlertParams;
p.mIconId = android.R.drawable.ic_dialog_info;
p.mTitle = getString(R.string.bluetooth_pairing_request);
- p.mView = createView();
+ p.mView = createView(deviceManager);
p.mPositiveButtonText = getString(R.string.bluetooth_pairing_accept);
p.mPositiveButtonListener = this;
p.mNegativeButtonText = getString(R.string.bluetooth_pairing_decline);
@@ -213,11 +244,12 @@ public class BluetoothPairingDialog extends AlertActivity implements DialogInter
setupAlert();
}
- private void createDisplayPasskeyOrPinDialog() {
+ private void createDisplayPasskeyOrPinDialog(
+ CachedBluetoothDeviceManager deviceManager) {
final AlertController.AlertParams p = mAlertParams;
p.mIconId = android.R.drawable.ic_dialog_info;
p.mTitle = getString(R.string.bluetooth_pairing_request);
- p.mView = createView();
+ p.mView = createView(deviceManager);
p.mNegativeButtonText = getString(android.R.string.cancel);
p.mNegativeButtonListener = this;
setupAlert();
@@ -244,32 +276,37 @@ public class BluetoothPairingDialog extends AlertActivity implements DialogInter
}
}
- private void dismissDialog() {
- this.dismiss();
- }
-
private void onPair(String value) {
- if (mType == BluetoothDevice.PAIRING_VARIANT_PIN) {
- byte[] pinBytes = BluetoothDevice.convertPinToBytes(value);
- if (pinBytes == null) {
- return;
- }
- mDevice.setPin(pinBytes);
- } else if (mType == BluetoothDevice.PAIRING_VARIANT_PASSKEY) {
- int passkey = Integer.parseInt(value);
- mDevice.setPasskey(passkey);
- } else if (mType == BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION) {
- mDevice.setPairingConfirmation(true);
- } else if (mType == BluetoothDevice.PAIRING_VARIANT_CONSENT) {
- mDevice.setPairingConfirmation(true);
- } else if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY) {
- // Do Nothing.
- } else if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN) {
- // Do Nothing
- } else if (mType == BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT) {
- mDevice.setRemoteOutOfBandData();
- } else {
- Log.e(TAG, "Incorrect pairing type received");
+ switch (mType) {
+ case BluetoothDevice.PAIRING_VARIANT_PIN:
+ byte[] pinBytes = BluetoothDevice.convertPinToBytes(value);
+ if (pinBytes == null) {
+ return;
+ }
+ mDevice.setPin(pinBytes);
+ break;
+
+ case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
+ int passkey = Integer.parseInt(value);
+ mDevice.setPasskey(passkey);
+ break;
+
+ case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
+ case BluetoothDevice.PAIRING_VARIANT_CONSENT:
+ mDevice.setPairingConfirmation(true);
+ break;
+
+ case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY:
+ case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN:
+ // Do nothing.
+ break;
+
+ case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
+ mDevice.setRemoteOutOfBandData();
+ break;
+
+ default:
+ Log.e(TAG, "Incorrect pairing type received");
}
}
@@ -279,11 +316,12 @@ public class BluetoothPairingDialog extends AlertActivity implements DialogInter
public void onClick(DialogInterface dialog, int which) {
switch (which) {
- case DialogInterface.BUTTON_POSITIVE:
+ case BUTTON_POSITIVE:
onPair(mPairingView.getText().toString());
break;
- case DialogInterface.BUTTON_NEGATIVE:
+ case BUTTON_NEGATIVE:
+ default:
onCancel();
break;
}
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingRequest.java b/src/com/android/settings/bluetooth/BluetoothPairingRequest.java
index 6037c82a9..de96d7119 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingRequest.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingRequest.java
@@ -35,17 +35,15 @@ import android.os.PowerManager;
* confirmation entry dialog. Otherwise it puts a Notification in the status bar, which can
* be clicked to bring up the Pairing entry dialog.
*/
-public class BluetoothPairingRequest extends BroadcastReceiver {
+public final class BluetoothPairingRequest extends BroadcastReceiver {
- public static final int NOTIFICATION_ID = android.R.drawable.stat_sys_data_bluetooth;
+ private static final int NOTIFICATION_ID = android.R.drawable.stat_sys_data_bluetooth;
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) {
-
- LocalBluetoothManager localManager = LocalBluetoothManager.getInstance(context);
-
+ // convert broadcast intent into activity intent (same action string)
BluetoothDevice device =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int type = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
@@ -68,39 +66,35 @@ public class BluetoothPairingRequest extends BroadcastReceiver {
(PowerManager)context.getSystemService(Context.POWER_SERVICE);
String deviceAddress = device != null ? device.getAddress() : null;
if (powerManager.isScreenOn() &&
- localManager.shouldShowDialogInForeground(deviceAddress)) {
+ LocalBluetoothPreferences.shouldShowDialogInForeground(context, deviceAddress)) {
// Since the screen is on and the BT-related activity is in the foreground,
// just open the dialog
context.startActivity(pairingIntent);
-
} else {
-
// Put up a notification that leads to the dialog
Resources res = context.getResources();
- Notification notification = new Notification(
- android.R.drawable.stat_sys_data_bluetooth,
- res.getString(R.string.bluetooth_notif_ticker),
- System.currentTimeMillis());
+ Notification.Builder builder = new Notification.Builder(context)
+ .setSmallIcon(android.R.drawable.stat_sys_data_bluetooth)
+ .setTicker(res.getString(R.string.bluetooth_notif_ticker));
PendingIntent pending = PendingIntent.getActivity(context, 0,
pairingIntent, PendingIntent.FLAG_ONE_SHOT);
String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
if (TextUtils.isEmpty(name)) {
- name = (device != null ? device.getName() :
- context.getString(android.R.string.unknownName));
+ name = device != null ? device.getName() :
+ context.getString(android.R.string.unknownName);
}
- notification.setLatestEventInfo(context,
- res.getString(R.string.bluetooth_notif_title),
- res.getString(R.string.bluetooth_notif_message, name),
- pending);
- notification.flags |= Notification.FLAG_AUTO_CANCEL;
- notification.defaults |= Notification.DEFAULT_SOUND;
+ builder.setContentTitle(res.getString(R.string.bluetooth_notif_title))
+ .setContentText(res.getString(R.string.bluetooth_notif_message, name))
+ .setContentIntent(pending)
+ .setAutoCancel(true)
+ .setDefaults(Notification.DEFAULT_SOUND);
NotificationManager manager = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
- manager.notify(NOTIFICATION_ID, notification);
+ manager.notify(NOTIFICATION_ID, builder.getNotification());
}
} else if (action.equals(BluetoothDevice.ACTION_PAIRING_CANCEL)) {
diff --git a/src/com/android/settings/bluetooth/BluetoothProfilePreference.java b/src/com/android/settings/bluetooth/BluetoothProfilePreference.java
index c74012a20..e334867ec 100644
--- a/src/com/android/settings/bluetooth/BluetoothProfilePreference.java
+++ b/src/com/android/settings/bluetooth/BluetoothProfilePreference.java
@@ -16,9 +16,6 @@
package com.android.settings.bluetooth;
-import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
-import com.android.settings.R;
-
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.preference.Preference;
@@ -26,22 +23,24 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
+import com.android.settings.R;
+
/**
* BluetoothProfilePreference is the preference type used to display each profile for a
* particular bluetooth device.
*/
-public class BluetoothProfilePreference extends Preference implements OnClickListener {
+final class BluetoothProfilePreference extends Preference implements OnClickListener {
- private static final String TAG = "BluetoothProfilePreference";
+// private static final String TAG = "BluetoothProfilePreference";
private Drawable mProfileDrawable;
private boolean mExpanded;
private ImageView mProfileExpandView;
- private final Profile mProfile;
+ private final LocalBluetoothProfile mProfile;
private OnClickListener mOnExpandClickListener;
- public BluetoothProfilePreference(Context context, Profile profile) {
+ BluetoothProfilePreference(Context context, LocalBluetoothProfile profile) {
super(context);
mProfile = profile;
@@ -75,14 +74,14 @@ public class BluetoothProfilePreference extends Preference implements OnClickLis
btProfile.setImageDrawable(mProfileDrawable);
mProfileExpandView = (ImageView) view.findViewById(R.id.profileExpand);
- if (mProfile == Profile.PAN) {
- mProfileExpandView.setVisibility(View.GONE);
- } else {
+ if (mProfile.isAutoConnectable()) {
mProfileExpandView.setOnClickListener(this);
mProfileExpandView.setTag(mProfile);
mProfileExpandView.setImageResource(mExpanded
? com.android.internal.R.drawable.expander_open_holo_dark
: com.android.internal.R.drawable.expander_close_holo_dark);
+ } else {
+ mProfileExpandView.setVisibility(View.GONE);
}
}
diff --git a/src/com/android/settings/bluetooth/BluetoothSettings.java b/src/com/android/settings/bluetooth/BluetoothSettings.java
index 07121e924..c6ba9af56 100644
--- a/src/com/android/settings/bluetooth/BluetoothSettings.java
+++ b/src/com/android/settings/bluetooth/BluetoothSettings.java
@@ -16,15 +16,13 @@
package com.android.settings.bluetooth;
-import android.app.Activity;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
-import android.preference.PreferenceCategory;
+import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
-import android.text.TextUtils;
import android.util.Log;
import android.view.View;
@@ -34,9 +32,7 @@ import com.android.settings.R;
* BluetoothSettings is the Settings screen for Bluetooth configuration and
* connection management.
*/
-public class BluetoothSettings extends DeviceListPreferenceFragment
- implements LocalBluetoothManager.Callback, View.OnClickListener {
-
+public final class BluetoothSettings extends DeviceListPreferenceFragment {
private static final String TAG = "BluetoothSettings";
private static final String KEY_BT_CHECKBOX = "bt_checkbox";
@@ -53,13 +49,20 @@ public class BluetoothSettings extends DeviceListPreferenceFragment
private static final String BTOPP_ACTION_OPEN_RECEIVED_FILES =
"android.btopp.intent.action.OPEN_RECEIVED_FILES";
- void addPreferencesForActivity(Activity activity) {
+ /** Initialize the filter to show bonded devices only. */
+ public BluetoothSettings() {
+ super(BluetoothDeviceFilter.BONDED_DEVICE_FILTER);
+ }
+
+ @Override
+ void addPreferencesForActivity() {
addPreferencesFromResource(R.xml.bluetooth_settings);
- mEnabler = new BluetoothEnabler(activity,
+ mEnabler = new BluetoothEnabler(getActivity(), mLocalAdapter,
(CheckBoxPreference) findPreference(KEY_BT_CHECKBOX));
- mDiscoverableEnabler = new BluetoothDiscoverableEnabler(activity,
+ mDiscoverableEnabler = new BluetoothDiscoverableEnabler(getActivity(),
+ mLocalAdapter,
(CheckBoxPreference) findPreference(KEY_BT_DISCOVERABLE),
(ListPreference) findPreference(KEY_BT_DISCOVERABLE_TIMEOUT));
@@ -88,6 +91,27 @@ public class BluetoothSettings extends DeviceListPreferenceFragment
mEnabler.pause();
}
+ private final View.OnClickListener mListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ // User clicked on advanced options icon for a device in the list
+ if (v.getTag() instanceof CachedBluetoothDevice) {
+ CachedBluetoothDevice
+ device = (CachedBluetoothDevice) v.getTag();
+
+ Preference pref = new Preference(getActivity());
+ pref.setTitle(device.getName());
+ pref.setFragment(DeviceProfilesSettings.class.getName());
+ pref.getExtras().putParcelable(DeviceProfilesSettings.EXTRA_DEVICE,
+ device.getDevice());
+ ((PreferenceActivity) getActivity())
+ .onPreferenceStartFragment(BluetoothSettings.this,
+ pref);
+ } else {
+ Log.w(TAG, "onClick() called for other View: " + v);
+ }
+ }
+ };
+
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
@@ -105,9 +129,7 @@ public class BluetoothSettings extends DeviceListPreferenceFragment
if (bondState == BluetoothDevice.BOND_BONDED) {
// add to "Paired devices" list after remote-initiated pairing
if (mDevicePreferenceMap.get(cachedDevice) == null) {
- if (addDevicePreference(cachedDevice)) {
- createDevicePreference(cachedDevice);
- }
+ createDevicePreference(cachedDevice);
}
} else if (bondState == BluetoothDevice.BOND_NONE) {
// remove unpaired device from paired devices list
@@ -116,21 +138,11 @@ public class BluetoothSettings extends DeviceListPreferenceFragment
}
/**
- * Additional check to only add paired devices to list.
- */
- boolean addDevicePreference(CachedBluetoothDevice cachedDevice) {
- if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
- return super.addDevicePreference(cachedDevice);
- } else {
- return false;
- }
- }
-
- /**
* Add a listener, which enables the advanced settings icon.
* @param preference the newly added preference
*/
+ @Override
void initDevicePreference(BluetoothDevicePreference preference) {
- preference.setOnSettingsClickListener(this);
+ preference.setOnSettingsClickListener(mListener);
}
}
diff --git a/src/com/android/settings/bluetooth/CachedBluetoothDevice.java b/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
index 11885ac6c..0bc816c9d 100644
--- a/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
+++ b/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
@@ -16,30 +16,18 @@
package com.android.settings.bluetooth;
-import com.android.settings.R;
-
-import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
-
-import android.app.AlertDialog;
-import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
+import android.bluetooth.BluetoothProfile;
import android.os.ParcelUuid;
import android.os.SystemClock;
-import android.preference.Preference;
-import android.preference.PreferenceActivity;
import android.text.TextUtils;
import android.util.Log;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Collection;
+import java.util.Collections;
import java.util.List;
-import java.util.Map;
/**
* CachedBluetoothDevice represents a remote Bluetooth device. It contains
@@ -47,27 +35,23 @@ import java.util.Map;
* functionality that can be performed on the device (connect, pair, disconnect,
* etc.).
*/
-class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
+final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
private static final String TAG = "CachedBluetoothDevice";
- private static final boolean D = LocalBluetoothManager.D;
- private static final boolean V = LocalBluetoothManager.V;
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Utils.V;
+ private final LocalBluetoothAdapter mLocalAdapter;
+ private final LocalBluetoothProfileManager mProfileManager;
private final BluetoothDevice mDevice;
private String mName;
private short mRssi;
private BluetoothClass mBtClass;
- private Context mContext;
- private List<Profile> mProfiles = new ArrayList<Profile>();
+ private final List<LocalBluetoothProfile> mProfiles =
+ new ArrayList<LocalBluetoothProfile>();
private boolean mVisible;
- private final LocalBluetoothManager mLocalManager;
-
- private AlertDialog mDialog = null;
-
- private List<Callback> mCallbacks = new ArrayList<Callback>();
+ private final Collection<Callback> mCallbacks = new ArrayList<Callback>();
/**
* When we connect to multiple profiles, we only want to display a single
@@ -95,186 +79,62 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
* @param profile Profile to describe
* @return Description of the device and profile
*/
- private String describe(Profile profile) {
+ private String describe(LocalBluetoothProfile profile) {
StringBuilder sb = new StringBuilder();
sb.append("Address:").append(mDevice);
if (profile != null) {
- sb.append(" Profile:").append(profile.name());
+ sb.append(" Profile:").append(profile);
}
return sb.toString();
}
- public void onProfileStateChanged(Profile profile, int newProfileState) {
- if (D) {
- Log.d(TAG, "onProfileStateChanged: profile " + profile.toString() +
+ void onProfileStateChanged(LocalBluetoothProfile profile, int newProfileState) {
+ if (Utils.D) {
+ Log.d(TAG, "onProfileStateChanged: profile " + profile +
" newProfileState " + newProfileState);
}
- final LocalBluetoothProfileManager pm =
- LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile);
- if (pm == null) return;
- int newState = pm.convertState(newProfileState);
-
- if (newState == SettingsBtStatus.CONNECTION_STATUS_CONNECTED) {
+ if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
if (!mProfiles.contains(profile)) {
mProfiles.add(profile);
}
}
}
- CachedBluetoothDevice(Context context, BluetoothDevice device) {
- mLocalManager = LocalBluetoothManager.getInstance(context);
- if (mLocalManager == null) {
- throw new IllegalStateException(
- "Cannot use CachedBluetoothDevice without Bluetooth hardware");
- }
-
+ CachedBluetoothDevice(LocalBluetoothAdapter adapter,
+ LocalBluetoothProfileManager profileManager,
+ BluetoothDevice device) {
+ mLocalAdapter = adapter;
+ mProfileManager = profileManager;
mDevice = device;
- mContext = context;
-
fillData();
}
- public void onClicked() {
- int bondState = getBondState();
-
- if (isConnected()) {
- askDisconnect();
- } else if (bondState == BluetoothDevice.BOND_BONDED) {
- connect(true);
- } else if (bondState == BluetoothDevice.BOND_NONE) {
- pair();
- }
- }
-
- public void disconnect() {
- for (Profile profile : mProfiles) {
+ void disconnect() {
+ for (LocalBluetoothProfile profile : mProfiles) {
disconnect(profile);
}
}
- public void disconnect(Profile profile) {
- LocalBluetoothProfileManager profileManager =
- LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile);
- if (profileManager.disconnect(mDevice)) {
- if (D) {
+ void disconnect(LocalBluetoothProfile profile) {
+ if (profile.disconnect(mDevice)) {
+ if (Utils.D) {
Log.d(TAG, "Command sent successfully:DISCONNECT " + describe(profile));
}
}
}
- public void askDisconnect() {
- Context context = mLocalManager.getForegroundActivity();
- if (context == null) {
- // Cannot ask, since we need an activity context
- disconnect();
+ void connect(boolean connectAllProfiles) {
+ if (!ensurePaired()) {
return;
}
- Resources res = context.getResources();
-
- String name = getName();
- if (TextUtils.isEmpty(name)) {
- name = res.getString(R.string.bluetooth_device);
- }
- String message = res.getString(R.string.bluetooth_disconnect_blank, name);
-
- DialogInterface.OnClickListener disconnectListener = new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- disconnect();
- }
- };
-
- showDisconnectDialog(context, disconnectListener, message);
- }
-
- public void askDisconnect(final Profile profile) {
- Context context = mLocalManager.getForegroundActivity();
- if (context == null) {
- // Cannot ask, since we need an activity context
- disconnect(profile);
- return;
- }
-
- Resources res = context.getResources();
-
- String name = getName();
- if (TextUtils.isEmpty(name)) {
- name = res.getString(R.string.bluetooth_device);
- }
- int disconnectMessage;
- switch (profile) {
- case A2DP:
- disconnectMessage = R.string.bluetooth_disconnect_a2dp_profile;
- break;
- case HEADSET:
- disconnectMessage = R.string.bluetooth_disconnect_headset_profile;
- break;
- case HID:
- disconnectMessage = R.string.bluetooth_disconnect_hid_profile;
- break;
- case PAN:
- disconnectMessage = R.string.bluetooth_disconnect_pan_profile;
- break;
- default:
- Log.w(TAG, "askDisconnect: unexpected profile " + profile);
- disconnectMessage = R.string.bluetooth_disconnect_blank;
- break;
- }
- String message = res.getString(disconnectMessage, name);
-
- DialogInterface.OnClickListener disconnectListener =
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- disconnect(profile);
- }
- };
-
- showDisconnectDialog(context, disconnectListener, message);
- }
-
- private void showDisconnectDialog(Context context,
- DialogInterface.OnClickListener disconnectListener,
- String message) {
- if (mDialog == null) {
- mDialog = new AlertDialog.Builder(context)
- .setPositiveButton(android.R.string.ok, disconnectListener)
- .setNegativeButton(android.R.string.cancel, null)
- .create();
- } else {
- if (mDialog.isShowing()) {
- mDialog.dismiss();
- }
- // use disconnectListener for the correct profile(s)
- CharSequence okText = context.getText(android.R.string.ok);
- mDialog.setButton(DialogInterface.BUTTON_POSITIVE,
- okText, disconnectListener);
- }
- mDialog.setTitle(getName());
- mDialog.setMessage(message);
- mDialog.show();
- }
-
- @Override
- protected void finalize() throws Throwable {
- if (mDialog != null) {
- mDialog.dismiss();
- mDialog = null;
- }
-
- super.finalize();
- }
-
- public void connect(boolean connectAllProfiles) {
- if (!ensurePaired()) return;
-
mConnectAttempted = SystemClock.elapsedRealtime();
-
connectWithoutResettingTimer(connectAllProfiles);
}
- /*package*/ void onBondingDockConnect() {
+ void onBondingDockConnect() {
// Attempt to connect if UUIDs are available. Otherwise,
// we will connect when the ACTION_UUID intent arrives.
connect(false);
@@ -282,7 +142,7 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
private void connectWithoutResettingTimer(boolean connectAllProfiles) {
// Try to initialize the profiles if they were not.
- if (mProfiles.size() == 0) {
+ if (mProfiles.isEmpty()) {
if (!updateProfiles()) {
// If UUIDs are not available yet, connect will be happen
// upon arrival of the ACTION_UUID intent.
@@ -295,98 +155,85 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
mIsConnectingErrorPossible = true;
int preferredProfiles = 0;
- for (Profile profile : mProfiles) {
+ for (LocalBluetoothProfile profile : mProfiles) {
if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {
- LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
- .getProfileManager(mLocalManager, profile);
- if (profileManager.isPreferred(mDevice)) {
+ if (profile.isPreferred(mDevice)) {
++preferredProfiles;
- connectInt(this, profile);
+ connectInt(profile);
}
}
}
if (DEBUG) Log.d(TAG, "Preferred profiles = " + preferredProfiles);
if (preferredProfiles == 0) {
- connectAllAutoConnectableProfiles();
+ connectAutoConnectableProfiles();
}
}
- private void connectAllAutoConnectableProfiles() {
- if (!ensurePaired()) return;
-
+ private void connectAutoConnectableProfiles() {
+ if (!ensurePaired()) {
+ return;
+ }
// Reset the only-show-one-error-dialog tracking variable
mIsConnectingErrorPossible = true;
- for (Profile profile : mProfiles) {
+ for (LocalBluetoothProfile profile : mProfiles) {
if (profile.isAutoConnectable()) {
- LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
- .getProfileManager(mLocalManager, profile);
- profileManager.setPreferred(mDevice, true);
- connectInt(this, profile);
+ profile.setPreferred(mDevice, true);
+ connectInt(profile);
}
}
}
- public void connect(Profile profile) {
+ /**
+ * Connect this device to the specified profile.
+ *
+ * @param profile the profile to use with the remote device
+ */
+ void connectProfile(LocalBluetoothProfile profile) {
mConnectAttempted = SystemClock.elapsedRealtime();
// Reset the only-show-one-error-dialog tracking variable
mIsConnectingErrorPossible = true;
- connectInt(this, profile);
+ connectInt(profile);
}
- private boolean connectInt(CachedBluetoothDevice cachedDevice, Profile profile) {
- if (!cachedDevice.ensurePaired()) return false;
-
- LocalBluetoothProfileManager profileManager =
- LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile);
-
- if (profileManager.connect(cachedDevice.mDevice)) {
- if (D) {
+ private void connectInt(LocalBluetoothProfile profile) {
+ if (!ensurePaired()) {
+ return;
+ }
+ if (profile.connect(mDevice)) {
+ if (Utils.D) {
Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
}
- return true;
+ return;
}
- Log.i(TAG, "Failed to connect " + profile.toString() + " to " + cachedDevice.mName);
-
- return false;
- }
-
- public void showConnectingError() {
- if (!mIsConnectingErrorPossible) return;
- mIsConnectingErrorPossible = false;
-
- mLocalManager.showError(mDevice,
- R.string.bluetooth_connecting_error_message);
+ Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName);
}
private boolean ensurePaired() {
if (getBondState() == BluetoothDevice.BOND_NONE) {
- pair();
+ startPairing();
return false;
} else {
return true;
}
}
- public void pair() {
- BluetoothAdapter adapter = mLocalManager.getBluetoothAdapter();
-
+ boolean startPairing() {
// Pairing is unreliable while scanning, so cancel discovery
- if (adapter.isDiscovering()) {
- adapter.cancelDiscovery();
+ if (mLocalAdapter.isDiscovering()) {
+ mLocalAdapter.cancelDiscovery();
}
if (!mDevice.createBond()) {
- mLocalManager.showError(mDevice,
- R.string.bluetooth_pairing_error_message);
- return;
+ return false;
}
mConnectAfterPairing = true; // auto-connect after pairing
+ return true;
}
- public void unpair() {
+ void unpair() {
disconnect();
int state = getBondState();
@@ -396,14 +243,14 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
}
if (state != BluetoothDevice.BOND_NONE) {
- final BluetoothDevice dev = getDevice();
+ final BluetoothDevice dev = mDevice;
if (dev != null) {
final boolean successful = dev.removeBond();
if (successful) {
- if (D) {
+ if (Utils.D) {
Log.d(TAG, "Command sent successfully:REMOVE_BOND " + describe(null));
}
- } else if (V) {
+ } else if (Utils.V) {
Log.v(TAG, "Framework rejected command immediately:REMOVE_BOND " +
describe(null));
}
@@ -411,6 +258,7 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
}
}
+ // TODO: do any of these need to run async on a background thread?
private void fillData() {
fetchName();
fetchBtClass();
@@ -421,15 +269,15 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
dispatchAttributesChanged();
}
- public BluetoothDevice getDevice() {
+ BluetoothDevice getDevice() {
return mDevice;
}
- public String getName() {
+ String getName() {
return mName;
}
- public void setName(String name) {
+ void setName(String name) {
if (!mName.equals(name)) {
if (TextUtils.isEmpty(name)) {
// TODO: use friendly name for unknown device (bug 1181856)
@@ -442,7 +290,7 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
}
}
- public void refreshName() {
+ void refreshName() {
fetchName();
dispatchAttributesChanged();
}
@@ -452,15 +300,15 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
if (TextUtils.isEmpty(mName)) {
mName = mDevice.getAddress();
- if (DEBUG) Log.d(TAG, "Default to address. Device has no name (yet) " + mName);
+ if (DEBUG) Log.d(TAG, "Device has no name (yet), use address: " + mName);
}
}
- public void refresh() {
+ void refresh() {
dispatchAttributesChanged();
}
- public boolean isVisible() {
+ boolean isVisible() {
return mVisible;
}
@@ -471,7 +319,7 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
}
}
- public int getBondState() {
+ int getBondState() {
return mDevice.getBondState();
}
@@ -487,11 +335,10 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
*
* @return Whether it is connected.
*/
- public boolean isConnected() {
- for (Profile profile : mProfiles) {
- int status = LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile)
- .getConnectionStatus(mDevice);
- if (SettingsBtStatus.isConnectionStatusConnected(status)) {
+ boolean isConnected() {
+ for (LocalBluetoothProfile profile : mProfiles) {
+ int status = profile.getConnectionStatus(mDevice);
+ if (status == BluetoothProfile.STATE_CONNECTED) {
return true;
}
}
@@ -499,81 +346,21 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
return false;
}
- public boolean isConnectedProfile(Profile profile) {
- int status = LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile)
- .getConnectionStatus(mDevice);
- if (SettingsBtStatus.isConnectionStatusConnected(status)) {
- return true;
- }
+ boolean isConnectedProfile(LocalBluetoothProfile profile) {
+ int status = profile.getConnectionStatus(mDevice);
+ return status == BluetoothProfile.STATE_CONNECTED;
- return false;
}
- public boolean isBusy() {
- for (Profile profile : mProfiles) {
- int status = LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile)
- .getConnectionStatus(mDevice);
- if (SettingsBtStatus.isConnectionStatusBusy(status)) {
+ boolean isBusy() {
+ for (LocalBluetoothProfile profile : mProfiles) {
+ int status = profile.getConnectionStatus(mDevice);
+ if (status == BluetoothProfile.STATE_CONNECTING
+ || status == BluetoothProfile.STATE_DISCONNECTING) {
return true;
}
}
-
- if (getBondState() == BluetoothDevice.BOND_BONDING) {
- return true;
- }
-
- return false;
- }
-
- public int getBtClassDrawable() {
- if (mBtClass != null) {
- switch (mBtClass.getMajorDeviceClass()) {
- case BluetoothClass.Device.Major.COMPUTER:
- return R.drawable.ic_bt_laptop;
-
- case BluetoothClass.Device.Major.PHONE:
- return R.drawable.ic_bt_cellphone;
-
- case BluetoothClass.Device.Major.PERIPHERAL:
- return getHidClassDrawable();
-
- case BluetoothClass.Device.Major.IMAGING:
- return R.drawable.ic_bt_imaging;
- }
- } else {
- Log.w(TAG, "mBtClass is null");
- }
-
- if (mProfiles.size() > 0) {
- if (mProfiles.contains(Profile.A2DP)) {
- return R.drawable.ic_bt_headphones_a2dp;
- } else if (mProfiles.contains(Profile.HEADSET)) {
- return R.drawable.ic_bt_headset_hfp;
- }
- } else if (mBtClass != null) {
- if (mBtClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) {
- return R.drawable.ic_bt_headphones_a2dp;
-
- }
- if (mBtClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
- return R.drawable.ic_bt_headset_hfp;
- }
- }
- return 0;
- }
-
- private int getHidClassDrawable() {
- switch (mBtClass.getDeviceClass()) {
- case BluetoothClass.Device.PERIPHERAL_KEYBOARD:
- case BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING:
- return R.drawable.ic_bt_keyboard_hid;
-
- case BluetoothClass.Device.PERIPHERAL_POINTING:
- return R.drawable.ic_bt_pointing_hid;
-
- default:
- return R.drawable.ic_bt_misc_hid;
- }
+ return getBondState() == BluetoothDevice.BOND_BONDING;
}
/**
@@ -587,11 +374,10 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
ParcelUuid[] uuids = mDevice.getUuids();
if (uuids == null) return false;
- BluetoothAdapter adapter = mLocalManager.getBluetoothAdapter();
- ParcelUuid[] localUuids = adapter.getUuids();
+ ParcelUuid[] localUuids = mLocalAdapter.getUuids();
if (localUuids == null) return false;
- LocalBluetoothProfileManager.updateProfiles(uuids, localUuids, mProfiles);
+ mProfileManager.updateProfiles(uuids, localUuids, mProfiles);
if (DEBUG) {
Log.e(TAG, "updating profiles for " + mDevice.getName());
@@ -599,8 +385,8 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
if (bluetoothClass != null) Log.v(TAG, "Class: " + bluetoothClass.toString());
Log.v(TAG, "UUID:");
- for (int i = 0; i < uuids.length; i++) {
- Log.v(TAG, " " + uuids[i]);
+ for (ParcelUuid uuid : uuids) {
+ Log.v(TAG, " " + uuid);
}
}
return true;
@@ -610,7 +396,7 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
* Refreshes the UI for the BT class, including fetching the latest value
* for the class.
*/
- public void refreshBtClass() {
+ void refreshBtClass() {
fetchBtClass();
dispatchAttributesChanged();
}
@@ -618,7 +404,7 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
/**
* Refreshes the UI when framework alerts us of a UUID change.
*/
- public void onUuidChanged() {
+ void onUuidChanged() {
updateProfiles();
if (DEBUG) {
@@ -630,7 +416,7 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
* If a connect was attempted earlier without any UUID, we will do the
* connect now.
*/
- if (mProfiles.size() > 0
+ if (!mProfiles.isEmpty()
&& (mConnectAttempted + MAX_UUID_DELAY_FOR_AUTO_CONNECT) > SystemClock
.elapsedRealtime()) {
connectWithoutResettingTimer(false);
@@ -638,7 +424,7 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
dispatchAttributesChanged();
}
- public void onBondingStateChanged(int bondState) {
+ void onBondingStateChanged(int bondState) {
if (bondState == BluetoothDevice.BOND_NONE) {
mProfiles.clear();
mConnectAfterPairing = false; // cancel auto-connect
@@ -656,52 +442,25 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
}
}
- public void setBtClass(BluetoothClass btClass) {
+ void setBtClass(BluetoothClass btClass) {
if (btClass != null && mBtClass != btClass) {
mBtClass = btClass;
dispatchAttributesChanged();
}
}
- public int getSummary() {
- for (Profile profile : mProfiles) {
- LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
- .getProfileManager(mLocalManager, profile);
- int connectionStatus = profileManager.getConnectionStatus(mDevice);
-
- if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus) ||
- connectionStatus == SettingsBtStatus.CONNECTION_STATUS_CONNECTING ||
- connectionStatus == SettingsBtStatus.CONNECTION_STATUS_DISCONNECTING) {
- return SettingsBtStatus.getConnectionStatusSummary(connectionStatus);
- }
- }
-
- return SettingsBtStatus.getPairingStatusSummary(getBondState());
+ BluetoothClass getBtClass() {
+ return mBtClass;
}
- public Map<Profile, Drawable> getProfileIcons() {
- Map<Profile, Drawable> drawables = new HashMap<Profile, Drawable>();
-
- for (Profile profile : mProfiles) {
- int iconResource;
- if (profile == Profile.HID && mBtClass != null) {
- iconResource = getHidClassDrawable();
- } else {
- LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
- .getProfileManager(mLocalManager, profile);
- iconResource = profileManager.getDrawableResource();
- }
- if (iconResource != 0) {
- drawables.put(profile, mContext.getResources().getDrawable(iconResource));
- }
- }
-
- return drawables;
+ List<LocalBluetoothProfile> getProfiles() {
+ return Collections.unmodifiableList(mProfiles);
}
- public List<Profile> getConnectableProfiles() {
- ArrayList<Profile> connectableProfiles = new ArrayList<Profile>();
- for (Profile profile : mProfiles) {
+ List<LocalBluetoothProfile> getConnectableProfiles() {
+ List<LocalBluetoothProfile> connectableProfiles =
+ new ArrayList<LocalBluetoothProfile>();
+ for (LocalBluetoothProfile profile : mProfiles) {
if (profile.isConnectable()) {
connectableProfiles.add(profile);
}
@@ -709,36 +468,13 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
return connectableProfiles;
}
- public void onClickedAdvancedOptions(SettingsPreferenceFragment fragment) {
- // TODO: Verify if there really is a case when there's no foreground
- // activity
-
- // Intent intent = new Intent();
- // // Need an activity context to open this in our task
- // Context context = mLocalManager.getForegroundActivity();
- // if (context == null) {
- // // Fallback on application context, and open in a new task
- // context = mLocalManager.getContext();
- // intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- // }
- // intent.setClass(context, ConnectSpecificProfilesActivity.class);
- // intent.putExtra(ConnectSpecificProfilesActivity.EXTRA_DEVICE,
- // mDevice);
- // context.startActivity(intent);
- Preference pref = new Preference(fragment.getActivity());
- pref.setTitle(getName());
- pref.setFragment(DeviceProfilesSettings.class.getName());
- pref.getExtras().putParcelable(DeviceProfilesSettings.EXTRA_DEVICE, mDevice);
- ((PreferenceActivity) fragment.getActivity()).onPreferenceStartFragment(fragment, pref);
- }
-
- public void registerCallback(Callback callback) {
+ void registerCallback(Callback callback) {
synchronized (mCallbacks) {
mCallbacks.add(callback);
}
}
- public void unregisterCallback(Callback callback) {
+ void unregisterCallback(Callback callback) {
synchronized (mCallbacks) {
mCallbacks.remove(callback);
}
@@ -760,9 +496,8 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
@Override
public boolean equals(Object o) {
if ((o == null) || !(o instanceof CachedBluetoothDevice)) {
- throw new ClassCastException();
+ return false;
}
-
return mDevice.equals(((CachedBluetoothDevice) o).mDevice);
}
@@ -771,11 +506,12 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
return mDevice.getAddress().hashCode();
}
+ // This comparison uses non-final fields so the sort order may change
+ // when device attributes change (such as bonding state). Settings
+ // will completely refresh the device list when this happens.
public int compareTo(CachedBluetoothDevice another) {
- int comparison;
-
// Connected above not connected
- comparison = (another.isConnected() ? 1 : 0) - (isConnected() ? 1 : 0);
+ int comparison = (another.isConnected() ? 1 : 0) - (isConnected() ? 1 : 0);
if (comparison != 0) return comparison;
// Paired above not paired
@@ -792,7 +528,7 @@ class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
if (comparison != 0) return comparison;
// Fallback on name
- return getName().compareTo(another.getName());
+ return mName.compareTo(another.mName);
}
public interface Callback {
diff --git a/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java b/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java
index 3ee8bc26d..ab71ece7e 100644
--- a/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java
+++ b/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java
@@ -16,122 +16,83 @@
package com.android.settings.bluetooth;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
-import android.util.Log;
-
-import com.android.settings.R;
-import com.android.settings.bluetooth.LocalBluetoothManager.Callback;
-import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
-import java.util.Set;
/**
* CachedBluetoothDeviceManager manages the set of remote Bluetooth devices.
*/
-class CachedBluetoothDeviceManager {
- private static final String TAG = "CachedBluetoothDeviceManager";
-
- final LocalBluetoothManager mLocalManager;
- final List<Callback> mCallbacks;
-
- final List<CachedBluetoothDevice> mCachedDevices = new ArrayList<CachedBluetoothDevice>();
-
- public CachedBluetoothDeviceManager(LocalBluetoothManager localManager) {
- mLocalManager = localManager;
- mCallbacks = localManager.getCallbacks();
- }
+final class CachedBluetoothDeviceManager {
+// private static final String TAG = "CachedBluetoothDeviceManager";
- private synchronized boolean readPairedDevices() {
- BluetoothAdapter adapter = mLocalManager.getBluetoothAdapter();
- Set<BluetoothDevice> bondedDevices = adapter.getBondedDevices();
- if (bondedDevices == null) return false;
-
- boolean deviceAdded = false;
- for (BluetoothDevice device : bondedDevices) {
- CachedBluetoothDevice cachedDevice = findDevice(device);
- if (cachedDevice == null) {
- cachedDevice = new CachedBluetoothDevice(mLocalManager.getContext(), device);
- mCachedDevices.add(cachedDevice);
- dispatchDeviceAdded(cachedDevice);
- deviceAdded = true;
- }
- }
-
- return deviceAdded;
- }
+ private final List<CachedBluetoothDevice> mCachedDevices =
+ new ArrayList<CachedBluetoothDevice>();
- public synchronized List<CachedBluetoothDevice> getCachedDevicesCopy() {
+ public synchronized Collection<CachedBluetoothDevice> getCachedDevicesCopy() {
return new ArrayList<CachedBluetoothDevice>(mCachedDevices);
}
- void onBluetoothStateChanged(boolean enabled) {
- if (enabled) {
- readPairedDevices();
- }
- }
-
- public synchronized void onDeviceAppeared(BluetoothDevice device, short rssi,
- BluetoothClass btClass, String name) {
- boolean deviceAdded = false;
-
- CachedBluetoothDevice cachedDevice = findDevice(device);
- if (cachedDevice == null) {
- cachedDevice = new CachedBluetoothDevice(mLocalManager.getContext(), device);
- mCachedDevices.add(cachedDevice);
- deviceAdded = true;
- }
- cachedDevice.setRssi(rssi);
- cachedDevice.setBtClass(btClass);
- cachedDevice.setName(name);
- cachedDevice.setVisible(true);
-
- if (deviceAdded) {
- dispatchDeviceAdded(cachedDevice);
- }
- }
-
- public synchronized void onDeviceDisappeared(BluetoothDevice device) {
- CachedBluetoothDevice cachedDevice = findDevice(device);
- if (cachedDevice == null) return;
-
+ public boolean onDeviceDisappeared(CachedBluetoothDevice cachedDevice) {
cachedDevice.setVisible(false);
- checkForDeviceRemoval(cachedDevice);
+ return checkForDeviceRemoval(cachedDevice);
}
- private void checkForDeviceRemoval(CachedBluetoothDevice cachedDevice) {
+ private boolean checkForDeviceRemoval(
+ CachedBluetoothDevice cachedDevice) {
if (cachedDevice.getBondState() == BluetoothDevice.BOND_NONE &&
!cachedDevice.isVisible()) {
// If device isn't paired, remove it altogether
mCachedDevices.remove(cachedDevice);
- dispatchDeviceDeleted(cachedDevice);
+ return true; // dispatch device deleted
}
+ return false;
}
- public synchronized void onDeviceNameUpdated(BluetoothDevice device) {
+ public void onDeviceNameUpdated(BluetoothDevice device) {
CachedBluetoothDevice cachedDevice = findDevice(device);
if (cachedDevice != null) {
cachedDevice.refreshName();
}
}
- public synchronized CachedBluetoothDevice findDevice(BluetoothDevice device) {
-
- for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
- CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
-
+ /**
+ * Search for existing {@link CachedBluetoothDevice} or return null
+ * if this device isn't in the cache. Use {@link #addDevice}
+ * to create and return a new {@link CachedBluetoothDevice} for
+ * a newly discovered {@link BluetoothDevice}.
+ *
+ * @param device the address of the Bluetooth device
+ * @return the cached device object for this device, or null if it has
+ * not been previously seen
+ */
+ CachedBluetoothDevice findDevice(BluetoothDevice device) {
+ for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
if (cachedDevice.getDevice().equals(device)) {
return cachedDevice;
}
}
-
return null;
}
/**
+ * Create and return a new {@link CachedBluetoothDevice}. This assumes
+ * that {@link #findDevice} has already been called and returned null.
+ * @param device the address of the new Bluetooth device
+ * @return the newly created CachedBluetoothDevice object
+ */
+ CachedBluetoothDevice addDevice(LocalBluetoothAdapter adapter,
+ LocalBluetoothProfileManager profileManager,
+ BluetoothDevice device) {
+ CachedBluetoothDevice newDevice = new CachedBluetoothDevice(adapter, profileManager,
+ device);
+ mCachedDevices.add(newDevice);
+ return newDevice;
+ }
+
+ /**
* Attempts to get the name of a remote device, otherwise returns the address.
*
* @param device The remote device.
@@ -139,122 +100,23 @@ class CachedBluetoothDeviceManager {
*/
public String getName(BluetoothDevice device) {
CachedBluetoothDevice cachedDevice = findDevice(device);
- if (cachedDevice != null) return cachedDevice.getName();
-
- String name = device.getName();
- if (name != null) return name;
-
- return device.getAddress();
- }
-
- private void dispatchDeviceAdded(CachedBluetoothDevice cachedDevice) {
- synchronized (mCallbacks) {
- for (Callback callback : mCallbacks) {
- callback.onDeviceAdded(cachedDevice);
- }
- }
-
- // TODO: divider between prev paired/connected and scanned
- }
-
- private void dispatchDeviceDeleted(CachedBluetoothDevice cachedDevice) {
- synchronized (mCallbacks) {
- for (Callback callback : mCallbacks) {
- callback.onDeviceDeleted(cachedDevice);
- }
- }
- }
-
- private void dispatchDeviceBondStateChanged(
- CachedBluetoothDevice cachedDevice, int bondState) {
- synchronized (mCallbacks) {
- for (Callback callback : mCallbacks) {
- callback.onDeviceBondStateChanged(cachedDevice, bondState);
- }
- }
- }
-
- public synchronized void onBondingStateChanged(BluetoothDevice device, int bondState) {
- CachedBluetoothDevice cachedDevice = findDevice(device);
- if (cachedDevice == null) {
- if (!readPairedDevices()) {
- Log.e(TAG, "Got bonding state changed for " + device +
- ", but we have no record of that device.");
- return;
- }
- cachedDevice = findDevice(device);
- if (cachedDevice == null) {
- Log.e(TAG, "Got bonding state changed for " + device +
- ", but device not added in cache.");
- return;
- }
+ if (cachedDevice != null) {
+ return cachedDevice.getName();
}
- dispatchDeviceBondStateChanged(cachedDevice, bondState);
- cachedDevice.onBondingStateChanged(bondState);
- }
-
- /**
- * Called when we have reached the un-bond state.
- *
- * @param device The remote device.
- * @param reason The reason, one of the error reasons from
- * BluetoothDevice.UNBOND_REASON_*
- */
- public synchronized void showUnbondMessage(BluetoothDevice device, int reason) {
- int errorMsg;
-
- switch(reason) {
- case BluetoothDevice.UNBOND_REASON_AUTH_FAILED:
- errorMsg = R.string.bluetooth_pairing_pin_error_message;
- mLocalManager.showError(device, errorMsg);
- break;
- case BluetoothDevice.UNBOND_REASON_AUTH_REJECTED:
- errorMsg = R.string.bluetooth_pairing_rejected_error_message;
- mLocalManager.showError(device, errorMsg);
- break;
- case BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN:
- errorMsg = R.string.bluetooth_pairing_device_down_error_message;
- mLocalManager.showError(device, errorMsg);
- break;
- case BluetoothDevice.UNBOND_REASON_DISCOVERY_IN_PROGRESS:
- case BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT:
- case BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS:
- case BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED:
- errorMsg = R.string.bluetooth_pairing_error_message;
- mLocalManager.showError(device, errorMsg);
- break;
- default:
- Log.w(TAG, "showUnbondMessage: Not displaying any message for reason:" + reason);
- break;
+ String name = device.getName();
+ if (name != null) {
+ return name;
}
- }
- public synchronized void onProfileStateChanged(BluetoothDevice device, Profile profile,
- int newProfileState) {
- CachedBluetoothDevice cachedDevice = findDevice(device);
- if (cachedDevice == null) return;
-
- cachedDevice.onProfileStateChanged(profile, newProfileState);
- cachedDevice.refresh();
- }
-
- public synchronized void onConnectingError(BluetoothDevice device) {
- CachedBluetoothDevice cachedDevice = findDevice(device);
- if (cachedDevice == null) return;
-
- /*
- * Go through the device's delegate so we don't spam the user with
- * errors connecting to different profiles, and instead make sure the
- * user sees a single error for his single 'connect' action.
- */
- cachedDevice.showConnectingError();
+ return device.getAddress();
}
public synchronized void onScanningStateChanged(boolean started) {
if (!started) return;
// If starting a new scan, clear old visibility
+ // Iterate in reverse order since devices may be removed.
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
cachedDevice.setVisible(false);
diff --git a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
index 46fff6e01..a978e2392 100644
--- a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
+++ b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
@@ -16,28 +16,18 @@
package com.android.settings.bluetooth;
-import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothDevicePicker;
-import android.bluetooth.BluetoothUuid;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.os.Bundle;
-import android.os.ParcelUuid;
import android.preference.Preference;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.util.Log;
-import android.view.View;
import com.android.settings.ProgressCategory;
import com.android.settings.SettingsPreferenceFragment;
-import java.util.List;
+import java.util.Collection;
import java.util.WeakHashMap;
/**
@@ -48,105 +38,96 @@ import java.util.WeakHashMap;
* @see DevicePickerFragment
* @see BluetoothFindNearby
*/
-public abstract class DeviceListPreferenceFragment extends SettingsPreferenceFragment
- implements LocalBluetoothManager.Callback, View.OnClickListener {
+public abstract class DeviceListPreferenceFragment extends
+ SettingsPreferenceFragment implements BluetoothCallback {
private static final String TAG = "DeviceListPreferenceFragment";
- static final String KEY_BT_DEVICE_LIST = "bt_device_list";
- static final String KEY_BT_SCAN = "bt_scan";
+ private static final String KEY_BT_DEVICE_LIST = "bt_device_list";
+ private static final String KEY_BT_SCAN = "bt_scan";
- int mFilterType;
+ private BluetoothDeviceFilter.Filter mFilter;
- BluetoothDevice mSelectedDevice = null;
+ BluetoothDevice mSelectedDevice;
+ LocalBluetoothAdapter mLocalAdapter;
LocalBluetoothManager mLocalManager;
private PreferenceCategory mDeviceList;
- WeakHashMap<CachedBluetoothDevice, BluetoothDevicePreference> mDevicePreferenceMap =
+ final WeakHashMap<CachedBluetoothDevice, BluetoothDevicePreference> mDevicePreferenceMap =
new WeakHashMap<CachedBluetoothDevice, BluetoothDevicePreference>();
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
- onBluetoothStateChanged(mLocalManager.getBluetoothState());
- }
- }
- };
+ DeviceListPreferenceFragment() {
+ mFilter = BluetoothDeviceFilter.ALL_FILTER;
+ }
+
+ DeviceListPreferenceFragment(BluetoothDeviceFilter.Filter filter) {
+ mFilter = filter;
+ }
+
+ final void setFilter(int filterType) {
+ mFilter = BluetoothDeviceFilter.getFilter(filterType);
+ }
@Override
- public void onActivityCreated(Bundle savedInstanceState) {
- // We delay calling super.onActivityCreated(). See WifiSettings.java for more info.
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
- final Activity activity = getActivity();
- mLocalManager = LocalBluetoothManager.getInstance(activity);
+ mLocalManager = LocalBluetoothManager.getInstance(getActivity());
if (mLocalManager == null) {
- finish();
+ Log.e(TAG, "Bluetooth is not supported on this device");
+ return;
}
+ mLocalAdapter = mLocalManager.getBluetoothAdapter();
- mFilterType = BluetoothDevicePicker.FILTER_TYPE_ALL;
-
- if (getPreferenceScreen() != null) getPreferenceScreen().removeAll();
-
- addPreferencesForActivity(activity);
+ addPreferencesForActivity();
mDeviceList = (PreferenceCategory) findPreference(KEY_BT_DEVICE_LIST);
-
- super.onActivityCreated(savedInstanceState);
+ if (mDeviceList == null) {
+ Log.e(TAG, "Could not find device list preference object!");
+ }
}
/** Add preferences from the subclass. */
- abstract void addPreferencesForActivity(Activity activity);
+ abstract void addPreferencesForActivity();
@Override
public void onResume() {
super.onResume();
- mLocalManager.registerCallback(this);
-
- updateProgressUi(mLocalManager.getBluetoothAdapter().isDiscovering());
-
- IntentFilter intentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
- getActivity().registerReceiver(mReceiver, intentFilter);
mLocalManager.setForegroundActivity(getActivity());
+ mLocalManager.getEventManager().registerCallback(this);
+
+ updateProgressUi(mLocalAdapter.isDiscovering());
}
@Override
public void onPause() {
super.onPause();
- mLocalManager.stopScanning();
+
+ mLocalAdapter.stopScanning();
mLocalManager.setForegroundActivity(null);
+ mLocalManager.getEventManager().unregisterCallback(this);
+
mDevicePreferenceMap.clear();
mDeviceList.removeAll();
- getActivity().unregisterReceiver(mReceiver);
-
- mLocalManager.unregisterCallback(this);
}
void addDevices() {
- List<CachedBluetoothDevice> cachedDevices =
+ Collection<CachedBluetoothDevice> cachedDevices =
mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
for (CachedBluetoothDevice cachedDevice : cachedDevices) {
onDeviceAdded(cachedDevice);
}
}
- public void onClick(View v) {
- // User clicked on advanced options icon for a device in the list
- if (v.getTag() instanceof CachedBluetoothDevice) {
- CachedBluetoothDevice device = (CachedBluetoothDevice) v.getTag();
- device.onClickedAdvancedOptions(this);
- }
- }
-
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
if (KEY_BT_SCAN.equals(preference.getKey())) {
- mLocalManager.startScanning(true);
+ mLocalAdapter.startScanning(true);
return true;
}
@@ -162,7 +143,7 @@ public abstract class DeviceListPreferenceFragment extends SettingsPreferenceFra
}
void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
- btPreference.getCachedDevice().onClicked();
+ btPreference.onClicked();
}
public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
@@ -171,71 +152,11 @@ public abstract class DeviceListPreferenceFragment extends SettingsPreferenceFra
return;
}
- if (addDevicePreference(cachedDevice)) {
+ if (mFilter.matches(cachedDevice.getDevice())) {
createDevicePreference(cachedDevice);
}
}
- /**
- * Determine whether to add the new device to the list.
- * @param cachedDevice the newly discovered device
- * @return true if the device should be added; false otherwise
- */
- boolean addDevicePreference(CachedBluetoothDevice cachedDevice) {
- ParcelUuid[] uuids = cachedDevice.getDevice().getUuids();
- BluetoothClass bluetoothClass = cachedDevice.getDevice().getBluetoothClass();
-
- switch(mFilterType) {
- case BluetoothDevicePicker.FILTER_TYPE_TRANSFER:
- if (uuids != null) {
- if (BluetoothUuid.containsAnyUuid(uuids,
- LocalBluetoothProfileManager.OPP_PROFILE_UUIDS)) return true;
- }
- if (bluetoothClass != null
- && bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_OPP)) {
- return true;
- }
- break;
- case BluetoothDevicePicker.FILTER_TYPE_AUDIO:
- if (uuids != null) {
- if (BluetoothUuid.containsAnyUuid(uuids,
- LocalBluetoothProfileManager.A2DP_SINK_PROFILE_UUIDS)) return true;
-
- if (BluetoothUuid.containsAnyUuid(uuids,
- LocalBluetoothProfileManager.HEADSET_PROFILE_UUIDS)) return true;
- } else if (bluetoothClass != null) {
- if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) return true;
-
- if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) return true;
- }
- break;
- case BluetoothDevicePicker.FILTER_TYPE_PANU:
- if (uuids != null) {
- if (BluetoothUuid.containsAnyUuid(uuids,
- LocalBluetoothProfileManager.PANU_PROFILE_UUIDS)) return true;
-
- }
- if (bluetoothClass != null
- && bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_PANU)) {
- return true;
- }
- break;
- case BluetoothDevicePicker.FILTER_TYPE_NAP:
- if (uuids != null) {
- if (BluetoothUuid.containsAnyUuid(uuids,
- LocalBluetoothProfileManager.NAP_PROFILE_UUIDS)) return true;
- }
- if (bluetoothClass != null
- && bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_NAP)) {
- return true;
- }
- break;
- default:
- return true;
- }
- return false;
- }
-
void createDevicePreference(CachedBluetoothDevice cachedDevice) {
BluetoothDevicePreference preference = new BluetoothDevicePreference(
getActivity(), cachedDevice);
@@ -252,7 +173,8 @@ public abstract class DeviceListPreferenceFragment extends SettingsPreferenceFra
void initDevicePreference(BluetoothDevicePreference preference) { }
public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
- BluetoothDevicePreference preference = mDevicePreferenceMap.remove(cachedDevice);
+ BluetoothDevicePreference preference = mDevicePreferenceMap.remove(
+ cachedDevice);
if (preference != null) {
mDeviceList.removePreference(preference);
}
@@ -268,15 +190,9 @@ public abstract class DeviceListPreferenceFragment extends SettingsPreferenceFra
}
}
- void onBluetoothStateChanged(int bluetoothState) {
+ public void onBluetoothStateChanged(int bluetoothState) {
if (bluetoothState == BluetoothAdapter.STATE_OFF) {
updateProgressUi(false);
}
}
-
- void sendDevicePickedIntent(BluetoothDevice device) {
- Intent intent = new Intent(BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
- getActivity().sendBroadcast(intent);
- }
}
diff --git a/src/com/android/settings/bluetooth/DevicePickerActivity.java b/src/com/android/settings/bluetooth/DevicePickerActivity.java
index c29fafb64..8f6e0dfe3 100644
--- a/src/com/android/settings/bluetooth/DevicePickerActivity.java
+++ b/src/com/android/settings/bluetooth/DevicePickerActivity.java
@@ -25,7 +25,7 @@ import android.os.Bundle;
* Activity for Bluetooth device picker dialog. The device picker logic
* is implemented in the {@link BluetoothSettings} fragment.
*/
-public class DevicePickerActivity extends Activity {
+public final class DevicePickerActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
diff --git a/src/com/android/settings/bluetooth/DevicePickerFragment.java b/src/com/android/settings/bluetooth/DevicePickerFragment.java
index d3e3d6925..126df022c 100644
--- a/src/com/android/settings/bluetooth/DevicePickerFragment.java
+++ b/src/com/android/settings/bluetooth/DevicePickerFragment.java
@@ -16,12 +16,11 @@
package com.android.settings.bluetooth;
-import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothDevicePicker;
import android.content.Intent;
-import android.util.Log;
+import android.os.Bundle;
import com.android.settings.R;
@@ -29,36 +28,42 @@ import com.android.settings.R;
* BluetoothSettings is the Settings screen for Bluetooth configuration and
* connection management.
*/
-public class DevicePickerFragment extends DeviceListPreferenceFragment {
-
- private static final String TAG = "BluetoothDevicePicker";
+public final class DevicePickerFragment extends DeviceListPreferenceFragment {
private boolean mNeedAuth;
private String mLaunchPackage;
private String mLaunchClass;
- void addPreferencesForActivity(Activity activity) {
- Intent intent = activity.getIntent();
+ @Override
+ void addPreferencesForActivity() {
+ addPreferencesFromResource(R.xml.device_picker);
+
+ Intent intent = getActivity().getIntent();
mNeedAuth = intent.getBooleanExtra(BluetoothDevicePicker.EXTRA_NEED_AUTH, false);
- mFilterType = intent.getIntExtra(BluetoothDevicePicker.EXTRA_FILTER_TYPE,
- BluetoothDevicePicker.FILTER_TYPE_ALL);
+ setFilter(intent.getIntExtra(BluetoothDevicePicker.EXTRA_FILTER_TYPE,
+ BluetoothDevicePicker.FILTER_TYPE_ALL));
mLaunchPackage = intent.getStringExtra(BluetoothDevicePicker.EXTRA_LAUNCH_PACKAGE);
mLaunchClass = intent.getStringExtra(BluetoothDevicePicker.EXTRA_LAUNCH_CLASS);
+ }
- activity.setTitle(activity.getString(R.string.device_picker));
- addPreferencesFromResource(R.xml.device_picker);
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getActivity().setTitle(getString(R.string.device_picker));
}
@Override
public void onResume() {
super.onResume();
addDevices();
- mLocalManager.startScanning(true);
+ mLocalAdapter.startScanning(true);
}
+ @Override
void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
- mLocalManager.stopScanning();
- mLocalManager.persistSelectedDeviceInPicker(mSelectedDevice.getAddress());
+ mLocalAdapter.stopScanning();
+ LocalBluetoothPreferences.persistSelectedDeviceInPicker(
+ getActivity(), mSelectedDevice.getAddress());
if ((btPreference.getCachedDevice().getBondState() ==
BluetoothDevice.BOND_BONDED) || !mNeedAuth) {
sendDevicePickedIntent(mSelectedDevice);
@@ -79,15 +84,16 @@ public class DevicePickerFragment extends DeviceListPreferenceFragment {
}
}
- void onBluetoothStateChanged(int bluetoothState) {
+ @Override
+ public void onBluetoothStateChanged(int bluetoothState) {
super.onBluetoothStateChanged(bluetoothState);
if (bluetoothState == BluetoothAdapter.STATE_ON) {
- mLocalManager.startScanning(false);
+ mLocalAdapter.startScanning(false);
}
}
- void sendDevicePickedIntent(BluetoothDevice device) {
+ private void sendDevicePickedIntent(BluetoothDevice device) {
Intent intent = new Intent(BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
if (mLaunchPackage != null && mLaunchClass != null) {
diff --git a/src/com/android/settings/bluetooth/DeviceProfilesSettings.java b/src/com/android/settings/bluetooth/DeviceProfilesSettings.java
index f39eabdc4..307125cb5 100644
--- a/src/com/android/settings/bluetooth/DeviceProfilesSettings.java
+++ b/src/com/android/settings/bluetooth/DeviceProfilesSettings.java
@@ -16,15 +16,12 @@
package com.android.settings.bluetooth;
-import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
-
-import android.bluetooth.BluetoothClass;
+import android.app.AlertDialog;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothUuid;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.content.DialogInterface;
import android.os.Bundle;
-import android.os.ParcelUuid;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.Preference;
@@ -34,6 +31,9 @@ import android.text.TextUtils;
import android.util.Log;
import android.view.View;
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+
import java.util.HashMap;
/**
@@ -41,7 +41,7 @@ import java.util.HashMap;
* for a particular device, and allows them to be individually connected
* (or disconnected).
*/
-public class DeviceProfilesSettings extends SettingsPreferenceFragment
+public final class DeviceProfilesSettings extends SettingsPreferenceFragment
implements CachedBluetoothDevice.Callback, Preference.OnPreferenceChangeListener,
View.OnClickListener {
private static final String TAG = "DeviceProfilesSettings";
@@ -56,11 +56,15 @@ public class DeviceProfilesSettings extends SettingsPreferenceFragment
private LocalBluetoothManager mManager;
private CachedBluetoothDevice mCachedDevice;
+ private LocalBluetoothProfileManager mProfileManager;
private PreferenceGroup mProfileContainer;
private EditTextPreference mDeviceNamePref;
- private final HashMap<String,CheckBoxPreference> mAutoConnectPrefs
- = new HashMap<String,CheckBoxPreference>();
+
+ private final HashMap<LocalBluetoothProfile, CheckBoxPreference> mAutoConnectPrefs
+ = new HashMap<LocalBluetoothProfile, CheckBoxPreference>();
+
+ private AlertDialog mDisconnectDialog;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -74,51 +78,54 @@ public class DeviceProfilesSettings extends SettingsPreferenceFragment
device = args.getParcelable(EXTRA_DEVICE);
}
+ addPreferencesFromResource(R.xml.bluetooth_device_advanced);
+ getPreferenceScreen().setOrderingAsAdded(false);
+ mProfileContainer = (PreferenceGroup) findPreference(KEY_PROFILE_CONTAINER);
+ mDeviceNamePref = (EditTextPreference) findPreference(KEY_RENAME_DEVICE);
+
if (device == null) {
Log.w(TAG, "Activity started without a remote Bluetooth device");
finish();
- return;
+ return; // TODO: test this failure path
}
mManager = LocalBluetoothManager.getInstance(getActivity());
- mCachedDevice = mManager.getCachedDeviceManager().findDevice(device);
+ CachedBluetoothDeviceManager deviceManager =
+ mManager.getCachedDeviceManager();
+ mProfileManager = mManager.getProfileManager();
+ mCachedDevice = deviceManager.findDevice(device);
if (mCachedDevice == null) {
Log.w(TAG, "Device not found, cannot connect to it");
finish();
- return;
+ return; // TODO: test this failure path
}
- addPreferencesFromResource(R.xml.bluetooth_device_advanced);
- getPreferenceScreen().setOrderingAsAdded(false);
-
- mProfileContainer = (PreferenceGroup) findPreference(KEY_PROFILE_CONTAINER);
-
- mDeviceNamePref = (EditTextPreference) findPreference(KEY_RENAME_DEVICE);
- mDeviceNamePref.setSummary(mCachedDevice.getName());
- mDeviceNamePref.setText(mCachedDevice.getName());
+ String deviceName = mCachedDevice.getName();
+ mDeviceNamePref.setSummary(deviceName);
+ mDeviceNamePref.setText(deviceName);
mDeviceNamePref.setOnPreferenceChangeListener(this);
// Set the title of the screen
- findPreference(KEY_TITLE).setTitle(getResources()
- .getString(R.string.bluetooth_device_advanced_title, mCachedDevice.getName()));
+ findPreference(KEY_TITLE).setTitle(
+ getString(R.string.bluetooth_device_advanced_title,
+ deviceName));
// Add a preference for each profile
addPreferencesForProfiles();
}
- private boolean isObjectPushSupported(BluetoothDevice device) {
- ParcelUuid[] uuids = device.getUuids();
- BluetoothClass bluetoothClass = device.getBluetoothClass();
- return (uuids != null && BluetoothUuid.containsAnyUuid(uuids,
- LocalBluetoothProfileManager.OPP_PROFILE_UUIDS)) ||
- (bluetoothClass != null && bluetoothClass.doesClassMatch(
- BluetoothClass.PROFILE_OPP));
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (mDisconnectDialog != null) {
+ mDisconnectDialog.dismiss();
+ mDisconnectDialog = null;
+ }
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
-
outState.putParcelable(EXTRA_DEVICE, mCachedDevice.getDevice());
}
@@ -141,7 +148,7 @@ public class DeviceProfilesSettings extends SettingsPreferenceFragment
}
private void addPreferencesForProfiles() {
- for (Profile profile : mCachedDevice.getConnectableProfiles()) {
+ for (LocalBluetoothProfile profile : mCachedDevice.getConnectableProfiles()) {
Preference pref = createProfilePreference(profile);
mProfileContainer.addPreference(pref);
}
@@ -155,21 +162,18 @@ public class DeviceProfilesSettings extends SettingsPreferenceFragment
* @return A preference that allows the user to choose whether this profile
* will be connected to.
*/
- private Preference createProfilePreference(Profile profile) {
+ private Preference createProfilePreference(LocalBluetoothProfile profile) {
BluetoothProfilePreference pref = new BluetoothProfilePreference(getActivity(), profile);
pref.setKey(profile.toString());
- pref.setTitle(profile.localizedString);
+ pref.setTitle(profile.getNameResource());
pref.setExpanded(false);
pref.setPersistent(false);
- pref.setOrder(getProfilePreferenceIndex(profile));
+ pref.setOrder(getProfilePreferenceIndex(profile.getOrdinal()));
pref.setOnExpandClickListener(this);
- LocalBluetoothProfileManager profileManager =
- LocalBluetoothProfileManager.getProfileManager(mManager, profile);
- int iconResource = profileManager.getDrawableResource();
+ int iconResource = profile.getDrawableResource(null); // FIXME: get BT class for this?
if (iconResource != 0) {
- pref.setProfileDrawable(mManager.getContext()
- .getResources().getDrawable(iconResource));
+ pref.setProfileDrawable(getResources().getDrawable(iconResource));
}
/**
@@ -186,7 +190,7 @@ public class DeviceProfilesSettings extends SettingsPreferenceFragment
public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
String key = preference.getKey();
if (preference instanceof BluetoothProfilePreference) {
- onProfileClicked(Profile.valueOf(key));
+ onProfileClicked(mProfileManager.getProfileByName(key));
return true;
} else if (key.equals(KEY_UNPAIR)) {
unpairDevice();
@@ -194,7 +198,7 @@ public class DeviceProfilesSettings extends SettingsPreferenceFragment
return true;
}
- return false;
+ return super.onPreferenceTreeClick(screen, preference);
}
public boolean onPreferenceChange(Preference preference, Object newValue) {
@@ -202,10 +206,8 @@ public class DeviceProfilesSettings extends SettingsPreferenceFragment
mCachedDevice.setName((String) newValue);
} else if (preference instanceof CheckBoxPreference) {
boolean autoConnect = (Boolean) newValue;
- Profile prof = getProfileOf(preference);
- LocalBluetoothProfileManager
- .getProfileManager(mManager, prof)
- .setPreferred(mCachedDevice.getDevice(),
+ LocalBluetoothProfile prof = getProfileOf(preference);
+ prof.setPreferred(mCachedDevice.getDevice(),
autoConnect);
return true;
} else {
@@ -215,20 +217,44 @@ public class DeviceProfilesSettings extends SettingsPreferenceFragment
return true;
}
- private void onProfileClicked(Profile profile) {
+ private void onProfileClicked(LocalBluetoothProfile profile) {
BluetoothDevice device = mCachedDevice.getDevice();
- LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
- .getProfileManager(mManager, profile);
- int status = profileManager.getConnectionStatus(device);
+ int status = profile.getConnectionStatus(device);
boolean isConnected =
- SettingsBtStatus.isConnectionStatusConnected(status);
+ status == BluetoothProfile.STATE_CONNECTED;
if (isConnected) {
- mCachedDevice.askDisconnect(profile);
+ askDisconnect(getActivity(), profile);
} else {
- mCachedDevice.connect(profile);
+ mCachedDevice.connectProfile(profile);
+ }
+ }
+
+ private void askDisconnect(Context context,
+ final LocalBluetoothProfile profile) {
+ // local reference for callback
+ final CachedBluetoothDevice device = mCachedDevice;
+ String name = device.getName();
+ if (TextUtils.isEmpty(name)) {
+ name = context.getString(R.string.bluetooth_device);
+ }
+ int disconnectMessage = profile.getDisconnectResource();
+ if (disconnectMessage == 0) {
+ Log.w(TAG, "askDisconnect: unexpected profile " + profile);
+ disconnectMessage = R.string.bluetooth_disconnect_blank;
}
+ String message = context.getString(disconnectMessage, name);
+
+ DialogInterface.OnClickListener disconnectListener =
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ device.disconnect(profile);
+ }
+ };
+
+ mDisconnectDialog = Utils.showDisconnectDialog(context,
+ mDisconnectDialog, disconnectListener, name, message);
}
public void onDeviceAttributesChanged() {
@@ -242,7 +268,7 @@ public class DeviceProfilesSettings extends SettingsPreferenceFragment
// transaction.setBreadCrumbTitle(deviceName);
// transaction.commit();
- findPreference(KEY_TITLE).setTitle(getResources().getString(
+ findPreference(KEY_TITLE).setTitle(getString(
R.string.bluetooth_device_advanced_title,
deviceName));
mDeviceNamePref = (EditTextPreference) findPreference(KEY_RENAME_DEVICE);
@@ -253,7 +279,7 @@ public class DeviceProfilesSettings extends SettingsPreferenceFragment
}
private void refreshProfiles() {
- for (Profile profile : mCachedDevice.getConnectableProfiles()) {
+ for (LocalBluetoothProfile profile : mCachedDevice.getConnectableProfiles()) {
Preference profilePref = findPreference(profile.toString());
if (profilePref == null) {
profilePref = createProfilePreference(profile);
@@ -264,78 +290,43 @@ public class DeviceProfilesSettings extends SettingsPreferenceFragment
}
}
- private void refreshProfilePreference(Preference profilePref, Profile profile) {
+ private void refreshProfilePreference(Preference profilePref, LocalBluetoothProfile profile) {
BluetoothDevice device = mCachedDevice.getDevice();
- LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
- .getProfileManager(mManager, profile);
-
- int connectionStatus = profileManager.getConnectionStatus(device);
/*
* Gray out checkbox while connecting and disconnecting
*/
profilePref.setEnabled(!mCachedDevice.isBusy());
- profilePref.setSummary(getProfileSummary(profileManager, profile, device,
- connectionStatus, isDeviceOnline()));
- // TODO:
- //profilePref.setChecked(profileManager.isPreferred(device));
+ profilePref.setSummary(profile.getSummaryResourceForDevice(device));
}
- private Profile getProfileOf(Preference pref) {
- if (!(pref instanceof CheckBoxPreference)) return null;
+ private LocalBluetoothProfile getProfileOf(Preference pref) {
+ if (!(pref instanceof CheckBoxPreference)) {
+ return null;
+ }
String key = pref.getKey();
if (TextUtils.isEmpty(key)) return null;
try {
- return Profile.valueOf(pref.getKey());
- } catch (IllegalArgumentException e) {
+ return mProfileManager.getProfileByName(pref.getKey());
+ } catch (IllegalArgumentException ignored) {
return null;
}
}
- private static int getProfileSummary(LocalBluetoothProfileManager profileManager,
- Profile profile, BluetoothDevice device, int connectionStatus, boolean onlineMode) {
- if (!onlineMode || connectionStatus == SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED) {
- return getProfileSummaryForSettingPreference(profile);
- } else {
- return profileManager.getSummary(device);
- }
- }
-
- /**
- * Gets the summary that describes when checked, it will become a preferred profile.
- *
- * @param profile The profile to get the summary for.
- * @return The summary.
- */
- private static final int getProfileSummaryForSettingPreference(Profile profile) {
- switch (profile) {
- case A2DP:
- return R.string.bluetooth_a2dp_profile_summary_use_for;
- case HEADSET:
- return R.string.bluetooth_headset_profile_summary_use_for;
- case HID:
- return R.string.bluetooth_hid_profile_summary_use_for;
- case PAN:
- return R.string.bluetooth_pan_profile_summary_use_for;
- default:
- return 0;
- }
- }
-
public void onClick(View v) {
- if (v.getTag() instanceof Profile) {
- Profile prof = (Profile) v.getTag();
- CheckBoxPreference autoConnectPref = mAutoConnectPrefs.get(prof.toString());
+ if (v.getTag() instanceof LocalBluetoothProfile) {
+ LocalBluetoothProfile prof = (LocalBluetoothProfile) v.getTag();
+ CheckBoxPreference autoConnectPref = mAutoConnectPrefs.get(prof);
if (autoConnectPref == null) {
autoConnectPref = new CheckBoxPreference(getActivity());
autoConnectPref.setLayoutResource(com.android.internal.R.layout.preference_child);
autoConnectPref.setKey(prof.toString());
autoConnectPref.setTitle(R.string.bluetooth_auto_connect);
- autoConnectPref.setOrder(getProfilePreferenceIndex(prof) + 1);
+ autoConnectPref.setOrder(getProfilePreferenceIndex(prof.getOrdinal()) + 1);
autoConnectPref.setChecked(getAutoConnect(prof));
autoConnectPref.setOnPreferenceChangeListener(this);
- mAutoConnectPrefs.put(prof.name(), autoConnectPref);
+ mAutoConnectPrefs.put(prof, autoConnectPref);
}
BluetoothProfilePreference profilePref =
(BluetoothProfilePreference) findPreference(prof.toString());
@@ -349,19 +340,14 @@ public class DeviceProfilesSettings extends SettingsPreferenceFragment
}
}
- private int getProfilePreferenceIndex(Profile prof) {
- return mProfileContainer.getOrder() + prof.ordinal() * 10;
+ private int getProfilePreferenceIndex(int profIndex) {
+ return mProfileContainer.getOrder() + profIndex * 10;
}
private void unpairDevice() {
mCachedDevice.unpair();
}
- private boolean isDeviceOnline() {
- // TODO: Verify
- return mCachedDevice.isConnected() || mCachedDevice.isBusy();
- }
-
private void setIncomingFileTransfersAllowed(boolean allow) {
// TODO: make an IPC call into BluetoothOpp to update
Log.d(TAG, "Set allow incoming = " + allow);
@@ -372,8 +358,7 @@ public class DeviceProfilesSettings extends SettingsPreferenceFragment
return true;
}
- private boolean getAutoConnect(Profile prof) {
- return LocalBluetoothProfileManager.getProfileManager(mManager, prof)
- .isPreferred(mCachedDevice.getDevice());
+ private boolean getAutoConnect(LocalBluetoothProfile prof) {
+ return prof.isPreferred(mCachedDevice.getDevice());
}
}
diff --git a/src/com/android/settings/bluetooth/DockEventReceiver.java b/src/com/android/settings/bluetooth/DockEventReceiver.java
index 041099813..6ecbef63a 100644
--- a/src/com/android/settings/bluetooth/DockEventReceiver.java
+++ b/src/com/android/settings/bluetooth/DockEventReceiver.java
@@ -28,7 +28,7 @@ import android.content.Intent;
import android.os.PowerManager;
import android.util.Log;
-public class DockEventReceiver extends BroadcastReceiver {
+public final class DockEventReceiver extends BroadcastReceiver {
private static final boolean DEBUG = DockService.DEBUG;
@@ -39,11 +39,9 @@ public class DockEventReceiver extends BroadcastReceiver {
private static final int EXTRA_INVALID = -1234;
- private static final Object mStartingServiceSync = new Object();
+ private static final Object sStartingServiceSync = new Object();
- private static final long WAKELOCK_TIMEOUT = 5000;
-
- private static PowerManager.WakeLock mStartingService;
+ private static PowerManager.WakeLock sStartingService;
@Override
public void onReceive(Context context, Intent intent) {
@@ -75,7 +73,7 @@ public class DockEventReceiver extends BroadcastReceiver {
beginStartingService(context, i);
break;
default:
- if (DEBUG) Log.e(TAG, "Unknown state");
+ Log.e(TAG, "Unknown state: " + state);
break;
}
} else if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction()) ||
@@ -118,15 +116,15 @@ public class DockEventReceiver extends BroadcastReceiver {
* Start the service to process the current event notifications, acquiring
* the wake lock before returning to ensure that the service will run.
*/
- public static void beginStartingService(Context context, Intent intent) {
- synchronized (mStartingServiceSync) {
- if (mStartingService == null) {
+ private static void beginStartingService(Context context, Intent intent) {
+ synchronized (sStartingServiceSync) {
+ if (sStartingService == null) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mStartingService = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ sStartingService = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"StartingDockService");
}
- mStartingService.acquire(WAKELOCK_TIMEOUT);
+ sStartingService.acquire();
if (context.startService(intent) == null) {
Log.e(TAG, "Can't start DockService");
@@ -139,10 +137,13 @@ public class DockEventReceiver extends BroadcastReceiver {
* releasing the wake lock if the service is now stopping.
*/
public static void finishStartingService(Service service, int startId) {
- synchronized (mStartingServiceSync) {
- if (mStartingService != null) {
- if (DEBUG) Log.d(TAG, "stopSelf id = "+ startId);
- service.stopSelfResult(startId);
+ synchronized (sStartingServiceSync) {
+ if (sStartingService != null) {
+ if (DEBUG) Log.d(TAG, "stopSelf id = " + startId);
+ if (service.stopSelfResult(startId)) {
+ Log.d(TAG, "finishStartingService: stopping service");
+ sStartingService.release();
+ }
}
}
}
diff --git a/src/com/android/settings/bluetooth/DockService.java b/src/com/android/settings/bluetooth/DockService.java
index 810465238..b45770658 100644
--- a/src/com/android/settings/bluetooth/DockService.java
+++ b/src/com/android/settings/bluetooth/DockService.java
@@ -17,7 +17,6 @@
package com.android.settings.bluetooth;
import com.android.settings.R;
-import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
import com.android.settings.bluetooth.LocalBluetoothProfileManager.ServiceListener;
import android.app.AlertDialog;
@@ -27,7 +26,7 @@ import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
-import android.content.Context;
+import android.bluetooth.BluetoothProfile;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
@@ -44,12 +43,11 @@ import android.view.WindowManager;
import android.widget.CheckBox;
import android.widget.CompoundButton;
+import java.util.Collection;
import java.util.List;
import java.util.Set;
-public class DockService extends Service implements AlertDialog.OnMultiChoiceClickListener,
- DialogInterface.OnClickListener, DialogInterface.OnDismissListener,
- CompoundButton.OnCheckedChangeListener, ServiceListener {
+public final class DockService extends Service implements ServiceListener {
private static final String TAG = "DockService";
@@ -82,14 +80,11 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
private static final String SHARED_PREFERENCES_NAME = "dock_settings";
- private static final String SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED =
- "disable_bt_when_undock";
+ private static final String KEY_DISABLE_BT_WHEN_UNDOCKED = "disable_bt_when_undock";
- private static final String SHARED_PREFERENCES_KEY_DISABLE_BT =
- "disable_bt";
+ private static final String KEY_DISABLE_BT = "disable_bt";
- private static final String SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT =
- "connect_retry_count";
+ private static final String KEY_CONNECT_RETRY_COUNT = "connect_retry_count";
/*
* If disconnected unexpectedly, reconnect up to 6 times. Each profile counts
@@ -103,8 +98,9 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private Runnable mRunnable;
- private DockService mContext;
- private LocalBluetoothManager mBtManager;
+ private LocalBluetoothAdapter mLocalAdapter;
+ private CachedBluetoothDeviceManager mDeviceManager;
+ private LocalBluetoothProfileManager mProfileManager;
// Normally set after getting a docked event and unset when the connection
// is severed. One exception is that mDevice could be null if the service
@@ -113,7 +109,7 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
// Created and used for the duration of the dialog
private AlertDialog mDialog;
- private Profile[] mProfiles;
+ private LocalBluetoothProfile[] mProfiles;
private boolean[] mCheckedItems;
private int mStartIdAssociatedWithDialog;
@@ -127,8 +123,19 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
public void onCreate() {
if (DEBUG) Log.d(TAG, "onCreate");
- mBtManager = LocalBluetoothManager.getInstance(this);
- mContext = this;
+ LocalBluetoothManager manager = LocalBluetoothManager.getInstance(this);
+ if (manager == null) {
+ Log.e(TAG, "Can't get LocalBluetoothManager: exiting");
+ return;
+ }
+
+ mLocalAdapter = manager.getBluetoothAdapter();
+ mDeviceManager = manager.getCachedDeviceManager();
+ mProfileManager = manager.getProfileManager();
+ if (mProfileManager == null) {
+ Log.e(TAG, "Can't get LocalBluetoothProfileManager: exiting");
+ return;
+ }
HandlerThread thread = new HandlerThread("DockService");
thread.start();
@@ -141,12 +148,22 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
public void onDestroy() {
if (DEBUG) Log.d(TAG, "onDestroy");
mRunnable = null;
- LocalBluetoothProfileManager.removeServiceListener(this);
if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
}
- mServiceLooper.quit();
+ if (mProfileManager != null) {
+ mProfileManager.removeServiceListener(this);
+ }
+ if (mServiceLooper != null) {
+ mServiceLooper.quit();
+ }
+
+ mLocalAdapter = null;
+ mDeviceManager = null;
+ mProfileManager = null;
+ mServiceLooper = null;
+ mServiceHandler = null;
}
@Override
@@ -155,9 +172,13 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
return null;
}
+ private SharedPreferences getPrefs() {
+ return getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE);
+ }
+
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
- if (DEBUG) Log.d(TAG, "onStartCommand startId:" + startId + " flags: " + flags);
+ if (DEBUG) Log.d(TAG, "onStartCommand startId: " + startId + " flags: " + flags);
if (intent == null) {
// Nothing to process, stop.
@@ -178,24 +199,24 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
* This assumes that the intent sender has checked that this is a dock
* and that the intent is for a disconnect
*/
+ final SharedPreferences prefs = getPrefs();
if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
BluetoothDevice disconnectedDevice = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-
- int retryCount = getSettingInt(SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT, 0);
+ int retryCount = prefs.getInt(KEY_CONNECT_RETRY_COUNT, 0);
if (retryCount < MAX_CONNECT_RETRY) {
- setSettingInt(SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT, retryCount + 1);
- handleUnexpectedDisconnect(disconnectedDevice, Profile.HEADSET, startId);
+ prefs.edit().putInt(KEY_CONNECT_RETRY_COUNT, retryCount + 1).apply();
+ handleUnexpectedDisconnect(disconnectedDevice, mProfileManager.getHeadsetProfile(), startId);
}
return START_NOT_STICKY;
} else if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
BluetoothDevice disconnectedDevice = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- int retryCount = getSettingInt(SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT, 0);
+ int retryCount = prefs.getInt(KEY_CONNECT_RETRY_COUNT, 0);
if (retryCount < MAX_CONNECT_RETRY) {
- setSettingInt(SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT, retryCount + 1);
- handleUnexpectedDisconnect(disconnectedDevice, Profile.A2DP, startId);
+ prefs.edit().putInt(KEY_CONNECT_RETRY_COUNT, retryCount + 1).apply();
+ handleUnexpectedDisconnect(disconnectedDevice, mProfileManager.getA2dpProfile(), startId);
}
return START_NOT_STICKY;
}
@@ -209,7 +230,7 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
}
if (msg.what == MSG_TYPE_DOCKED) {
- removeSetting(SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT);
+ prefs.edit().remove(KEY_CONNECT_RETRY_COUNT).apply();
}
msg.arg2 = startId;
@@ -219,7 +240,7 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
}
private final class ServiceHandler extends Handler {
- public ServiceHandler(Looper looper) {
+ private ServiceHandler(Looper looper) {
super(looper);
}
@@ -234,7 +255,6 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
int msgType = msg.what;
final int state = msg.arg1;
final int startId = msg.arg2;
- boolean deferFinishCall = false;
BluetoothDevice device = null;
if (msg.obj != null) {
device = (BluetoothDevice) msg.obj;
@@ -243,102 +263,27 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
if(DEBUG) Log.d(TAG, "processMessage: " + msgType + " state: " + state + " device = "
+ (device == null ? "null" : device.toString()));
+ boolean deferFinishCall = false;
+
switch (msgType) {
case MSG_TYPE_SHOW_UI:
- if (mDialog != null) {
- // Shouldn't normally happen
- mDialog.dismiss();
- mDialog = null;
- }
- mDevice = device;
- createDialog(mContext, mDevice, state, startId);
+ createDialog(device, state, startId);
break;
case MSG_TYPE_DOCKED:
- if (DEBUG) {
- // TODO figure out why hasMsg always returns false if device
- // is supplied
- Log.d(TAG, "1 Has undock perm msg = "
- + mServiceHandler.hasMessages(MSG_TYPE_UNDOCKED_PERMANENT, mDevice));
- Log.d(TAG, "2 Has undock perm msg = "
- + mServiceHandler.hasMessages(MSG_TYPE_UNDOCKED_PERMANENT, device));
- }
-
- mServiceHandler.removeMessages(MSG_TYPE_UNDOCKED_PERMANENT);
- mServiceHandler.removeMessages(MSG_TYPE_DISABLE_BT);
- removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT);
-
- if (!device.equals(mDevice)) {
- if (mDevice != null) {
- // Not expected. Cleanup/undock existing
- handleUndocked(mContext, mBtManager, mDevice);
- }
-
- mDevice = device;
-
- // Register first in case LocalBluetoothProfileManager
- // becomes ready after isManagerReady is called and it
- // would be too late to register a service listener.
- LocalBluetoothProfileManager.addServiceListener(this);
- if (LocalBluetoothProfileManager.isManagerReady()) {
- handleDocked(device, state, startId);
- // Not needed after all
- LocalBluetoothProfileManager.removeServiceListener(this);
- } else {
- final BluetoothDevice d = device;
- mRunnable = new Runnable() {
- public void run() {
- handleDocked(d, state, startId);
- }
- };
- deferFinishCall = true;
- }
- }
+ deferFinishCall = msgTypeDocked(device, state, startId);
break;
case MSG_TYPE_UNDOCKED_PERMANENT:
- // Grace period passed. Disconnect.
- handleUndocked(mContext, mBtManager, device);
-
- if (DEBUG) {
- Log.d(TAG, "DISABLE_BT_WHEN_UNDOCKED = "
- + getSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED));
- }
-
- if (getSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED)) {
- // BT was disabled when we first docked
- if (!hasOtherConnectedDevices(device)) {
- if(DEBUG) Log.d(TAG, "QUEUED BT DISABLE");
- // Queue a delayed msg to disable BT
- Message newMsg = mServiceHandler.obtainMessage(MSG_TYPE_DISABLE_BT, 0,
- startId, null);
- mServiceHandler.sendMessageDelayed(newMsg, DISABLE_BT_GRACE_PERIOD);
- deferFinishCall = true;
- } else {
- // Don't disable BT if something is connected
- removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED);
- }
- }
+ deferFinishCall = msgTypeUndockedPermanent(device, startId);
break;
case MSG_TYPE_UNDOCKED_TEMPORARY:
- // Undocked event received. Queue a delayed msg to sever connection
- Message newMsg = mServiceHandler.obtainMessage(MSG_TYPE_UNDOCKED_PERMANENT, state,
- startId, device);
- mServiceHandler.sendMessageDelayed(newMsg, UNDOCKED_GRACE_PERIOD);
+ msgTypeUndockedTemporary(device, state, startId);
break;
case MSG_TYPE_DISABLE_BT:
- if(DEBUG) Log.d(TAG, "BT DISABLE");
- if (mBtManager.getBluetoothAdapter().disable()) {
- removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED);
- } else {
- // disable() returned an error. Persist a flag to disable BT later
- setSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT, true);
- mPendingTurnOffStartId = startId;
- deferFinishCall = true;
- if(DEBUG) Log.d(TAG, "disable failed. try again later " + startId);
- }
+ deferFinishCall = msgTypeDisableBluetooth(startId);
break;
}
@@ -346,24 +291,127 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
&& !deferFinishCall) {
// NOTE: We MUST not call stopSelf() directly, since we need to
// make sure the wake lock acquired by the Receiver is released.
- DockEventReceiver.finishStartingService(DockService.this, startId);
+ DockEventReceiver.finishStartingService(this, startId);
}
}
- public synchronized boolean hasOtherConnectedDevices(BluetoothDevice dock) {
- List<CachedBluetoothDevice> cachedDevices = mBtManager.getCachedDeviceManager()
- .getCachedDevicesCopy();
- Set<BluetoothDevice> btDevices = mBtManager.getBluetoothAdapter().getBondedDevices();
- if (btDevices == null || cachedDevices == null || btDevices.size() == 0) {
+ private boolean msgTypeDisableBluetooth(int startId) {
+ if (DEBUG) {
+ Log.d(TAG, "BT DISABLE");
+ }
+ final SharedPreferences prefs = getPrefs();
+ if (mLocalAdapter.disable()) {
+ prefs.edit().remove(KEY_DISABLE_BT_WHEN_UNDOCKED).apply();
return false;
+ } else {
+ // disable() returned an error. Persist a flag to disable BT later
+ prefs.edit().putBoolean(KEY_DISABLE_BT, true).apply();
+ mPendingTurnOffStartId = startId;
+ if(DEBUG) {
+ Log.d(TAG, "disable failed. try again later " + startId);
+ }
+ return true;
}
- if(DEBUG) Log.d(TAG, "btDevices = " + btDevices.size());
- if(DEBUG) Log.d(TAG, "cachedDevices = " + cachedDevices.size());
+ }
- for (CachedBluetoothDevice device : cachedDevices) {
- BluetoothDevice btDevice = device.getDevice();
- if (!btDevice.equals(dock) && btDevices.contains(btDevice) && device.isConnected()) {
- if(DEBUG) Log.d(TAG, "connected device = " + device.getName());
+ private void msgTypeUndockedTemporary(BluetoothDevice device, int state,
+ int startId) {
+ // Undocked event received. Queue a delayed msg to sever connection
+ Message newMsg = mServiceHandler.obtainMessage(MSG_TYPE_UNDOCKED_PERMANENT, state,
+ startId, device);
+ mServiceHandler.sendMessageDelayed(newMsg, UNDOCKED_GRACE_PERIOD);
+ }
+
+ private boolean msgTypeUndockedPermanent(BluetoothDevice device, int startId) {
+ // Grace period passed. Disconnect.
+ handleUndocked(device);
+ final SharedPreferences prefs = getPrefs();
+
+ if (DEBUG) {
+ Log.d(TAG, "DISABLE_BT_WHEN_UNDOCKED = "
+ + prefs.getBoolean(KEY_DISABLE_BT_WHEN_UNDOCKED, false));
+ }
+
+ if (prefs.getBoolean(KEY_DISABLE_BT_WHEN_UNDOCKED, false)) {
+ if (hasOtherConnectedDevices(device)) {
+ // Don't disable BT if something is connected
+ prefs.edit().remove(KEY_DISABLE_BT_WHEN_UNDOCKED).apply();
+ } else {
+ // BT was disabled when we first docked
+ if (DEBUG) {
+ Log.d(TAG, "QUEUED BT DISABLE");
+ }
+ // Queue a delayed msg to disable BT
+ Message newMsg = mServiceHandler.obtainMessage(
+ MSG_TYPE_DISABLE_BT, 0, startId, null);
+ mServiceHandler.sendMessageDelayed(newMsg,
+ DISABLE_BT_GRACE_PERIOD);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean msgTypeDocked(BluetoothDevice device, final int state,
+ final int startId) {
+ if (DEBUG) {
+ // TODO figure out why hasMsg always returns false if device
+ // is supplied
+ Log.d(TAG, "1 Has undock perm msg = "
+ + mServiceHandler.hasMessages(MSG_TYPE_UNDOCKED_PERMANENT, mDevice));
+ Log.d(TAG, "2 Has undock perm msg = "
+ + mServiceHandler.hasMessages(MSG_TYPE_UNDOCKED_PERMANENT, device));
+ }
+
+ mServiceHandler.removeMessages(MSG_TYPE_UNDOCKED_PERMANENT);
+ mServiceHandler.removeMessages(MSG_TYPE_DISABLE_BT);
+ getPrefs().edit().remove(KEY_DISABLE_BT).apply();
+
+ if (device != null && !device.equals(mDevice)) {
+ if (mDevice != null) {
+ // Not expected. Cleanup/undock existing
+ handleUndocked(mDevice);
+ }
+
+ mDevice = device;
+
+ // Register first in case LocalBluetoothProfileManager
+ // becomes ready after isManagerReady is called and it
+ // would be too late to register a service listener.
+ mProfileManager.addServiceListener(this);
+ if (mProfileManager.isManagerReady()) {
+ handleDocked(device, state, startId);
+ // Not needed after all
+ mProfileManager.removeServiceListener(this);
+ } else {
+ final BluetoothDevice d = device;
+ mRunnable = new Runnable() {
+ public void run() {
+ handleDocked(d, state, startId); // FIXME: WTF runnable here?
+ }
+ };
+ return true;
+ }
+ }
+ return false;
+ }
+
+ synchronized boolean hasOtherConnectedDevices(BluetoothDevice dock) {
+ Collection<CachedBluetoothDevice> cachedDevices = mDeviceManager.getCachedDevicesCopy();
+ Set<BluetoothDevice> btDevices = mLocalAdapter.getBondedDevices();
+ if (btDevices == null || cachedDevices == null || btDevices.isEmpty()) {
+ return false;
+ }
+ if(DEBUG) {
+ Log.d(TAG, "btDevices = " + btDevices.size());
+ Log.d(TAG, "cachedDeviceUIs = " + cachedDevices.size());
+ }
+
+ for (CachedBluetoothDevice deviceUI : cachedDevices) {
+ BluetoothDevice btDevice = deviceUI.getDevice();
+ if (!btDevice.equals(dock) && btDevices.contains(btDevice) && deviceUI
+ .isConnected()) {
+ if(DEBUG) Log.d(TAG, "connected deviceUI = " + deviceUI.getName());
return true;
}
}
@@ -404,96 +452,128 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
return mServiceHandler.obtainMessage(msgType, state, 0, device);
}
- private boolean createDialog(DockService service, BluetoothDevice device, int state,
- int startId) {
+ private void createDialog(BluetoothDevice device,
+ int state, int startId) {
+ if (mDialog != null) {
+ // Shouldn't normally happen
+ mDialog.dismiss();
+ mDialog = null;
+ }
+ mDevice = device;
switch (state) {
case Intent.EXTRA_DOCK_STATE_CAR:
case Intent.EXTRA_DOCK_STATE_DESK:
break;
default:
- return false;
+ return;
}
startForeground(0, new Notification());
// Device in a new dock.
- boolean firstTime = !mBtManager.hasDockAutoConnectSetting(device.getAddress());
+ boolean firstTime = !LocalBluetoothPreferences.hasDockAutoConnectSetting(this, device.getAddress());
- CharSequence[] items = initBtSettings(service, device, state, firstTime);
+ CharSequence[] items = initBtSettings(device, state, firstTime);
- final AlertDialog.Builder ab = new AlertDialog.Builder(service);
- ab.setTitle(service.getString(R.string.bluetooth_dock_settings_title));
+ final AlertDialog.Builder ab = new AlertDialog.Builder(this);
+ ab.setTitle(getString(R.string.bluetooth_dock_settings_title));
// Profiles
- ab.setMultiChoiceItems(items, mCheckedItems, service);
+ ab.setMultiChoiceItems(items, mCheckedItems, mMultiClickListener);
// Remember this settings
- LayoutInflater inflater = (LayoutInflater) service
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- float pixelScaleFactor = service.getResources().getDisplayMetrics().density;
+ LayoutInflater inflater = (LayoutInflater)
+ getSystemService(LAYOUT_INFLATER_SERVICE);
+ float pixelScaleFactor = getResources().getDisplayMetrics().density;
View view = inflater.inflate(R.layout.remember_dock_setting, null);
CheckBox rememberCheckbox = (CheckBox) view.findViewById(R.id.remember);
// check "Remember setting" by default if no value was saved
- boolean checked = firstTime || mBtManager.getDockAutoConnectSetting(device.getAddress());
+ boolean checked = firstTime || LocalBluetoothPreferences.getDockAutoConnectSetting(this, device.getAddress());
rememberCheckbox.setChecked(checked);
- rememberCheckbox.setOnCheckedChangeListener(this);
+ rememberCheckbox.setOnCheckedChangeListener(mCheckedChangeListener);
int viewSpacingLeft = (int) (14 * pixelScaleFactor);
int viewSpacingRight = (int) (14 * pixelScaleFactor);
ab.setView(view, viewSpacingLeft, 0 /* top */, viewSpacingRight, 0 /* bottom */);
if (DEBUG) {
Log.d(TAG, "Auto connect = "
- + mBtManager.getDockAutoConnectSetting(device.getAddress()));
+ + LocalBluetoothPreferences.getDockAutoConnectSetting(this, device.getAddress()));
}
// Ok Button
- ab.setPositiveButton(service.getString(android.R.string.ok), service);
+ ab.setPositiveButton(getString(android.R.string.ok), mClickListener);
mStartIdAssociatedWithDialog = startId;
mDialog = ab.create();
mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- mDialog.setOnDismissListener(service);
+ mDialog.setOnDismissListener(mDismissListener);
mDialog.show();
- return true;
}
// Called when the individual bt profiles are clicked.
- public void onClick(DialogInterface dialog, int which, boolean isChecked) {
- if (DEBUG) Log.d(TAG, "Item " + which + " changed to " + isChecked);
- mCheckedItems[which] = isChecked;
- }
+ private final DialogInterface.OnMultiChoiceClickListener mMultiClickListener =
+ new DialogInterface.OnMultiChoiceClickListener() {
+ public void onClick(DialogInterface dialog, int which, boolean isChecked) {
+ if (DEBUG) {
+ Log.d(TAG, "Item " + which + " changed to " + isChecked);
+ }
+ mCheckedItems[which] = isChecked;
+ }
+ };
+
// Called when the "Remember" Checkbox is clicked
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- if (DEBUG) Log.d(TAG, "onCheckedChanged: Remember Settings = " + isChecked);
- if (mDevice != null) {
- mBtManager.saveDockAutoConnectSetting(mDevice.getAddress(), isChecked);
- }
- }
+ private final CompoundButton.OnCheckedChangeListener mCheckedChangeListener =
+ new CompoundButton.OnCheckedChangeListener() {
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (DEBUG) {
+ Log.d(TAG, "onCheckedChanged: Remember Settings = " + isChecked);
+ }
+ if (mDevice != null) {
+ LocalBluetoothPreferences.saveDockAutoConnectSetting(
+ DockService.this, mDevice.getAddress(), isChecked);
+ }
+ }
+ };
+
// Called when the dialog is dismissed
- public void onDismiss(DialogInterface dialog) {
- // NOTE: We MUST not call stopSelf() directly, since we need to
- // make sure the wake lock acquired by the Receiver is released.
- if (mPendingDevice == null) {
- DockEventReceiver.finishStartingService(mContext, mStartIdAssociatedWithDialog);
- }
- mContext.stopForeground(true);
- }
+ private final DialogInterface.OnDismissListener mDismissListener =
+ new DialogInterface.OnDismissListener() {
+ public void onDismiss(DialogInterface dialog) {
+ // NOTE: We MUST not call stopSelf() directly, since we need to
+ // make sure the wake lock acquired by the Receiver is released.
+ if (mPendingDevice == null) {
+ DockEventReceiver.finishStartingService(
+ DockService.this, mStartIdAssociatedWithDialog);
+ }
+ stopForeground(true);
+ }
+ };
// Called when clicked on the OK button
- public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_POSITIVE && mDevice != null) {
- if (!mBtManager.hasDockAutoConnectSetting(mDevice.getAddress())) {
- mBtManager.saveDockAutoConnectSetting(mDevice.getAddress(), true);
- }
+ private final DialogInterface.OnClickListener mClickListener =
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == DialogInterface.BUTTON_POSITIVE
+ && mDevice != null) {
+ if (!LocalBluetoothPreferences
+ .hasDockAutoConnectSetting(
+ DockService.this,
+ mDevice.getAddress())) {
+ LocalBluetoothPreferences
+ .saveDockAutoConnectSetting(
+ DockService.this,
+ mDevice.getAddress(), true);
+ }
- applyBtSettings(mDevice, mStartIdAssociatedWithDialog);
- }
- }
+ applyBtSettings(mDevice, mStartIdAssociatedWithDialog);
+ }
+ }
+ };
- private CharSequence[] initBtSettings(DockService service, BluetoothDevice device, int state,
- boolean firstTime) {
+ private CharSequence[] initBtSettings(BluetoothDevice device,
+ int state, boolean firstTime) {
// TODO Avoid hardcoding dock and profiles. Read from system properties
int numOfProfiles;
switch (state) {
@@ -507,96 +587,54 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
return null;
}
- mProfiles = new Profile[numOfProfiles];
+ mProfiles = new LocalBluetoothProfile[numOfProfiles];
mCheckedItems = new boolean[numOfProfiles];
CharSequence[] items = new CharSequence[numOfProfiles];
+ // FIXME: convert switch to something else
switch (state) {
case Intent.EXTRA_DOCK_STATE_CAR:
- items[0] = service.getString(R.string.bluetooth_dock_settings_headset);
- items[1] = service.getString(R.string.bluetooth_dock_settings_a2dp);
- mProfiles[0] = Profile.HEADSET;
- mProfiles[1] = Profile.A2DP;
+ items[0] = getString(R.string.bluetooth_dock_settings_headset);
+ items[1] = getString(R.string.bluetooth_dock_settings_a2dp);
+ mProfiles[0] = mProfileManager.getHeadsetProfile();
+ mProfiles[1] = mProfileManager.getA2dpProfile();
if (firstTime) {
// Enable by default for car dock
mCheckedItems[0] = true;
mCheckedItems[1] = true;
} else {
- mCheckedItems[0] = LocalBluetoothProfileManager.getProfileManager(mBtManager,
- Profile.HEADSET).isPreferred(device);
- mCheckedItems[1] = LocalBluetoothProfileManager.getProfileManager(mBtManager,
- Profile.A2DP).isPreferred(device);
+ mCheckedItems[0] = mProfiles[0].isPreferred(device);
+ mCheckedItems[1] = mProfiles[1].isPreferred(device);
}
break;
case Intent.EXTRA_DOCK_STATE_DESK:
- items[0] = service.getString(R.string.bluetooth_dock_settings_a2dp);
- mProfiles[0] = Profile.A2DP;
+ items[0] = getString(R.string.bluetooth_dock_settings_a2dp);
+ mProfiles[0] = mProfileManager.getA2dpProfile();
if (firstTime) {
// Disable by default for desk dock
mCheckedItems[0] = false;
} else {
- mCheckedItems[0] = LocalBluetoothProfileManager.getProfileManager(mBtManager,
- Profile.A2DP).isPreferred(device);
+ mCheckedItems[0] = mProfiles[0].isPreferred(device);
}
break;
}
return items;
}
+ // TODO: move to background thread to fix strict mode warnings
private void handleBtStateChange(Intent intent, int startId) {
int btState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
synchronized (this) {
if(DEBUG) Log.d(TAG, "BtState = " + btState + " mPendingDevice = " + mPendingDevice);
if (btState == BluetoothAdapter.STATE_ON) {
- if (mPendingDevice != null) {
- if (mPendingDevice.equals(mDevice)) {
- if(DEBUG) Log.d(TAG, "applying settings");
- applyBtSettings(mPendingDevice, mPendingStartId);
- } else if(DEBUG) {
- Log.d(TAG, "mPendingDevice (" + mPendingDevice + ") != mDevice ("
- + mDevice + ")");
- }
-
- mPendingDevice = null;
- DockEventReceiver.finishStartingService(mContext, mPendingStartId);
- } else {
- if (DEBUG) {
- Log.d(TAG, "A DISABLE_BT_WHEN_UNDOCKED = "
- + getSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED));
- }
- // Reconnect if docked and bluetooth was enabled by user.
- Intent i = registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT));
- if (i != null) {
- int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE,
- Intent.EXTRA_DOCK_STATE_UNDOCKED);
- if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
- BluetoothDevice device = i
- .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- if (device != null) {
- connectIfEnabled(device);
- }
- } else if (getSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT)
- && mBtManager.getBluetoothAdapter().disable()) {
- mPendingTurnOffStartId = startId;
- removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT);
- return;
- }
- }
- }
-
- if (mPendingTurnOnStartId != INVALID_STARTID) {
- DockEventReceiver.finishStartingService(this, mPendingTurnOnStartId);
- mPendingTurnOnStartId = INVALID_STARTID;
- }
-
- DockEventReceiver.finishStartingService(this, startId);
+ handleBluetoothStateOn(startId);
} else if (btState == BluetoothAdapter.STATE_TURNING_OFF) {
// Remove the flag to disable BT if someone is turning off bt.
// The rational is that:
// a) if BT is off at undock time, no work needs to be done
// b) if BT is on at undock time, the user wants it on.
- removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED);
+ getPrefs().edit().remove(KEY_DISABLE_BT_WHEN_UNDOCKED).apply();
DockEventReceiver.finishStartingService(this, startId);
} else if (btState == BluetoothAdapter.STATE_OFF) {
// Bluetooth was turning off as we were trying to turn it on.
@@ -605,12 +643,12 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
if (mPendingTurnOffStartId != INVALID_STARTID) {
DockEventReceiver.finishStartingService(this, mPendingTurnOffStartId);
- removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT);
+ getPrefs().edit().remove(KEY_DISABLE_BT).apply();
mPendingTurnOffStartId = INVALID_STARTID;
}
if (mPendingDevice != null) {
- mBtManager.getBluetoothAdapter().enable();
+ mLocalAdapter.enable();
mPendingTurnOnStartId = startId;
} else {
DockEventReceiver.finishStartingService(this, startId);
@@ -619,86 +657,124 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
}
}
- private void handleUnexpectedDisconnect(BluetoothDevice disconnectedDevice, Profile profile,
- int startId) {
- synchronized (this) {
- if (DEBUG) Log.d(TAG, "handling failed connect for " + disconnectedDevice);
+ private void handleBluetoothStateOn(int startId) {
+ if (mPendingDevice != null) {
+ if (mPendingDevice.equals(mDevice)) {
+ if(DEBUG) {
+ Log.d(TAG, "applying settings");
+ }
+ applyBtSettings(mPendingDevice, mPendingStartId);
+ } else if(DEBUG) {
+ Log.d(TAG, "mPendingDevice (" + mPendingDevice + ") != mDevice ("
+ + mDevice + ')');
+ }
+
+ mPendingDevice = null;
+ DockEventReceiver.finishStartingService(this, mPendingStartId);
+ } else {
+ final SharedPreferences prefs = getPrefs();
+ if (DEBUG) {
+ Log.d(TAG, "A DISABLE_BT_WHEN_UNDOCKED = "
+ + prefs.getBoolean(KEY_DISABLE_BT_WHEN_UNDOCKED, false));
+ }
+ // Reconnect if docked and bluetooth was enabled by user.
+ Intent i = registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT));
+ if (i != null) {
+ int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE,
+ Intent.EXTRA_DOCK_STATE_UNDOCKED);
+ if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+ BluetoothDevice device = i
+ .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ if (device != null) {
+ connectIfEnabled(device);
+ }
+ } else if (prefs.getBoolean(KEY_DISABLE_BT, false)
+ && mLocalAdapter.disable()) {
+ mPendingTurnOffStartId = startId;
+ prefs.edit().remove(KEY_DISABLE_BT).apply();
+ return;
+ }
+ }
+ }
+
+ if (mPendingTurnOnStartId != INVALID_STARTID) {
+ DockEventReceiver.finishStartingService(this, mPendingTurnOnStartId);
+ mPendingTurnOnStartId = INVALID_STARTID;
+ }
+
+ DockEventReceiver.finishStartingService(this, startId);
+ }
+
+ private synchronized void handleUnexpectedDisconnect(BluetoothDevice disconnectedDevice,
+ LocalBluetoothProfile profile, int startId) {
+ if (DEBUG) {
+ Log.d(TAG, "handling failed connect for " + disconnectedDevice);
+ }
// Reconnect if docked.
if (disconnectedDevice != null) {
// registerReceiver can't be called from a BroadcastReceiver
- Intent i = registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT));
- if (i != null) {
- int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE,
+ Intent intent = registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT));
+ if (intent != null) {
+ int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
Intent.EXTRA_DOCK_STATE_UNDOCKED);
if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
- BluetoothDevice dockedDevice = i
+ BluetoothDevice dockedDevice = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (dockedDevice != null && dockedDevice.equals(disconnectedDevice)) {
- CachedBluetoothDevice cachedDevice = getCachedBluetoothDevice(mContext,
- mBtManager, dockedDevice);
- cachedDevice.connect(profile);
+ CachedBluetoothDevice cachedDevice = getCachedBluetoothDevice(
+ dockedDevice);
+ cachedDevice.connectProfile(profile);
}
}
}
}
DockEventReceiver.finishStartingService(this, startId);
- }
}
private synchronized void connectIfEnabled(BluetoothDevice device) {
- CachedBluetoothDevice cachedDevice = getCachedBluetoothDevice(mContext, mBtManager, device);
- List<Profile> profiles = cachedDevice.getConnectableProfiles();
- for (int i = 0; i < profiles.size(); i++) {
- LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
- .getProfileManager(mBtManager, profiles.get(i));
- int auto;
- if (Profile.A2DP == profiles.get(i)) {
- auto = BluetoothA2dp.PRIORITY_AUTO_CONNECT;
- } else if (Profile.HEADSET == profiles.get(i)) {
- auto = BluetoothHeadset.PRIORITY_AUTO_CONNECT;
- } else {
- continue;
- }
-
- if (profileManager.getPreferred(device) == auto) {
+ CachedBluetoothDevice cachedDevice = getCachedBluetoothDevice(
+ device);
+ List<LocalBluetoothProfile> profiles = cachedDevice.getConnectableProfiles();
+ for (LocalBluetoothProfile profile : profiles) {
+ if (profile.getPreferred(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT) {
cachedDevice.connect(false);
- break;
+ return;
}
}
}
- private synchronized void applyBtSettings(final BluetoothDevice device, int startId) {
- if (device == null || mProfiles == null || mCheckedItems == null)
+ private synchronized void applyBtSettings(BluetoothDevice device, int startId) {
+ if (device == null || mProfiles == null || mCheckedItems == null
+ || mLocalAdapter == null) {
return;
+ }
// Turn on BT if something is enabled
- synchronized (this) {
- for (boolean enable : mCheckedItems) {
- if (enable) {
- int btState = mBtManager.getBluetoothState();
- if(DEBUG) Log.d(TAG, "BtState = " + btState);
- // May have race condition as the phone comes in and out and in the dock.
- // Always turn on BT
- mBtManager.getBluetoothAdapter().enable();
-
- switch (btState) {
- case BluetoothAdapter.STATE_OFF:
- case BluetoothAdapter.STATE_TURNING_OFF:
- case BluetoothAdapter.STATE_TURNING_ON:
- if (mPendingDevice != null && mPendingDevice.equals(mDevice)) {
- return;
- }
-
- mPendingDevice = device;
- mPendingStartId = startId;
- if (btState != BluetoothAdapter.STATE_TURNING_ON) {
- setSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED,
- true);
- }
- return;
+ for (boolean enable : mCheckedItems) {
+ if (enable) {
+ int btState = mLocalAdapter.getBluetoothState();
+ if (DEBUG) {
+ Log.d(TAG, "BtState = " + btState);
+ }
+ // May have race condition as the phone comes in and out and in the dock.
+ // Always turn on BT
+ mLocalAdapter.enable();
+
+ // if adapter was previously OFF, TURNING_OFF, or TURNING_ON
+ if (btState != BluetoothAdapter.STATE_ON) {
+ if (mPendingDevice != null && mPendingDevice.equals(mDevice)) {
+ return;
+ }
+
+ mPendingDevice = device;
+ mPendingStartId = startId;
+ if (btState != BluetoothAdapter.STATE_TURNING_ON) {
+ getPrefs().edit().putBoolean(
+ KEY_DISABLE_BT_WHEN_UNDOCKED, true).apply();
}
+ return;
}
}
}
@@ -706,28 +782,26 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
mPendingDevice = null;
boolean callConnect = false;
- CachedBluetoothDevice cachedDevice = getCachedBluetoothDevice(mContext, mBtManager,
+ CachedBluetoothDevice cachedDevice = getCachedBluetoothDevice(
device);
for (int i = 0; i < mProfiles.length; i++) {
- LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
- .getProfileManager(mBtManager, mProfiles[i]);
-
- if (DEBUG) Log.d(TAG, mProfiles[i].toString() + " = " + mCheckedItems[i]);
+ LocalBluetoothProfile profile = mProfiles[i];
+ if (DEBUG) Log.d(TAG, profile.toString() + " = " + mCheckedItems[i]);
if (mCheckedItems[i]) {
// Checked but not connected
callConnect = true;
} else if (!mCheckedItems[i]) {
// Unchecked, may or may not be connected.
- int status = profileManager.getConnectionStatus(cachedDevice.getDevice());
- if (SettingsBtStatus.isConnectionStatusConnected(status)) {
+ int status = profile.getConnectionStatus(cachedDevice.getDevice());
+ if (status == BluetoothProfile.STATE_CONNECTED) {
if (DEBUG) Log.d(TAG, "applyBtSettings - Disconnecting");
cachedDevice.disconnect(mProfiles[i]);
}
}
- profileManager.setPreferred(device, mCheckedItems[i]);
+ profile.setPreferred(device, mCheckedItems[i]);
if (DEBUG) {
- if (mCheckedItems[i] != profileManager.isPreferred(device)) {
+ if (mCheckedItems[i] != profile.isPreferred(device)) {
Log.e(TAG, "Can't save preferred value");
}
}
@@ -739,84 +813,47 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
}
}
- private synchronized void handleDocked(final BluetoothDevice device, final int state,
- final int startId) {
- if (mBtManager.getDockAutoConnectSetting(device.getAddress())) {
+ private synchronized void handleDocked(BluetoothDevice device, int state,
+ int startId) {
+ if (LocalBluetoothPreferences.getDockAutoConnectSetting(this, device.getAddress())) {
// Setting == auto connect
- initBtSettings(mContext, device, state, false);
+ initBtSettings(device, state, false);
applyBtSettings(mDevice, startId);
} else {
- createDialog(mContext, device, state, startId);
+ createDialog(device, state, startId);
}
}
- private synchronized void handleUndocked(Context context, LocalBluetoothManager localManager,
- BluetoothDevice device) {
+ private synchronized void handleUndocked(BluetoothDevice device) {
mRunnable = null;
- LocalBluetoothProfileManager.removeServiceListener(this);
+ mProfileManager.removeServiceListener(this);
if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
}
mDevice = null;
mPendingDevice = null;
- CachedBluetoothDevice cachedBluetoothDevice = getCachedBluetoothDevice(context,
- localManager, device);
- cachedBluetoothDevice.disconnect();
+ CachedBluetoothDevice cachedDevice = getCachedBluetoothDevice(device);
+ cachedDevice.disconnect();
}
- private static CachedBluetoothDevice getCachedBluetoothDevice(Context context,
- LocalBluetoothManager localManager, BluetoothDevice device) {
- CachedBluetoothDeviceManager cachedDeviceManager = localManager.getCachedDeviceManager();
- CachedBluetoothDevice cachedBluetoothDevice = cachedDeviceManager.findDevice(device);
- if (cachedBluetoothDevice == null) {
- cachedBluetoothDevice = new CachedBluetoothDevice(context, device);
+ private CachedBluetoothDevice getCachedBluetoothDevice(BluetoothDevice device) {
+ CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+ if (cachedDevice == null) {
+ cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
}
- return cachedBluetoothDevice;
- }
-
- private boolean getSettingBool(String key) {
- SharedPreferences sharedPref = getSharedPreferences(SHARED_PREFERENCES_NAME,
- Context.MODE_PRIVATE);
- return sharedPref.getBoolean(key, false);
- }
-
- private int getSettingInt(String key, int defaultValue) {
- SharedPreferences sharedPref = getSharedPreferences(SHARED_PREFERENCES_NAME,
- Context.MODE_PRIVATE);
- return sharedPref.getInt(key, defaultValue);
- }
-
- private void setSettingBool(String key, boolean bool) {
- SharedPreferences.Editor editor = getSharedPreferences(SHARED_PREFERENCES_NAME,
- Context.MODE_PRIVATE).edit();
- editor.putBoolean(key, bool);
- editor.apply();
- }
-
- private void setSettingInt(String key, int value) {
- SharedPreferences.Editor editor = getSharedPreferences(SHARED_PREFERENCES_NAME,
- Context.MODE_PRIVATE).edit();
- editor.putInt(key, value);
- editor.apply();
- }
-
- private void removeSetting(String key) {
- SharedPreferences sharedPref = getSharedPreferences(SHARED_PREFERENCES_NAME,
- Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = sharedPref.edit();
- editor.remove(key);
- editor.apply();
+ return cachedDevice;
}
public synchronized void onServiceConnected() {
if (mRunnable != null) {
mRunnable.run();
mRunnable = null;
- LocalBluetoothProfileManager.removeServiceListener(this);
+ mProfileManager.removeServiceListener(this);
}
}
public void onServiceDisconnected() {
+ // FIXME: shouldn't I do something on service disconnected too?
}
}
diff --git a/src/com/android/settings/bluetooth/HeadsetProfile.java b/src/com/android/settings/bluetooth/HeadsetProfile.java
new file mode 100644
index 000000000..dac47b767
--- /dev/null
+++ b/src/com/android/settings/bluetooth/HeadsetProfile.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.Handler;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.settings.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * HeadsetProfile handles Bluetooth HFP and Headset profiles.
+ */
+final class HeadsetProfile implements LocalBluetoothProfile {
+ private static final String TAG = "HeadsetProfile";
+
+ private BluetoothHeadset mService;
+ private boolean mProfileReady;
+
+ private final LocalBluetoothAdapter mLocalAdapter;
+ private final CachedBluetoothDeviceManager mDeviceManager;
+ private final LocalBluetoothProfileManager mProfileManager;
+
+ static final ParcelUuid[] UUIDS = {
+ BluetoothUuid.HSP,
+ BluetoothUuid.Handsfree,
+ };
+
+ static final String NAME = "HEADSET";
+
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 0;
+
+ // These callbacks run on the main thread.
+ private final class HeadsetServiceListener
+ implements BluetoothProfile.ServiceListener {
+
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ mService = (BluetoothHeadset) proxy;
+ mProfileReady = true;
+ // We just bound to the service, so refresh the UI of the
+ // headset device.
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+ if (deviceList.isEmpty()) {
+ return;
+ }
+ BluetoothDevice firstDevice = deviceList.get(0);
+ CachedBluetoothDevice device = mDeviceManager.findDevice(firstDevice);
+ // we may add a new device here, but generally this should not happen
+ if (device == null) {
+ Log.w(TAG, "HeadsetProfile found new device: " + firstDevice);
+ device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, firstDevice);
+ }
+ device.onProfileStateChanged(HeadsetProfile.this,
+ BluetoothProfile.STATE_CONNECTED);
+
+ mProfileManager.callServiceConnectedListeners();
+ }
+
+ public void onServiceDisconnected(int profile) {
+ mProfileReady = false;
+ mService = null;
+ mProfileManager.callServiceDisconnectedListeners();
+ }
+ }
+
+ // TODO(): The calls must get queued if mService becomes null.
+ // It can happen when the phone app crashes for some reason.
+ // All callers should have service listeners. Dock Service is the only
+ // one right now.
+ HeadsetProfile(Context context, LocalBluetoothAdapter adapter,
+ CachedBluetoothDeviceManager deviceManager,
+ LocalBluetoothProfileManager profileManager) {
+ mLocalAdapter = adapter;
+ mDeviceManager = deviceManager;
+ mProfileManager = profileManager;
+ mLocalAdapter.getProfileProxy(context, new HeadsetServiceListener(),
+ BluetoothProfile.HEADSET);
+ }
+
+ public boolean isConnectable() {
+ return true;
+ }
+
+ public boolean isAutoConnectable() {
+ return true;
+ }
+
+ public boolean connect(BluetoothDevice device) {
+ List<BluetoothDevice> sinks = mService.getConnectedDevices();
+ if (sinks != null) {
+ for (BluetoothDevice sink : sinks) {
+ mService.disconnect(sink);
+ }
+ }
+ return mService.connect(device);
+ }
+
+ public boolean disconnect(BluetoothDevice device) {
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+ if (!deviceList.isEmpty() && deviceList.get(0).equals(device)) {
+ // Downgrade priority as user is disconnecting the headset.
+ if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ return mService.disconnect(device);
+ } else {
+ return false;
+ }
+ }
+
+ public int getConnectionStatus(BluetoothDevice device) {
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+
+ return !deviceList.isEmpty() && deviceList.get(0).equals(device)
+ ? mService.getConnectionState(device)
+ : BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ public boolean isPreferred(BluetoothDevice device) {
+ return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ }
+
+ public int getPreferred(BluetoothDevice device) {
+ return mService.getPriority(device);
+ }
+
+ public void setPreferred(BluetoothDevice device, boolean preferred) {
+ if (preferred) {
+ if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ } else {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ }
+ }
+
+ public synchronized boolean isProfileReady() {
+ return mProfileReady;
+ }
+
+ public String toString() {
+ return NAME;
+ }
+
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ public int getNameResource() {
+ return R.string.bluetooth_profile_headset;
+ }
+
+ public int getDisconnectResource() {
+ return R.string.bluetooth_disconnect_headset_profile;
+ }
+
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ int state = mService.getConnectionState(device);
+ switch (state) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ return R.string.bluetooth_headset_profile_summary_use_for;
+
+ case BluetoothProfile.STATE_CONNECTED:
+ return R.string.bluetooth_headset_profile_summary_connected;
+
+ default:
+ return Utils.getConnectionStateSummary(state);
+ }
+ }
+
+ public int getDrawableResource(BluetoothClass btClass) {
+ return R.drawable.ic_bt_headset_hfp;
+ }
+}
diff --git a/src/com/android/settings/bluetooth/HidProfile.java b/src/com/android/settings/bluetooth/HidProfile.java
new file mode 100644
index 000000000..9185059d6
--- /dev/null
+++ b/src/com/android/settings/bluetooth/HidProfile.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothInputDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settings.R;
+
+import java.util.List;
+
+/**
+ * HidProfile handles Bluetooth HID profile.
+ */
+final class HidProfile implements LocalBluetoothProfile {
+ private BluetoothInputDevice mService;
+ private boolean mProfileReady;
+
+ static final String NAME = "HID";
+
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 3;
+
+ // These callbacks run on the main thread.
+ private final class InputDeviceServiceListener
+ implements BluetoothProfile.ServiceListener {
+
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ mService = (BluetoothInputDevice) proxy;
+ mProfileReady = true;
+ }
+
+ public void onServiceDisconnected(int profile) {
+ mProfileReady = false;
+ mService = null;
+ }
+ }
+
+ HidProfile(Context context, LocalBluetoothAdapter adapter) {
+ adapter.getProfileProxy(context, new InputDeviceServiceListener(),
+ BluetoothProfile.INPUT_DEVICE);
+ }
+
+ public boolean isConnectable() {
+ return true;
+ }
+
+ public boolean isAutoConnectable() {
+ return true;
+ }
+
+ public boolean connect(BluetoothDevice device) {
+ return mService.connect(device);
+ }
+
+ public boolean disconnect(BluetoothDevice device) {
+ return mService.disconnect(device);
+ }
+
+ public int getConnectionStatus(BluetoothDevice device) {
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+
+ return !deviceList.isEmpty() && deviceList.get(0).equals(device)
+ ? mService.getConnectionState(device)
+ : BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ public boolean isPreferred(BluetoothDevice device) {
+ return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ }
+
+ public int getPreferred(BluetoothDevice device) {
+ return mService.getPriority(device);
+ }
+
+ public void setPreferred(BluetoothDevice device, boolean preferred) {
+ if (preferred) {
+ if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ } else {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ }
+ }
+
+ public boolean isProfileReady() {
+ return mProfileReady;
+ }
+
+ public String toString() {
+ return NAME;
+ }
+
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ public int getNameResource() {
+ return R.string.bluetooth_profile_hid;
+ }
+
+ public int getDisconnectResource() {
+ return R.string.bluetooth_disconnect_hid_profile;
+ }
+
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ int state = mService.getConnectionState(device);
+ switch (state) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ return R.string.bluetooth_hid_profile_summary_use_for;
+
+ case BluetoothProfile.STATE_CONNECTED:
+ return R.string.bluetooth_hid_profile_summary_connected;
+
+ default:
+ return Utils.getConnectionStateSummary(state);
+ }
+ }
+
+ public int getDrawableResource(BluetoothClass btClass) {
+ if (btClass == null) {
+ return R.drawable.ic_bt_keyboard_hid;
+ }
+ return getHidClassDrawable(btClass);
+ }
+
+ static int getHidClassDrawable(BluetoothClass btClass) {
+ switch (btClass.getDeviceClass()) {
+ case BluetoothClass.Device.PERIPHERAL_KEYBOARD:
+ case BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING:
+ return R.drawable.ic_bt_keyboard_hid;
+ case BluetoothClass.Device.PERIPHERAL_POINTING:
+ return R.drawable.ic_bt_pointing_hid;
+ default:
+ return R.drawable.ic_bt_misc_hid;
+ }
+ }
+}
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothAdapter.java b/src/com/android/settings/bluetooth/LocalBluetoothAdapter.java
new file mode 100644
index 000000000..013171c14
--- /dev/null
+++ b/src/com/android/settings/bluetooth/LocalBluetoothAdapter.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import java.util.Set;
+
+/**
+ * LocalBluetoothAdapter provides an interface between the Settings app
+ * and the functionality of the local {@link BluetoothAdapter}, specifically
+ * those related to state transitions of the adapter itself.
+ *
+ * <p>Connection and bonding state changes affecting specific devices
+ * are handled by {@link CachedBluetoothDeviceManager},
+ * {@link BluetoothEventManager}, and {@link LocalBluetoothProfileManager}.
+ */
+public final class LocalBluetoothAdapter {
+ private static final String TAG = "LocalBluetoothAdapter";
+
+ /** This class does not allow direct access to the BluetoothAdapter. */
+ private final BluetoothAdapter mAdapter;
+
+ private LocalBluetoothProfileManager mProfileManager;
+
+ private static LocalBluetoothAdapter sInstance;
+
+ private int mState = BluetoothAdapter.ERROR;
+
+ private static final int SCAN_EXPIRATION_MS = 5 * 60 * 1000; // 5 mins
+
+ private long mLastScan;
+
+ private LocalBluetoothAdapter(BluetoothAdapter adapter) {
+ mAdapter = adapter;
+ }
+
+ void setProfileManager(LocalBluetoothProfileManager manager) {
+ mProfileManager = manager;
+ }
+
+ /**
+ * Get the singleton instance of the LocalBluetoothAdapter. If this device
+ * doesn't support Bluetooth, then null will be returned. Callers must be
+ * prepared to handle a null return value.
+ * @return the LocalBluetoothAdapter object, or null if not supported
+ */
+ static synchronized LocalBluetoothAdapter getInstance() {
+ if (sInstance == null) {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null) {
+ sInstance = new LocalBluetoothAdapter(adapter);
+ }
+ }
+
+ return sInstance;
+ }
+
+ // Pass-through BluetoothAdapter methods that we can intercept if necessary
+
+ void cancelDiscovery() {
+ mAdapter.cancelDiscovery();
+ }
+
+ boolean enable() {
+ return mAdapter.enable();
+ }
+
+ boolean disable() {
+ return mAdapter.disable();
+ }
+
+ void getProfileProxy(Context context,
+ BluetoothProfile.ServiceListener listener, int profile) {
+ mAdapter.getProfileProxy(context, listener, profile);
+ }
+
+ Set<BluetoothDevice> getBondedDevices() {
+ return mAdapter.getBondedDevices();
+ }
+
+ String getName() {
+ return mAdapter.getName();
+ }
+
+ int getScanMode() {
+ return mAdapter.getScanMode();
+ }
+
+ int getState() {
+ return mAdapter.getState();
+ }
+
+ ParcelUuid[] getUuids() {
+ return mAdapter.getUuids();
+ }
+
+ boolean isDiscovering() {
+ return mAdapter.isDiscovering();
+ }
+
+ boolean isEnabled() {
+ return mAdapter.isEnabled();
+ }
+
+ void setDiscoverableTimeout(int timeout) {
+ mAdapter.setDiscoverableTimeout(timeout);
+ }
+
+ void setName(String name) {
+ mAdapter.setName(name);
+ }
+
+ void setScanMode(int mode) {
+ mAdapter.setScanMode(mode);
+ }
+
+ boolean setScanMode(int mode, int duration) {
+ return mAdapter.setScanMode(mode, duration);
+ }
+
+ void startScanning(boolean force) {
+ // Only start if we're not already scanning
+ if (!mAdapter.isDiscovering()) {
+ if (!force) {
+ // Don't scan more than frequently than SCAN_EXPIRATION_MS,
+ // unless forced
+ if (mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) {
+ return;
+ }
+
+ // If we are playing music, don't scan unless forced.
+ A2dpProfile a2dp = mProfileManager.getA2dpProfile();
+ if (a2dp != null && a2dp.isA2dpPlaying()) {
+ return;
+ }
+ }
+
+ if (mAdapter.startDiscovery()) {
+ mLastScan = System.currentTimeMillis();
+ }
+ }
+ }
+
+ void stopScanning() {
+ if (mAdapter.isDiscovering()) {
+ mAdapter.cancelDiscovery();
+ }
+ }
+
+ public synchronized int getBluetoothState() {
+ // Always sync state, in case it changed while paused
+ syncBluetoothState();
+ return mState;
+ }
+
+ synchronized void setBluetoothStateInt(int state) {
+ mState = state;
+
+ if (state == BluetoothAdapter.STATE_ON) {
+ // if mProfileManager hasn't been constructed yet, it will
+ // get the adapter UUIDs in its constructor when it is.
+ if (mProfileManager != null) {
+ mProfileManager.setBluetoothStateOn();
+ }
+ }
+ }
+
+ // Returns true if the state changed; false otherwise.
+ boolean syncBluetoothState() {
+ int currentState = mAdapter.getState();
+ if (currentState != mState) {
+ setBluetoothStateInt(mAdapter.getState());
+ return true;
+ }
+ return false;
+ }
+
+ public void setBluetoothEnabled(boolean enabled) {
+ boolean success = enabled
+ ? mAdapter.enable()
+ : mAdapter.disable();
+
+ if (success) {
+ setBluetoothStateInt(enabled
+ ? BluetoothAdapter.STATE_TURNING_ON
+ : BluetoothAdapter.STATE_TURNING_OFF);
+ } else {
+ if (Utils.V) {
+ Log.v(TAG, "setBluetoothEnabled call, manager didn't return " +
+ "success for enabled: " + enabled);
+ }
+
+ syncBluetoothState();
+ }
+ }
+}
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothManager.java b/src/com/android/settings/bluetooth/LocalBluetoothManager.java
index f3c5e6f30..0c04e2273 100644
--- a/src/com/android/settings/bluetooth/LocalBluetoothManager.java
+++ b/src/com/android/settings/bluetooth/LocalBluetoothManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,376 +16,96 @@
package com.android.settings.bluetooth;
-import com.android.settings.R;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
import android.content.Context;
-import android.content.SharedPreferences;
-import android.os.ParcelUuid;
-import android.util.Config;
import android.util.Log;
-import android.widget.Toast;
-
-import java.util.ArrayList;
-import java.util.List;
-// TODO: have some notion of shutting down. Maybe a minute after they leave BT settings?
/**
* LocalBluetoothManager provides a simplified interface on top of a subset of
- * the Bluetooth API.
+ * the Bluetooth API. Note that {@link #getInstance} will return null
+ * if there is no Bluetooth adapter on this device, and callers must be
+ * prepared to handle this case.
*/
-public class LocalBluetoothManager {
+public final class LocalBluetoothManager {
private static final String TAG = "LocalBluetoothManager";
- static final boolean V = Config.LOGV;
- static final boolean D = Config.LOGD;
-
- private static final String SHARED_PREFERENCES_NAME = "bluetooth_settings";
/** Singleton instance. */
private static LocalBluetoothManager sInstance;
- private Context mContext;
- /** If a BT-related activity is in the foreground, this will be it. */
- private Activity mForegroundActivity;
- private AlertDialog mErrorDialog = null;
-
- private BluetoothAdapter mAdapter;
-
- private CachedBluetoothDeviceManager mCachedDeviceManager;
- private BluetoothA2dp mBluetoothA2dp;
-
- private int mState = BluetoothAdapter.ERROR;
+ private final Context mContext;
- private final List<Callback> mCallbacks = new ArrayList<Callback>();
-
- private static final int SCAN_EXPIRATION_MS = 5 * 60 * 1000; // 5 mins
-
- // If a device was picked from the device picker or was in discoverable mode
- // in the last 60 seconds, show the pairing dialogs in foreground instead
- // of raising notifications
- private static final int GRACE_PERIOD_TO_SHOW_DIALOGS_IN_FOREGROUND = 60 * 1000;
-
- public static final String SHARED_PREFERENCES_KEY_DISCOVERING_TIMESTAMP =
- "last_discovering_time";
-
- private static final String SHARED_PREFERENCES_KEY_LAST_SELECTED_DEVICE =
- "last_selected_device";
+ /** If a BT-related activity is in the foreground, this will be it. */
+ private Context mForegroundActivity;
- private static final String SHARED_PREFERENCES_KEY_LAST_SELECTED_DEVICE_TIME =
- "last_selected_device_time";
+ private final LocalBluetoothAdapter mLocalAdapter;
- private static final String SHARED_PREFERENCES_KEY_DOCK_AUTO_CONNECT = "auto_connect_to_dock";
+ private final CachedBluetoothDeviceManager mCachedDeviceManager;
- private long mLastScan;
+ /** The Bluetooth profile manager. */
+ private final LocalBluetoothProfileManager mProfileManager;
- private LocalBluetoothManager() { }
+ /** The broadcast receiver event manager. */
+ private final BluetoothEventManager mEventManager;
- public static LocalBluetoothManager getInstance(Context context) {
- synchronized (LocalBluetoothManager.class) {
- if (sInstance == null) {
- sInstance = new LocalBluetoothManager();
- if (!sInstance.init(context)) {
- return null;
- }
- LocalBluetoothProfileManager.init(sInstance);
+ public static synchronized LocalBluetoothManager getInstance(Context context) {
+ if (sInstance == null) {
+ LocalBluetoothAdapter adapter = LocalBluetoothAdapter.getInstance();
+ if (adapter == null) {
+ return null;
}
-
- return sInstance;
- }
- }
-
- private boolean init(Context context) {
- // This will be around as long as this process is
- mContext = context.getApplicationContext();
-
- mAdapter = BluetoothAdapter.getDefaultAdapter();
- if (mAdapter == null) {
- return false;
+ // This will be around as long as this process is
+ Context appContext = context.getApplicationContext();
+ sInstance = new LocalBluetoothManager(adapter, appContext);
}
- mCachedDeviceManager = new CachedBluetoothDeviceManager(this);
-
- new BluetoothEventRedirector(this).registerReceiver();
+ return sInstance;
+ }
- mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP);
+ private LocalBluetoothManager(LocalBluetoothAdapter adapter, Context context) {
+ mContext = context;
+ mLocalAdapter = adapter;
- return true;
+ mCachedDeviceManager = new CachedBluetoothDeviceManager();
+ mEventManager = new BluetoothEventManager(mLocalAdapter,
+ mCachedDeviceManager);
+ mProfileManager = new LocalBluetoothProfileManager(context,
+ mLocalAdapter, mCachedDeviceManager, mEventManager);
}
- private final BluetoothProfile.ServiceListener mProfileListener =
- new BluetoothProfile.ServiceListener() {
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- mBluetoothA2dp = (BluetoothA2dp) proxy;
- }
- public void onServiceDisconnected(int profile) {
- mBluetoothA2dp = null;
- }
- };
-
- public BluetoothAdapter getBluetoothAdapter() {
- return mAdapter;
+ public LocalBluetoothAdapter getBluetoothAdapter() {
+ return mLocalAdapter;
}
public Context getContext() {
return mContext;
}
- public Activity getForegroundActivity() {
- return mForegroundActivity;
- }
-
- public void setForegroundActivity(Activity activity) {
- if (mErrorDialog != null) {
- mErrorDialog.dismiss();
- mErrorDialog = null;
- }
- mForegroundActivity = activity;
+ boolean isForegroundActivity() {
+ return mForegroundActivity != null;
}
- public SharedPreferences getSharedPreferences() {
- return mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
- }
-
- public CachedBluetoothDeviceManager getCachedDeviceManager() {
- return mCachedDeviceManager;
- }
-
- List<Callback> getCallbacks() {
- return mCallbacks;
- }
-
- public void registerCallback(Callback callback) {
- synchronized (mCallbacks) {
- mCallbacks.add(callback);
- }
- }
-
- public void unregisterCallback(Callback callback) {
- synchronized (mCallbacks) {
- mCallbacks.remove(callback);
- }
- }
-
- public void startScanning(boolean force) {
- if (mAdapter.isDiscovering()) {
- /*
- * Already discovering, but give the callback that information.
- * Note: we only call the callbacks, not the same path as if the
- * scanning state had really changed (in that case the device
- * manager would clear its list of unpaired scanned devices).
- */
- dispatchScanningStateChanged(true);
+ synchronized void setForegroundActivity(Context context) {
+ if (context != null) {
+ Log.d(TAG, "setting foreground activity to non-null context");
+ mForegroundActivity = context;
+ mEventManager.resume(context);
} else {
- if (!force) {
- // Don't scan more than frequently than SCAN_EXPIRATION_MS,
- // unless forced
- if (mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) {
- return;
- }
-
- // If we are playing music, don't scan unless forced.
- if (mBluetoothA2dp != null) {
- List<BluetoothDevice> sinks = mBluetoothA2dp.getConnectedDevices();
- if (sinks.size() > 0) {
- if (mBluetoothA2dp.isA2dpPlaying(sinks.get(0))) return;
- }
- }
+ if (mForegroundActivity != null) {
+ Log.d(TAG, "setting foreground activity to null");
+ mEventManager.pause(mForegroundActivity);
+ mForegroundActivity = null;
}
-
- if (mAdapter.startDiscovery()) {
- mLastScan = System.currentTimeMillis();
- }
- }
- }
-
- public void stopScanning() {
- if (mAdapter.isDiscovering()) {
- mAdapter.cancelDiscovery();
- }
- }
-
- public int getBluetoothState() {
-
- if (mState == BluetoothAdapter.ERROR) {
- syncBluetoothState();
}
-
- return mState;
}
- void setBluetoothStateInt(int state) {
- mState = state;
-
- if (state == BluetoothAdapter.STATE_ON) {
- ParcelUuid[] uuids = mAdapter.getUuids();
- LocalBluetoothProfileManager.updateLocalProfiles(getInstance(mContext), uuids);
- }
-
- if (state == BluetoothAdapter.STATE_ON ||
- state == BluetoothAdapter.STATE_OFF) {
- mCachedDeviceManager.onBluetoothStateChanged(state ==
- BluetoothAdapter.STATE_ON);
- }
- }
-
- private void syncBluetoothState() {
- int bluetoothState;
-
- if (mAdapter != null) {
- bluetoothState = mAdapter.isEnabled()
- ? BluetoothAdapter.STATE_ON
- : BluetoothAdapter.STATE_OFF;
- } else {
- bluetoothState = BluetoothAdapter.ERROR;
- }
-
- setBluetoothStateInt(bluetoothState);
- }
-
- public void setBluetoothEnabled(boolean enabled) {
- boolean wasSetStateSuccessful = enabled
- ? mAdapter.enable()
- : mAdapter.disable();
-
- if (wasSetStateSuccessful) {
- setBluetoothStateInt(enabled
- ? BluetoothAdapter.STATE_TURNING_ON
- : BluetoothAdapter.STATE_TURNING_OFF);
- } else {
- if (V) {
- Log.v(TAG,
- "setBluetoothEnabled call, manager didn't return success for enabled: "
- + enabled);
- }
-
- syncBluetoothState();
- }
- }
-
- /**
- * @param started True if scanning started, false if scanning finished.
- */
- void onScanningStateChanged(boolean started) {
- // TODO: have it be a callback (once we switch bluetooth state changed to callback)
- mCachedDeviceManager.onScanningStateChanged(started);
- dispatchScanningStateChanged(started);
- }
-
- private void dispatchScanningStateChanged(boolean started) {
- synchronized (mCallbacks) {
- for (Callback callback : mCallbacks) {
- callback.onScanningStateChanged(started);
- }
- }
- }
-
- public void showError(BluetoothDevice device, int messageResId) {
- CachedBluetoothDevice cachedDevice = mCachedDeviceManager.findDevice(device);
- String name = null;
- if (cachedDevice == null) {
- if (device != null) name = device.getName();
-
- if (name == null) {
- name = mContext.getString(R.string.bluetooth_remote_device);
- }
- } else {
- name = cachedDevice.getName();
- }
- String message = mContext.getString(messageResId, name);
-
- if (mForegroundActivity != null) {
- // Need an activity context to show a dialog
- mErrorDialog = new AlertDialog.Builder(mForegroundActivity)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setTitle(R.string.bluetooth_error_title)
- .setMessage(message)
- .setPositiveButton(android.R.string.ok, null)
- .show();
- } else {
- // Fallback on a toast
- Toast.makeText(mContext, message, Toast.LENGTH_LONG).show();
- }
- }
-
- public interface Callback {
- void onScanningStateChanged(boolean started);
- void onDeviceAdded(CachedBluetoothDevice cachedDevice);
- void onDeviceDeleted(CachedBluetoothDevice cachedDevice);
- void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState);
- }
-
- public boolean shouldShowDialogInForeground(String deviceAddress) {
- // If Bluetooth Settings is visible
- if (mForegroundActivity != null) return true;
-
- long currentTimeMillis = System.currentTimeMillis();
- SharedPreferences sharedPreferences = getSharedPreferences();
-
- // If the device was in discoverABLE mode recently
- long lastDiscoverableEndTime = sharedPreferences.getLong(
- BluetoothDiscoverableEnabler.SHARED_PREFERENCES_KEY_DISCOVERABLE_END_TIMESTAMP, 0);
- if ((lastDiscoverableEndTime + GRACE_PERIOD_TO_SHOW_DIALOGS_IN_FOREGROUND)
- > currentTimeMillis) {
- return true;
- }
-
- // If the device was discoverING recently
- if (mAdapter != null && mAdapter.isDiscovering()) {
- return true;
- } else if ((sharedPreferences.getLong(SHARED_PREFERENCES_KEY_DISCOVERING_TIMESTAMP, 0) +
- GRACE_PERIOD_TO_SHOW_DIALOGS_IN_FOREGROUND) > currentTimeMillis) {
- return true;
- }
-
- // If the device was picked in the device picker recently
- if (deviceAddress != null) {
- String lastSelectedDevice = sharedPreferences.getString(
- SHARED_PREFERENCES_KEY_LAST_SELECTED_DEVICE, null);
-
- if (deviceAddress.equals(lastSelectedDevice)) {
- long lastDeviceSelectedTime = sharedPreferences.getLong(
- SHARED_PREFERENCES_KEY_LAST_SELECTED_DEVICE_TIME, 0);
- if ((lastDeviceSelectedTime + GRACE_PERIOD_TO_SHOW_DIALOGS_IN_FOREGROUND)
- > currentTimeMillis) {
- return true;
- }
- }
- }
- return false;
- }
-
- void persistSelectedDeviceInPicker(String deviceAddress) {
- SharedPreferences.Editor editor = getSharedPreferences().edit();
- editor.putString(LocalBluetoothManager.SHARED_PREFERENCES_KEY_LAST_SELECTED_DEVICE,
- deviceAddress);
- editor.putLong(LocalBluetoothManager.SHARED_PREFERENCES_KEY_LAST_SELECTED_DEVICE_TIME,
- System.currentTimeMillis());
- editor.apply();
- }
-
- public boolean hasDockAutoConnectSetting(String addr) {
- return getSharedPreferences().contains(SHARED_PREFERENCES_KEY_DOCK_AUTO_CONNECT + addr);
- }
-
- public boolean getDockAutoConnectSetting(String addr) {
- return getSharedPreferences().getBoolean(SHARED_PREFERENCES_KEY_DOCK_AUTO_CONNECT + addr,
- false);
+ CachedBluetoothDeviceManager getCachedDeviceManager() {
+ return mCachedDeviceManager;
}
- public void saveDockAutoConnectSetting(String addr, boolean autoConnect) {
- SharedPreferences.Editor editor = getSharedPreferences().edit();
- editor.putBoolean(SHARED_PREFERENCES_KEY_DOCK_AUTO_CONNECT + addr, autoConnect);
- editor.apply();
+ BluetoothEventManager getEventManager() {
+ return mEventManager;
}
- public void removeDockAutoConnectSetting(String addr) {
- SharedPreferences.Editor editor = getSharedPreferences().edit();
- editor.remove(SHARED_PREFERENCES_KEY_DOCK_AUTO_CONNECT + addr);
- editor.apply();
+ LocalBluetoothProfileManager getProfileManager() {
+ return mProfileManager;
}
}
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothPreferences.java b/src/com/android/settings/bluetooth/LocalBluetoothPreferences.java
new file mode 100644
index 000000000..7e62b0e1a
--- /dev/null
+++ b/src/com/android/settings/bluetooth/LocalBluetoothPreferences.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.app.QueuedWork;
+import android.content.Context;
+import android.content.SharedPreferences;
+
+/**
+ * LocalBluetoothPreferences provides an interface to the preferences
+ * related to Bluetooth.
+ */
+final class LocalBluetoothPreferences {
+// private static final String TAG = "LocalBluetoothPreferences";
+
+ private static final String SHARED_PREFERENCES_NAME = "bluetooth_settings";
+
+ // If a device was picked from the device picker or was in discoverable mode
+ // in the last 60 seconds, show the pairing dialogs in foreground instead
+ // of raising notifications
+ private static final int GRACE_PERIOD_TO_SHOW_DIALOGS_IN_FOREGROUND = 60 * 1000;
+
+ private static final String KEY_DISCOVERING_TIMESTAMP = "last_discovering_time";
+
+ private static final String KEY_LAST_SELECTED_DEVICE = "last_selected_device";
+
+ private static final String KEY_LAST_SELECTED_DEVICE_TIME = "last_selected_device_time";
+
+ private static final String KEY_DOCK_AUTO_CONNECT = "auto_connect_to_dock";
+
+ private static final String KEY_DISCOVERABLE_END_TIMESTAMP = "discoverable_end_timestamp";
+
+ private LocalBluetoothPreferences() {
+ }
+
+ private static SharedPreferences getSharedPreferences(Context context) {
+ return context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
+ }
+
+ static long getDiscoverableEndTimestamp(Context context) {
+ return getSharedPreferences(context).getLong(
+ KEY_DISCOVERABLE_END_TIMESTAMP, 0);
+ }
+
+ static boolean shouldShowDialogInForeground(Context context,
+ String deviceAddress) {
+ LocalBluetoothManager manager = LocalBluetoothManager.getInstance(context);
+ if (manager == null) {
+ return false;
+ }
+
+ // If Bluetooth Settings is visible
+ if (manager.isForegroundActivity()) {
+ return true;
+ }
+
+ long currentTimeMillis = System.currentTimeMillis();
+ SharedPreferences sharedPreferences = getSharedPreferences(context);
+
+ // If the device was in discoverABLE mode recently
+ long lastDiscoverableEndTime = sharedPreferences.getLong(
+ KEY_DISCOVERABLE_END_TIMESTAMP, 0);
+ if ((lastDiscoverableEndTime + GRACE_PERIOD_TO_SHOW_DIALOGS_IN_FOREGROUND)
+ > currentTimeMillis) {
+ return true;
+ }
+
+ // If the device was discoverING recently
+ LocalBluetoothAdapter adapter = manager.getBluetoothAdapter();
+ if (adapter != null && adapter.isDiscovering()) {
+ return true;
+ } else if ((sharedPreferences.getLong(KEY_DISCOVERING_TIMESTAMP, 0) +
+ GRACE_PERIOD_TO_SHOW_DIALOGS_IN_FOREGROUND) > currentTimeMillis) {
+ return true;
+ }
+
+ // If the device was picked in the device picker recently
+ if (deviceAddress != null) {
+ String lastSelectedDevice = sharedPreferences.getString(
+ KEY_LAST_SELECTED_DEVICE, null);
+
+ if (deviceAddress.equals(lastSelectedDevice)) {
+ long lastDeviceSelectedTime = sharedPreferences.getLong(
+ KEY_LAST_SELECTED_DEVICE_TIME, 0);
+ if ((lastDeviceSelectedTime + GRACE_PERIOD_TO_SHOW_DIALOGS_IN_FOREGROUND)
+ > currentTimeMillis) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ static void persistSelectedDeviceInPicker(Context context, String deviceAddress) {
+ SharedPreferences.Editor editor = getSharedPreferences(context).edit();
+ editor.putString(KEY_LAST_SELECTED_DEVICE,
+ deviceAddress);
+ editor.putLong(KEY_LAST_SELECTED_DEVICE_TIME,
+ System.currentTimeMillis());
+ editor.apply();
+ }
+
+ static void persistDiscoverableEndTimestamp(Context context, long endTimestamp) {
+ SharedPreferences.Editor editor = getSharedPreferences(context).edit();
+ editor.putLong(KEY_DISCOVERABLE_END_TIMESTAMP, endTimestamp);
+ editor.apply();
+ }
+
+ static void persistDiscoveringTimestamp(final Context context) {
+ // Load the shared preferences and edit it on a background
+ // thread (but serialized!).
+ QueuedWork.singleThreadExecutor().submit(new Runnable() {
+ public void run() {
+ SharedPreferences.Editor editor = getSharedPreferences(context).edit();
+ editor.putLong(
+ KEY_DISCOVERING_TIMESTAMP,
+ System.currentTimeMillis());
+ editor.apply();
+ }
+ });
+ }
+
+ static boolean hasDockAutoConnectSetting(Context context, String addr) {
+ return getSharedPreferences(context).contains(KEY_DOCK_AUTO_CONNECT + addr);
+ }
+
+ static boolean getDockAutoConnectSetting(Context context, String addr) {
+ return getSharedPreferences(context).getBoolean(KEY_DOCK_AUTO_CONNECT + addr,
+ false);
+ }
+
+ static void saveDockAutoConnectSetting(Context context, String addr, boolean autoConnect) {
+ SharedPreferences.Editor editor = getSharedPreferences(context).edit();
+ editor.putBoolean(KEY_DOCK_AUTO_CONNECT + addr, autoConnect);
+ editor.apply();
+ }
+
+ static void removeDockAutoConnectSetting(Context context, String addr) {
+ SharedPreferences.Editor editor = getSharedPreferences(context).edit();
+ editor.remove(KEY_DOCK_AUTO_CONNECT + addr);
+ editor.apply();
+ }
+}
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothProfile.java b/src/com/android/settings/bluetooth/LocalBluetoothProfile.java
new file mode 100644
index 000000000..936231a1c
--- /dev/null
+++ b/src/com/android/settings/bluetooth/LocalBluetoothProfile.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * LocalBluetoothProfile is an interface defining the basic
+ * functionality related to a Bluetooth profile.
+ */
+interface LocalBluetoothProfile {
+
+ /**
+ * Returns true if the user can initiate a connection, false otherwise.
+ */
+ boolean isConnectable();
+
+ /**
+ * Returns true if the user can enable auto connection for this profile.
+ */
+ boolean isAutoConnectable();
+
+ boolean connect(BluetoothDevice device);
+
+ boolean disconnect(BluetoothDevice device);
+
+ int getConnectionStatus(BluetoothDevice device);
+
+ boolean isPreferred(BluetoothDevice device);
+
+ int getPreferred(BluetoothDevice device);
+
+ void setPreferred(BluetoothDevice device, boolean preferred);
+
+ boolean isProfileReady();
+
+ /** Display order for device profile settings. */
+ int getOrdinal();
+
+ /**
+ * Returns the string resource ID for the localized name for this profile.
+ */
+ int getNameResource();
+
+ /**
+ * Returns the string resource ID for the disconnect confirmation text
+ * for this profile.
+ */
+ int getDisconnectResource();
+
+ /**
+ * Returns the string resource ID for the summary text for this profile
+ * for the specified device, e.g. "Use for media audio" or
+ * "Connected to media audio".
+ * @param device the device to query for profile connection status
+ * @return a string resource ID for the profile summary text
+ */
+ int getSummaryResourceForDevice(BluetoothDevice device);
+
+ int getDrawableResource(BluetoothClass btClass);
+}
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java b/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java
index 164d2da32..0bb6f115b 100644
--- a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java
+++ b/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,67 +16,37 @@
package com.android.settings.bluetooth;
-import com.android.settings.R;
-
import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothInputDevice;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
-import android.os.Handler;
+import android.content.Context;
+import android.content.Intent;
import android.os.ParcelUuid;
import android.util.Log;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
import java.util.Map;
/**
- * LocalBluetoothProfileManager is an abstract class defining the basic
- * functionality related to a profile.
+ * LocalBluetoothProfileManager provides access to the LocalBluetoothProfile
+ * objects for the available Bluetooth profiles.
*/
-abstract class LocalBluetoothProfileManager {
+final class LocalBluetoothProfileManager {
private static final String TAG = "LocalBluetoothProfileManager";
- /* package */ static final ParcelUuid[] HEADSET_PROFILE_UUIDS = new ParcelUuid[] {
- BluetoothUuid.HSP,
- BluetoothUuid.Handsfree,
- };
-
- /* package */ static final ParcelUuid[] A2DP_SINK_PROFILE_UUIDS = new ParcelUuid[] {
- BluetoothUuid.AudioSink,
- BluetoothUuid.AdvAudioDist,
- };
-
- /* package */ static final ParcelUuid[] A2DP_SRC_PROFILE_UUIDS = new ParcelUuid[] {
- BluetoothUuid.AudioSource
- };
-
- /* package */ static final ParcelUuid[] OPP_PROFILE_UUIDS = new ParcelUuid[] {
- BluetoothUuid.ObexObjectPush
- };
-
- /* package */ static final ParcelUuid[] HID_PROFILE_UUIDS = new ParcelUuid[] {
- BluetoothUuid.Hid
- };
-
- /* package */ static final ParcelUuid[] PANU_PROFILE_UUIDS = new ParcelUuid[] {
- BluetoothUuid.PANU
- };
-
- /* package */ static final ParcelUuid[] NAP_PROFILE_UUIDS = new ParcelUuid[] {
- BluetoothUuid.NAP
- };
+ /** Singleton instance. */
+ private static LocalBluetoothProfileManager sInstance;
/**
* An interface for notifying BluetoothHeadset IPC clients when they have
* been connected to the BluetoothHeadset service.
+ * Only used by {@link DockService}.
*/
public interface ServiceListener {
/**
@@ -85,7 +55,7 @@ abstract class LocalBluetoothProfileManager {
* this callback before making IPC calls on the BluetoothHeadset
* service.
*/
- public void onServiceConnected();
+ void onServiceConnected();
/**
* Called to notify the client that this proxy object has been
@@ -94,743 +64,246 @@ abstract class LocalBluetoothProfileManager {
* This callback will currently only occur if the application hosting
* the BluetoothHeadset service, but may be called more often in future.
*/
- public void onServiceDisconnected();
- }
-
- // TODO: close profiles when we're shutting down
- private static final Map<Profile, LocalBluetoothProfileManager> sProfileMap =
- new HashMap<Profile, LocalBluetoothProfileManager>();
-
- protected final LocalBluetoothManager mLocalManager;
-
- public static void init(LocalBluetoothManager localManager) {
- synchronized (sProfileMap) {
- if (sProfileMap.size() == 0) {
- LocalBluetoothProfileManager profileManager;
-
- profileManager = new A2dpProfileManager(localManager);
- sProfileMap.put(Profile.A2DP, profileManager);
-
- profileManager = new HeadsetProfileManager(localManager);
- sProfileMap.put(Profile.HEADSET, profileManager);
-
- profileManager = new OppProfileManager(localManager);
- sProfileMap.put(Profile.OPP, profileManager);
-
- profileManager = new HidProfileManager(localManager);
- sProfileMap.put(Profile.HID, profileManager);
-
- profileManager = new PanProfileManager(localManager);
- sProfileMap.put(Profile.PAN, profileManager);
- }
- }
+ void onServiceDisconnected();
}
- // TODO(): Combine the init and updateLocalProfiles codes.
- // init can get called from various paths, it makes no sense to add and then delete.
- public static void updateLocalProfiles(LocalBluetoothManager localManager, ParcelUuid[] uuids) {
- if (!BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) &&
- !BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP_AG)) {
- sProfileMap.remove(Profile.HEADSET);
- }
-
- if (!BluetoothUuid.containsAnyUuid(uuids, A2DP_SRC_PROFILE_UUIDS)) {
- sProfileMap.remove(Profile.A2DP);
- }
+ private final Context mContext;
+ private final LocalBluetoothAdapter mLocalAdapter;
+ private final CachedBluetoothDeviceManager mDeviceManager;
+ private final BluetoothEventManager mEventManager;
- if (!BluetoothUuid.containsAnyUuid(uuids, OPP_PROFILE_UUIDS)) {
- sProfileMap.remove(Profile.OPP);
- }
-
- // There is no local SDP record for HID and Settings app doesn't control PBAP
- }
-
- private static final LinkedList<ServiceListener> mServiceListeners =
- new LinkedList<ServiceListener>();
-
- public static void addServiceListener(ServiceListener l) {
- mServiceListeners.add(l);
- }
-
- public static void removeServiceListener(ServiceListener l) {
- mServiceListeners.remove(l);
- }
-
- public static boolean isManagerReady() {
- // Getting just the headset profile is fine for now. Will need to deal with A2DP
- // and others if they aren't always in a ready state.
- LocalBluetoothProfileManager profileManager = sProfileMap.get(Profile.HEADSET);
- if (profileManager == null) {
- return sProfileMap.size() > 0;
- }
- return profileManager.isProfileReady();
- }
-
- public static LocalBluetoothProfileManager getProfileManager(LocalBluetoothManager localManager,
- Profile profile) {
- // Note: This code assumes that "localManager" is same as the
- // LocalBluetoothManager that was used to initialize the sProfileMap.
- // If that every changes, we can't just keep one copy of sProfileMap.
- synchronized (sProfileMap) {
- LocalBluetoothProfileManager profileManager = sProfileMap.get(profile);
- if (profileManager == null) {
- Log.e(TAG, "profileManager can't be found for " + profile.toString());
- }
- return profileManager;
- }
- }
+ private A2dpProfile mA2dpProfile;
+ private HeadsetProfile mHeadsetProfile;
+ private final HidProfile mHidProfile;
+ private OppProfile mOppProfile;
+ private final PanProfile mPanProfile;
/**
- * Temporary method to fill profiles based on a device's class.
- *
- * NOTE: This list happens to define the connection order. We should put this logic in a more
- * well known place when this method is no longer temporary.
- * @param uuids of the remote device
- * @param localUuids UUIDs of the local device
- * @param profiles The list of profiles to fill
+ * Mapping from profile name, e.g. "HEADSET" to profile object.
*/
- public static void updateProfiles(ParcelUuid[] uuids, ParcelUuid[] localUuids,
- List<Profile> profiles) {
- profiles.clear();
+ private final Map<String, LocalBluetoothProfile>
+ mProfileNameMap = new HashMap<String, LocalBluetoothProfile>();
- if (uuids == null) {
- return;
- }
-
- if (sProfileMap.containsKey(Profile.HEADSET)) {
- if ((BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG) &&
- BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP)) ||
- (BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) &&
- BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) {
- profiles.add(Profile.HEADSET);
- }
- }
+ LocalBluetoothProfileManager(Context context,
+ LocalBluetoothAdapter adapter,
+ CachedBluetoothDeviceManager deviceManager,
+ BluetoothEventManager eventManager) {
+ mContext = context;
+ mLocalAdapter = adapter;
+ mDeviceManager = deviceManager;
+ mEventManager = eventManager;
+ // pass this reference to adapter and event manager (circular dependency)
+ mLocalAdapter.setProfileManager(this);
+ mEventManager.setProfileManager(this);
- if (BluetoothUuid.containsAnyUuid(uuids, A2DP_SINK_PROFILE_UUIDS) &&
- sProfileMap.containsKey(Profile.A2DP)) {
- profiles.add(Profile.A2DP);
- }
+ ParcelUuid[] uuids = adapter.getUuids();
- if (BluetoothUuid.containsAnyUuid(uuids, OPP_PROFILE_UUIDS) &&
- sProfileMap.containsKey(Profile.OPP)) {
- profiles.add(Profile.OPP);
+ // uuids may be null if Bluetooth is turned off
+ if (uuids != null) {
+ updateLocalProfiles(uuids);
}
- if (BluetoothUuid.containsAnyUuid(uuids, HID_PROFILE_UUIDS) &&
- sProfileMap.containsKey(Profile.HID)) {
- profiles.add(Profile.HID);
- }
+ // Always add HID and PAN profiles
+ mHidProfile = new HidProfile(context, mLocalAdapter);
+ addProfile(mHidProfile, HidProfile.NAME,
+ BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
- if (BluetoothUuid.containsAnyUuid(uuids, NAP_PROFILE_UUIDS) &&
- sProfileMap.containsKey(Profile.PAN)) {
- profiles.add(Profile.PAN);
- }
- }
-
- protected LocalBluetoothProfileManager(LocalBluetoothManager localManager) {
- mLocalManager = localManager;
- }
-
- public abstract List<BluetoothDevice> getConnectedDevices();
-
- public abstract boolean connect(BluetoothDevice device);
-
- public abstract boolean disconnect(BluetoothDevice device);
-
- public abstract int getConnectionStatus(BluetoothDevice device);
-
- public abstract int getSummary(BluetoothDevice device);
-
- public abstract int convertState(int a2dpState);
-
- public abstract boolean isPreferred(BluetoothDevice device);
-
- public abstract int getPreferred(BluetoothDevice device);
-
- public abstract void setPreferred(BluetoothDevice device, boolean preferred);
-
- public boolean isConnected(BluetoothDevice device) {
- return SettingsBtStatus.isConnectionStatusConnected(getConnectionStatus(device));
- }
-
- public abstract boolean isProfileReady();
-
- public abstract int getDrawableResource();
-
- public static enum Profile {
- HEADSET(R.string.bluetooth_profile_headset, true, true),
- A2DP(R.string.bluetooth_profile_a2dp, true, true),
- OPP(R.string.bluetooth_profile_opp, false, false),
- HID(R.string.bluetooth_profile_hid, true, true),
- PAN(R.string.bluetooth_profile_pan, true, false);
-
- public final int localizedString;
- private final boolean mConnectable;
- private final boolean mAutoConnectable;
-
- private Profile(int localizedString, boolean connectable,
- boolean autoConnectable) {
- this.localizedString = localizedString;
- this.mConnectable = connectable;
- this.mAutoConnectable = autoConnectable;
- }
-
- public boolean isConnectable() {
- return mConnectable;
- }
-
- public boolean isAutoConnectable() {
- return mAutoConnectable;
- }
+ mPanProfile = new PanProfile(context);
+ addProfile(mPanProfile, PanProfile.NAME, BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
+ Log.d(TAG, "LocalBluetoothProfileManager construction complete");
}
/**
- * A2dpProfileManager is an abstraction for the {@link BluetoothA2dp} service.
+ * Initialize or update the local profile objects. If a UUID was previously
+ * present but has been removed, we print a warning but don't remove the
+ * profile object as it might be referenced elsewhere, or the UUID might
+ * come back and we don't want multiple copies of the profile objects.
+ * @param uuids
*/
- private static class A2dpProfileManager extends LocalBluetoothProfileManager
- implements BluetoothProfile.ServiceListener {
- private BluetoothA2dp mService;
-
- // TODO(): The calls must wait for mService. Its not null just
- // because it runs in the system server.
- public A2dpProfileManager(LocalBluetoothManager localManager) {
- super(localManager);
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- adapter.getProfileProxy(localManager.getContext(), this, BluetoothProfile.A2DP);
-
- }
-
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- mService = (BluetoothA2dp) proxy;
- }
-
- public void onServiceDisconnected(int profile) {
- mService = null;
- }
-
- @Override
- public List<BluetoothDevice> getConnectedDevices() {
- return mService.getDevicesMatchingConnectionStates(
- new int[] {BluetoothProfile.STATE_CONNECTED,
- BluetoothProfile.STATE_CONNECTING,
- BluetoothProfile.STATE_DISCONNECTING});
- }
-
- @Override
- public boolean connect(BluetoothDevice device) {
- List<BluetoothDevice> sinks = getConnectedDevices();
- if (sinks != null) {
- for (BluetoothDevice sink : sinks) {
- mService.disconnect(sink);
- }
+ void updateLocalProfiles(ParcelUuid[] uuids) {
+ // A2DP
+ if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSource)) {
+ if (mA2dpProfile == null) {
+ Log.d(TAG, "Adding local A2DP profile");
+ mA2dpProfile = new A2dpProfile(mContext);
+ addProfile(mA2dpProfile, A2dpProfile.NAME,
+ BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
}
- return mService.connect(device);
- }
-
- @Override
- public boolean disconnect(BluetoothDevice device) {
- // Downgrade priority as user is disconnecting the sink.
- if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ } else if (mA2dpProfile != null) {
+ Log.w(TAG, "Warning: A2DP profile was previously added but the UUID is now missing.");
+ }
+
+ // Headset / Handsfree
+ if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) ||
+ BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP_AG)) {
+ if (mHeadsetProfile == null) {
+ Log.d(TAG, "Adding local HEADSET profile");
+ mHeadsetProfile = new HeadsetProfile(mContext, mLocalAdapter,
+ mDeviceManager, this);
+ addProfile(mHeadsetProfile, HeadsetProfile.NAME,
+ BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
}
- return mService.disconnect(device);
+ } else if (mHeadsetProfile != null) {
+ Log.w(TAG, "Warning: HEADSET profile was previously added but the UUID is now missing.");
}
- @Override
- public int getConnectionStatus(BluetoothDevice device) {
- return convertState(mService.getConnectionState(device));
- }
-
- @Override
- public int getSummary(BluetoothDevice device) {
- int connectionStatus = getConnectionStatus(device);
-
- if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) {
- return R.string.bluetooth_a2dp_profile_summary_connected;
- } else {
- return SettingsBtStatus.getConnectionStatusSummary(connectionStatus);
+ // OPP
+ if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) {
+ if (mOppProfile == null) {
+ Log.d(TAG, "Adding local OPP profile");
+ mOppProfile = new OppProfile();
+ // Note: no event handler for OPP, only name map.
+ mProfileNameMap.put(OppProfile.NAME, mOppProfile);
}
+ } else if (mOppProfile != null) {
+ Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing.");
}
- @Override
- public boolean isPreferred(BluetoothDevice device) {
- return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
- }
-
- @Override
- public int getPreferred(BluetoothDevice device) {
- return mService.getPriority(device);
- }
-
- @Override
- public void setPreferred(BluetoothDevice device, boolean preferred) {
- if (preferred) {
- if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
- }
- } else {
- mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
- }
- }
-
- @Override
- public int convertState(int a2dpState) {
- switch (a2dpState) {
- case BluetoothProfile.STATE_CONNECTED:
- return SettingsBtStatus.CONNECTION_STATUS_CONNECTED;
- case BluetoothProfile.STATE_CONNECTING:
- return SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
- case BluetoothProfile.STATE_DISCONNECTED:
- return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
- case BluetoothProfile.STATE_DISCONNECTING:
- return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTING;
- case BluetoothA2dp.STATE_PLAYING:
- return SettingsBtStatus.CONNECTION_STATUS_ACTIVE;
- default:
- return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN;
- }
- }
-
- @Override
- public boolean isProfileReady() {
- return true;
- }
-
- @Override
- public int getDrawableResource() {
- return R.drawable.ic_bt_headphones_a2dp;
- }
+ // There is no local SDP record for HID and Settings app doesn't control PBAP
}
- /**
- * HeadsetProfileManager is an abstraction for the {@link BluetoothHeadset} service.
- */
- private static class HeadsetProfileManager extends LocalBluetoothProfileManager
- implements BluetoothProfile.ServiceListener {
- private BluetoothHeadset mService;
- private final Handler mUiHandler = new Handler();
- private boolean profileReady = false;
-
- // TODO(): The calls must get queued if mService becomes null.
- // It can happen when phone app crashes for some reason.
- // All callers should have service listeners. Dock Service is the only
- // one right now.
- public HeadsetProfileManager(LocalBluetoothManager localManager) {
- super(localManager);
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- adapter.getProfileProxy(localManager.getContext(), this, BluetoothProfile.HEADSET);
- }
-
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- mService = (BluetoothHeadset) proxy;
- profileReady = true;
- // This could be called on a non-UI thread, funnel to UI thread.
- mUiHandler.post(new Runnable() {
- public void run() {
- /*
- * We just bound to the service, so refresh the UI of the
- * headset device.
- */
- List<BluetoothDevice> deviceList = mService.getConnectedDevices();
- if (deviceList.size() == 0) return;
-
- mLocalManager.getCachedDeviceManager()
- .onProfileStateChanged(deviceList.get(0), Profile.HEADSET,
- BluetoothProfile.STATE_CONNECTED);
- }
- });
-
- if (mServiceListeners.size() > 0) {
- Iterator<ServiceListener> it = mServiceListeners.iterator();
- while(it.hasNext()) {
- it.next().onServiceConnected();
- }
- }
- }
-
- public void onServiceDisconnected(int profile) {
- mService = null;
- profileReady = false;
- if (mServiceListeners.size() > 0) {
- Iterator<ServiceListener> it = mServiceListeners.iterator();
- while(it.hasNext()) {
- it.next().onServiceDisconnected();
- }
- }
- }
-
- @Override
- public boolean isProfileReady() {
- return profileReady;
- }
-
- @Override
- public List<BluetoothDevice> getConnectedDevices() {
- if (mService != null) {
- return mService.getConnectedDevices();
- } else {
- return new ArrayList<BluetoothDevice>();
- }
- }
-
- @Override
- public boolean connect(BluetoothDevice device) {
- List<BluetoothDevice> sinks = getConnectedDevices();
- if (sinks != null) {
- for (BluetoothDevice sink : sinks) {
- mService.disconnect(sink);
- }
- }
- return mService.connect(device);
- }
-
- @Override
- public boolean disconnect(BluetoothDevice device) {
- List<BluetoothDevice> deviceList = getConnectedDevices();
- if (deviceList.size() != 0 && deviceList.get(0).equals(device)) {
- // Downgrade priority as user is disconnecting the headset.
- if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
- }
- return mService.disconnect(device);
- } else {
- return false;
- }
- }
-
- @Override
- public int getConnectionStatus(BluetoothDevice device) {
- List<BluetoothDevice> deviceList = getConnectedDevices();
-
- return deviceList.size() > 0 && deviceList.get(0).equals(device)
- ? convertState(mService.getConnectionState(device))
- : SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
- }
-
- @Override
- public int getSummary(BluetoothDevice device) {
- int connectionStatus = getConnectionStatus(device);
+ private final Collection<ServiceListener> mServiceListeners =
+ new ArrayList<ServiceListener>();
- if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) {
- return R.string.bluetooth_headset_profile_summary_connected;
- } else {
- return SettingsBtStatus.getConnectionStatusSummary(connectionStatus);
- }
- }
-
- @Override
- public boolean isPreferred(BluetoothDevice device) {
- return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
- }
-
- @Override
- public int getPreferred(BluetoothDevice device) {
- return mService.getPriority(device);
- }
-
- @Override
- public void setPreferred(BluetoothDevice device, boolean preferred) {
- if (preferred) {
- if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
- }
- } else {
- mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
- }
- }
+ private void addProfile(LocalBluetoothProfile profile,
+ String profileName, String stateChangedAction) {
+ mEventManager.addHandler(stateChangedAction, new StateChangedHandler(profile));
+ mProfileNameMap.put(profileName, profile);
+ }
- @Override
- public int convertState(int headsetState) {
- switch (headsetState) {
- case BluetoothProfile.STATE_CONNECTED:
- return SettingsBtStatus.CONNECTION_STATUS_CONNECTED;
- case BluetoothProfile.STATE_CONNECTING:
- return SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
- case BluetoothProfile.STATE_DISCONNECTED:
- return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
- default:
- return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN;
- }
- }
+ LocalBluetoothProfile getProfileByName(String name) {
+ return mProfileNameMap.get(name);
+ }
- @Override
- public int getDrawableResource() {
- return R.drawable.ic_bt_headset_hfp;
+ // Called from LocalBluetoothAdapter when state changes to ON
+ void setBluetoothStateOn() {
+ ParcelUuid[] uuids = mLocalAdapter.getUuids();
+ if (uuids != null) {
+ updateLocalProfiles(uuids);
}
+ mEventManager.readPairedDevices();
}
/**
- * OppProfileManager
+ * Generic handler for connection state change events for the specified profile.
*/
- private static class OppProfileManager extends LocalBluetoothProfileManager {
-
- public OppProfileManager(LocalBluetoothManager localManager) {
- super(localManager);
- }
-
- @Override
- public List<BluetoothDevice> getConnectedDevices() {
- return null;
- }
-
- @Override
- public boolean connect(BluetoothDevice device) {
- return false;
- }
+ private class StateChangedHandler implements BluetoothEventManager.Handler {
+ private final LocalBluetoothProfile mProfile;
- @Override
- public boolean disconnect(BluetoothDevice device) {
- return false;
+ StateChangedHandler(LocalBluetoothProfile profile) {
+ mProfile = profile;
}
- @Override
- public int getConnectionStatus(BluetoothDevice device) {
- return -1;
- }
-
- @Override
- public int getSummary(BluetoothDevice device) {
- int connectionStatus = getConnectionStatus(device);
-
- if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) {
- return R.string.bluetooth_opp_profile_summary_connected;
- } else {
- return R.string.bluetooth_opp_profile_summary_not_connected;
+ public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+ CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+ if (cachedDevice == null) {
+ Log.w(TAG, "StateChangedHandler found new device: " + device);
+ cachedDevice = mDeviceManager.addDevice(mLocalAdapter,
+ LocalBluetoothProfileManager.this, device);
}
- }
-
- @Override
- public boolean isPreferred(BluetoothDevice device) {
- return false;
- }
-
- @Override
- public int getPreferred(BluetoothDevice device) {
- return -1;
- }
-
- @Override
- public void setPreferred(BluetoothDevice device, boolean preferred) {
- }
-
- @Override
- public boolean isProfileReady() {
- return true;
- }
-
- @Override
- public int convertState(int oppState) {
- switch (oppState) {
- case 0:
- return SettingsBtStatus.CONNECTION_STATUS_CONNECTED;
- case 1:
- return SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
- case 2:
- return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
- default:
- return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN;
+ int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
+ int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
+ if (newState == BluetoothProfile.STATE_DISCONNECTED &&
+ oldState == BluetoothProfile.STATE_CONNECTING) {
+ Log.i(TAG, "Failed to connect " + mProfile + " device");
}
- }
- @Override
- public int getDrawableResource() {
- return 0; // no icon for OPP
+ cachedDevice.onProfileStateChanged(mProfile, newState);
+ cachedDevice.refresh();
}
}
- private static class HidProfileManager extends LocalBluetoothProfileManager
- implements BluetoothProfile.ServiceListener {
- private BluetoothInputDevice mService;
-
- public HidProfileManager(LocalBluetoothManager localManager) {
- super(localManager);
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- adapter.getProfileProxy(localManager.getContext(), this, BluetoothProfile.INPUT_DEVICE);
- }
-
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- mService = (BluetoothInputDevice) proxy;
- }
-
- public void onServiceDisconnected(int profile) {
- mService = null;
- }
-
- @Override
- public boolean connect(BluetoothDevice device) {
- return mService.connect(device);
- }
-
- @Override
- public int convertState(int hidState) {
- switch (hidState) {
- case BluetoothProfile.STATE_CONNECTED:
- return SettingsBtStatus.CONNECTION_STATUS_CONNECTED;
- case BluetoothProfile.STATE_CONNECTING:
- return SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
- case BluetoothProfile.STATE_DISCONNECTED:
- return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
- case BluetoothProfile.STATE_DISCONNECTING:
- return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTING;
- default:
- return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN;
- }
- }
-
- @Override
- public boolean disconnect(BluetoothDevice device) {
- return mService.disconnect(device);
- }
-
- @Override
- public List<BluetoothDevice> getConnectedDevices() {
- return mService.getConnectedDevices();
- }
-
- @Override
- public int getConnectionStatus(BluetoothDevice device) {
- return convertState(mService.getConnectionState(device));
- }
-
- @Override
- public int getPreferred(BluetoothDevice device) {
- return mService.getPriority(device);
- }
-
- @Override
- public int getSummary(BluetoothDevice device) {
- final int connectionStatus = getConnectionStatus(device);
-
- if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) {
- return R.string.bluetooth_hid_profile_summary_connected;
- } else {
- return SettingsBtStatus.getConnectionStatusSummary(connectionStatus);
- }
- }
-
- @Override
- public boolean isPreferred(BluetoothDevice device) {
- return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
- }
+ // called from DockService
+ void addServiceListener(ServiceListener l) {
+ mServiceListeners.add(l);
+ }
- @Override
- public boolean isProfileReady() {
- return true;
- }
+ // called from DockService
+ void removeServiceListener(ServiceListener l) {
+ mServiceListeners.remove(l);
+ }
- @Override
- public void setPreferred(BluetoothDevice device, boolean preferred) {
- if (preferred) {
- if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
- }
- } else {
- mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
- }
+ // not synchronized: use only from UI thread! (TODO: verify)
+ void callServiceConnectedListeners() {
+ for (ServiceListener l : mServiceListeners) {
+ l.onServiceConnected();
}
+ }
- @Override
- public int getDrawableResource() {
- return R.drawable.ic_bt_keyboard_hid;
+ // not synchronized: use only from UI thread! (TODO: verify)
+ void callServiceDisconnectedListeners() {
+ for (ServiceListener listener : mServiceListeners) {
+ listener.onServiceDisconnected();
}
}
- private static class PanProfileManager extends LocalBluetoothProfileManager
- implements BluetoothProfile.ServiceListener {
- private BluetoothPan mService;
-
- public PanProfileManager(LocalBluetoothManager localManager) {
- super(localManager);
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- adapter.getProfileProxy(localManager.getContext(), this, BluetoothProfile.PAN);
+ // This is called by DockService, so check Headset and A2DP.
+ public synchronized boolean isManagerReady() {
+ // Getting just the headset profile is fine for now. Will need to deal with A2DP
+ // and others if they aren't always in a ready state.
+ LocalBluetoothProfile profile = mHeadsetProfile;
+ if (profile != null) {
+ return profile.isProfileReady();
}
-
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- mService = (BluetoothPan) proxy;
+ profile = mA2dpProfile;
+ if (profile != null) {
+ return profile.isProfileReady();
}
+ return false;
+ }
- public void onServiceDisconnected(int profile) {
- mService = null;
- }
+ A2dpProfile getA2dpProfile() {
+ return mA2dpProfile;
+ }
- @Override
- public boolean connect(BluetoothDevice device) {
- List<BluetoothDevice> sinks = getConnectedDevices();
- if (sinks != null) {
- for (BluetoothDevice sink : sinks) {
- mService.disconnect(sink);
- }
- }
- return mService.connect(device);
- }
+ HeadsetProfile getHeadsetProfile() {
+ return mHeadsetProfile;
+ }
- @Override
- public int convertState(int panState) {
- switch (panState) {
- case BluetoothPan.STATE_CONNECTED:
- return SettingsBtStatus.CONNECTION_STATUS_CONNECTED;
- case BluetoothPan.STATE_CONNECTING:
- return SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
- case BluetoothPan.STATE_DISCONNECTED:
- return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
- case BluetoothPan.STATE_DISCONNECTING:
- return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTING;
- default:
- return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN;
- }
- }
+ /**
+ * Fill in a list of LocalBluetoothProfile objects that are supported by
+ * the local device and the remote device.
+ *
+ * @param uuids of the remote device
+ * @param localUuids UUIDs of the local device
+ * @param profiles The list of profiles to fill
+ */
+ synchronized void updateProfiles(ParcelUuid[] uuids, ParcelUuid[] localUuids,
+ Collection<LocalBluetoothProfile> profiles) {
+ profiles.clear();
- @Override
- public boolean disconnect(BluetoothDevice device) {
- return mService.disconnect(device);
+ if (uuids == null) {
+ return;
}
- @Override
- public int getSummary(BluetoothDevice device) {
- final int connectionStatus = getConnectionStatus(device);
-
- if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) {
- return R.string.bluetooth_pan_profile_summary_connected;
- } else {
- return SettingsBtStatus.getConnectionStatusSummary(connectionStatus);
+ if (mHeadsetProfile != null) {
+ if ((BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG) &&
+ BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP)) ||
+ (BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) &&
+ BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) {
+ profiles.add(mHeadsetProfile);
}
}
- @Override
- public boolean isProfileReady() {
- return true;
+ if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) &&
+ mA2dpProfile != null) {
+ profiles.add(mA2dpProfile);
}
- @Override
- public List<BluetoothDevice> getConnectedDevices() {
- return mService.getConnectedDevices();
+ if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) &&
+ mOppProfile != null) {
+ profiles.add(mOppProfile);
}
- @Override
- public int getConnectionStatus(BluetoothDevice device) {
- return convertState(mService.getConnectionState(device));
- }
-
- @Override
- public int getPreferred(BluetoothDevice device) {
- return -1;
- }
-
- @Override
- public boolean isPreferred(BluetoothDevice device) {
- return true;
- }
-
- @Override
- public void setPreferred(BluetoothDevice device, boolean preferred) {
- // ignore: isPreferred is always true for PAN
- return;
+ if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hid) &&
+ mHidProfile != null) {
+ profiles.add(mHidProfile);
}
- @Override
- public int getDrawableResource() {
- return R.drawable.ic_bt_network_pan;
+ if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP) &&
+ mPanProfile != null) {
+ profiles.add(mPanProfile);
}
}
}
diff --git a/src/com/android/settings/bluetooth/OppProfile.java b/src/com/android/settings/bluetooth/OppProfile.java
new file mode 100644
index 000000000..7cbae37e8
--- /dev/null
+++ b/src/com/android/settings/bluetooth/OppProfile.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+
+import com.android.settings.R;
+
+/**
+ * OppProfile handles Bluetooth OPP.
+ */
+final class OppProfile implements LocalBluetoothProfile {
+
+ static final String NAME = "OPP";
+
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 2;
+
+ public boolean isConnectable() {
+ return false;
+ }
+
+ public boolean isAutoConnectable() {
+ return false;
+ }
+
+ public boolean connect(BluetoothDevice device) {
+ return false;
+ }
+
+ public boolean disconnect(BluetoothDevice device) {
+ return false;
+ }
+
+ public int getConnectionStatus(BluetoothDevice device) {
+ return -1; // FIXME: change to DISCONNECTED?
+ }
+
+ public boolean isPreferred(BluetoothDevice device) {
+ return false;
+ }
+
+ public int getPreferred(BluetoothDevice device) {
+ return -1; // FIXME: is this correct?
+ }
+
+ public void setPreferred(BluetoothDevice device, boolean preferred) {
+ }
+
+ public boolean isProfileReady() {
+ return true;
+ }
+
+ public String toString() {
+ return NAME;
+ }
+
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ public int getNameResource() {
+ return R.string.bluetooth_profile_opp;
+ }
+
+ public int getDisconnectResource() {
+ return 0; // user must use notification to disconnect OPP transfer.
+ }
+
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ return 0; // OPP profile not displayed in UI
+ }
+
+ public int getDrawableResource(BluetoothClass btClass) {
+ return 0; // no icon for OPP
+ }
+}
diff --git a/src/com/android/settings/bluetooth/PanProfile.java b/src/com/android/settings/bluetooth/PanProfile.java
new file mode 100644
index 000000000..3f456e45b
--- /dev/null
+++ b/src/com/android/settings/bluetooth/PanProfile.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settings.R;
+
+import java.util.List;
+
+/**
+ * PanProfile handles Bluetooth PAN profile.
+ */
+final class PanProfile implements LocalBluetoothProfile {
+ private BluetoothPan mService;
+
+ static final String NAME = "PAN";
+
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 4;
+
+ // These callbacks run on the main thread.
+ private final class PanServiceListener
+ implements BluetoothProfile.ServiceListener {
+
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ mService = (BluetoothPan) proxy;
+ }
+
+ public void onServiceDisconnected(int profile) {
+ mService = null;
+ }
+ }
+
+ PanProfile(Context context) {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ adapter.getProfileProxy(context, new PanServiceListener(),
+ BluetoothProfile.PAN);
+ }
+
+ public boolean isConnectable() {
+ return true;
+ }
+
+ public boolean isAutoConnectable() {
+ return false;
+ }
+
+ public boolean connect(BluetoothDevice device) {
+ List<BluetoothDevice> sinks = mService.getConnectedDevices();
+ if (sinks != null) {
+ for (BluetoothDevice sink : sinks) {
+ mService.disconnect(sink);
+ }
+ }
+ return mService.connect(device);
+ }
+
+ public boolean disconnect(BluetoothDevice device) {
+ return mService.disconnect(device);
+ }
+
+ public int getConnectionStatus(BluetoothDevice device) {
+ return mService.getConnectionState(device);
+ }
+
+ public boolean isPreferred(BluetoothDevice device) {
+ return true;
+ }
+
+ public int getPreferred(BluetoothDevice device) {
+ return -1;
+ }
+
+ public void setPreferred(BluetoothDevice device, boolean preferred) {
+ // ignore: isPreferred is always true for PAN
+ }
+
+ public boolean isProfileReady() {
+ return true;
+ }
+
+ public String toString() {
+ return NAME;
+ }
+
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ public int getNameResource() {
+ return R.string.bluetooth_profile_pan;
+ }
+
+ public int getDisconnectResource() {
+ return R.string.bluetooth_disconnect_pan_profile;
+ }
+
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ int state = mService.getConnectionState(device);
+ switch (state) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ return R.string.bluetooth_pan_profile_summary_use_for;
+
+ case BluetoothProfile.STATE_CONNECTED:
+ return R.string.bluetooth_pan_profile_summary_connected;
+
+ default:
+ return Utils.getConnectionStateSummary(state);
+ }
+ }
+
+ public int getDrawableResource(BluetoothClass btClass) {
+ return R.drawable.ic_bt_network_pan;
+ }
+}
diff --git a/src/com/android/settings/bluetooth/RequestPermissionActivity.java b/src/com/android/settings/bluetooth/RequestPermissionActivity.java
index 93d05bc52..07a7316cb 100644
--- a/src/com/android/settings/bluetooth/RequestPermissionActivity.java
+++ b/src/com/android/settings/bluetooth/RequestPermissionActivity.java
@@ -27,7 +27,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
@@ -51,7 +50,7 @@ public class RequestPermissionActivity extends Activity implements
private static final int REQUEST_CODE_START_BT = 1;
- private LocalBluetoothManager mLocalManager;
+ private LocalBluetoothAdapter mLocalAdapter;
private int mTimeout = BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT;
@@ -66,18 +65,19 @@ public class RequestPermissionActivity extends Activity implements
// True if requesting BT to be turned on
// False if requesting BT to be turned on + discoverable mode
- private boolean mEnableOnly = false;
+ private boolean mEnableOnly;
- private boolean mUserConfirmed = false;
+ private boolean mUserConfirmed;
- private AlertDialog mDialog = null;
+ private AlertDialog mDialog;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (intent == null)
+ if (intent == null) {
return;
+ }
if (mNeededToEnableBluetooth
&& BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothDevice.ERROR);
@@ -94,12 +94,13 @@ public class RequestPermissionActivity extends Activity implements
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ // Note: initializes mLocalAdapter and returns true on error
if (parseIntent()) {
finish();
return;
}
- int btState = mLocalManager.getBluetoothState();
+ int btState = mLocalAdapter.getState();
switch (btState) {
case BluetoothAdapter.STATE_OFF:
@@ -120,28 +121,29 @@ public class RequestPermissionActivity extends Activity implements
*/
registerReceiver(mReceiver,
new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
- Intent i = new Intent();
- i.setClass(this, RequestPermissionHelperActivity.class);
+ Intent intent = new Intent();
+ intent.setClass(this, RequestPermissionHelperActivity.class);
if (mEnableOnly) {
- i.setAction(RequestPermissionHelperActivity.ACTION_INTERNAL_REQUEST_BT_ON);
+ intent.setAction(RequestPermissionHelperActivity.ACTION_INTERNAL_REQUEST_BT_ON);
} else {
- i.setAction(RequestPermissionHelperActivity.
+ intent.setAction(RequestPermissionHelperActivity.
ACTION_INTERNAL_REQUEST_BT_ON_AND_DISCOVERABLE);
- i.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, mTimeout);
+ intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, mTimeout);
}
- startActivityForResult(i, REQUEST_CODE_START_BT);
+ startActivityForResult(intent, REQUEST_CODE_START_BT);
mNeededToEnableBluetooth = true;
break;
case BluetoothAdapter.STATE_ON:
if (mEnableOnly) {
// Nothing to do. Already enabled.
proceedAndFinish();
- return;
} else {
// Ask the user about enabling discovery mode
createDialog();
- break;
}
+ break;
+ default:
+ Log.e(TAG, "Unknown adapter state: " + btState);
}
}
@@ -176,8 +178,8 @@ public class RequestPermissionActivity extends Activity implements
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != REQUEST_CODE_START_BT) {
- Log.e(TAG, "Unexpected onActivityResult " + requestCode + " " + resultCode);
- setResult(Activity.RESULT_CANCELED);
+ Log.e(TAG, "Unexpected onActivityResult " + requestCode + ' ' + resultCode);
+ setResult(RESULT_CANCELED);
finish();
return;
}
@@ -191,7 +193,7 @@ public class RequestPermissionActivity extends Activity implements
// BT and discoverable mode.
mUserConfirmed = true;
- if (mLocalManager.getBluetoothState() == BluetoothAdapter.STATE_ON) {
+ if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON) {
proceedAndFinish();
} else {
// If BT is not up yet, show "Turning on Bluetooth..."
@@ -206,7 +208,7 @@ public class RequestPermissionActivity extends Activity implements
break;
case DialogInterface.BUTTON_NEGATIVE:
- setResult(Activity.RESULT_CANCELED);
+ setResult(RESULT_CANCELED);
finish();
break;
}
@@ -217,18 +219,19 @@ public class RequestPermissionActivity extends Activity implements
if (mEnableOnly) {
// BT enabled. Done
- returnCode = Activity.RESULT_OK;
- } else if (mLocalManager.getBluetoothAdapter().setScanMode(
+ returnCode = RESULT_OK;
+ } else if (mLocalAdapter.setScanMode(
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, mTimeout)) {
// If already in discoverable mode, this will extend the timeout.
- persistDiscoverableEndTimestamp(System.currentTimeMillis() + mTimeout * 1000);
+ LocalBluetoothPreferences.persistDiscoverableEndTimestamp(
+ this, System.currentTimeMillis() + (long) mTimeout * 1000);
returnCode = mTimeout;
// Activity.RESULT_FIRST_USER should be 1
- if (returnCode < Activity.RESULT_FIRST_USER) {
- returnCode = Activity.RESULT_FIRST_USER;
+ if (returnCode < RESULT_FIRST_USER) {
+ returnCode = RESULT_FIRST_USER;
}
} else {
- returnCode = Activity.RESULT_CANCELED;
+ returnCode = RESULT_CANCELED;
}
if (mDialog != null) {
@@ -239,6 +242,10 @@ public class RequestPermissionActivity extends Activity implements
finish();
}
+ /**
+ * Parse the received Intent and initialize mLocalBluetoothAdapter.
+ * @return true if an error occurred; false otherwise
+ */
private boolean parseIntent() {
Intent intent = getIntent();
if (intent != null && intent.getAction().equals(BluetoothAdapter.ACTION_REQUEST_ENABLE)) {
@@ -257,16 +264,17 @@ public class RequestPermissionActivity extends Activity implements
Log.e(TAG, "Error: this activity may be started only with intent "
+ BluetoothAdapter.ACTION_REQUEST_ENABLE + " or "
+ BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
- setResult(Activity.RESULT_CANCELED);
+ setResult(RESULT_CANCELED);
return true;
}
- mLocalManager = LocalBluetoothManager.getInstance(this);
- if (mLocalManager == null) {
- Log.e(TAG, "Error: there's a problem starting bluetooth");
- setResult(Activity.RESULT_CANCELED);
+ LocalBluetoothManager manager = LocalBluetoothManager.getInstance(this);
+ if (manager == null) {
+ Log.e(TAG, "Error: there's a problem starting Bluetooth");
+ setResult(RESULT_CANCELED);
return true;
}
+ mLocalAdapter = manager.getBluetoothAdapter();
return false;
}
@@ -274,20 +282,14 @@ public class RequestPermissionActivity extends Activity implements
@Override
protected void onDestroy() {
super.onDestroy();
- if (mNeededToEnableBluetooth) unregisterReceiver(mReceiver);
- }
-
- private void persistDiscoverableEndTimestamp(long endTimestamp) {
- SharedPreferences.Editor editor = mLocalManager.getSharedPreferences().edit();
- editor.putLong(
- BluetoothDiscoverableEnabler.SHARED_PREFERENCES_KEY_DISCOVERABLE_END_TIMESTAMP,
- endTimestamp);
- editor.apply();
+ if (mNeededToEnableBluetooth) {
+ unregisterReceiver(mReceiver);
+ }
}
@Override
public void onBackPressed() {
- setResult(Activity.RESULT_CANCELED);
+ setResult(RESULT_CANCELED);
super.onBackPressed();
}
}
diff --git a/src/com/android/settings/bluetooth/RequestPermissionHelperActivity.java b/src/com/android/settings/bluetooth/RequestPermissionHelperActivity.java
index 2657d91b8..9b5946b59 100644
--- a/src/com/android/settings/bluetooth/RequestPermissionHelperActivity.java
+++ b/src/com/android/settings/bluetooth/RequestPermissionHelperActivity.java
@@ -43,7 +43,7 @@ public class RequestPermissionHelperActivity extends AlertActivity implements
public static final String ACTION_INTERNAL_REQUEST_BT_ON_AND_DISCOVERABLE =
"com.android.settings.bluetooth.ACTION_INTERNAL_REQUEST_BT_ON_AND_DISCOVERABLE";
- private LocalBluetoothManager mLocalManager;
+ private LocalBluetoothAdapter mLocalAdapter;
private int mTimeout;
@@ -55,6 +55,7 @@ public class RequestPermissionHelperActivity extends AlertActivity implements
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ // Note: initializes mLocalAdapter and returns true on error
if (parseIntent()) {
finish();
return;
@@ -92,32 +93,33 @@ public class RequestPermissionHelperActivity extends AlertActivity implements
public void onClick(DialogInterface dialog, int which) {
int returnCode;
+ // FIXME: fix this ugly switch logic!
switch (which) {
- case DialogInterface.BUTTON_POSITIVE:
+ case BUTTON_POSITIVE:
int btState = 0;
try {
// TODO There's a better way.
int retryCount = 30;
do {
- btState = mLocalManager.getBluetoothState();
+ btState = mLocalAdapter.getBluetoothState();
Thread.sleep(100);
} while (btState == BluetoothAdapter.STATE_TURNING_OFF && --retryCount > 0);
- } catch (InterruptedException e) {
+ } catch (InterruptedException ignored) {
// don't care
}
if (btState == BluetoothAdapter.STATE_TURNING_ON
|| btState == BluetoothAdapter.STATE_ON
- || mLocalManager.getBluetoothAdapter().enable()) {
+ || mLocalAdapter.enable()) {
returnCode = RequestPermissionActivity.RESULT_BT_STARTING_OR_STARTED;
} else {
- returnCode = Activity.RESULT_CANCELED;
+ returnCode = RESULT_CANCELED;
}
break;
- case DialogInterface.BUTTON_NEGATIVE:
- returnCode = Activity.RESULT_CANCELED;
+ case BUTTON_NEGATIVE:
+ returnCode = RESULT_CANCELED;
break;
default:
return;
@@ -125,6 +127,10 @@ public class RequestPermissionHelperActivity extends AlertActivity implements
setResult(returnCode);
}
+ /**
+ * Parse the received Intent and initialize mLocalBluetoothAdapter.
+ * @return true if an error occurred; false otherwise
+ */
private boolean parseIntent() {
Intent intent = getIntent();
if (intent != null && intent.getAction().equals(ACTION_INTERNAL_REQUEST_BT_ON)) {
@@ -136,23 +142,24 @@ public class RequestPermissionHelperActivity extends AlertActivity implements
mTimeout = intent.getIntExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,
BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT);
} else {
- setResult(Activity.RESULT_CANCELED);
+ setResult(RESULT_CANCELED);
return true;
}
- mLocalManager = LocalBluetoothManager.getInstance(this);
- if (mLocalManager == null) {
- Log.e(TAG, "Error: there's a problem starting bluetooth");
- setResult(Activity.RESULT_CANCELED);
+ LocalBluetoothManager manager = LocalBluetoothManager.getInstance(this);
+ if (manager == null) {
+ Log.e(TAG, "Error: there's a problem starting Bluetooth");
+ setResult(RESULT_CANCELED);
return true;
}
+ mLocalAdapter = manager.getBluetoothAdapter();
return false;
}
@Override
public void onBackPressed() {
- setResult(Activity.RESULT_CANCELED);
+ setResult(RESULT_CANCELED);
super.onBackPressed();
}
}
diff --git a/src/com/android/settings/bluetooth/SettingsBtStatus.java b/src/com/android/settings/bluetooth/SettingsBtStatus.java
deleted file mode 100644
index 2407b533d..000000000
--- a/src/com/android/settings/bluetooth/SettingsBtStatus.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.bluetooth;
-
-import android.bluetooth.BluetoothDevice;
-
-import com.android.settings.R;
-
-/**
- * SettingsBtStatus is a helper class that contains constants for various status
- * codes.
- */
-class SettingsBtStatus {
- private static final String TAG = "SettingsBtStatus";
-
- // Connection status
-
- public static final int CONNECTION_STATUS_UNKNOWN = 0;
- public static final int CONNECTION_STATUS_ACTIVE = 1;
- /** Use {@link #isConnectionStatusConnected} to check for the connected state */
- public static final int CONNECTION_STATUS_CONNECTED = 2;
- public static final int CONNECTION_STATUS_CONNECTING = 3;
- public static final int CONNECTION_STATUS_DISCONNECTED = 4;
- public static final int CONNECTION_STATUS_DISCONNECTING = 5;
-
- public static final int getConnectionStatusSummary(int connectionStatus) {
- switch (connectionStatus) {
- case CONNECTION_STATUS_ACTIVE:
- return R.string.bluetooth_connected;
- case CONNECTION_STATUS_CONNECTED:
- return R.string.bluetooth_connected;
- case CONNECTION_STATUS_CONNECTING:
- return R.string.bluetooth_connecting;
- case CONNECTION_STATUS_DISCONNECTED:
- return R.string.bluetooth_disconnected;
- case CONNECTION_STATUS_DISCONNECTING:
- return R.string.bluetooth_disconnecting;
- case CONNECTION_STATUS_UNKNOWN:
- return R.string.bluetooth_unknown;
- default:
- return 0;
- }
- }
-
- public static final boolean isConnectionStatusConnected(int connectionStatus) {
- return connectionStatus == CONNECTION_STATUS_ACTIVE
- || connectionStatus == CONNECTION_STATUS_CONNECTED;
- }
-
- public static final boolean isConnectionStatusBusy(int connectionStatus) {
- return connectionStatus == CONNECTION_STATUS_CONNECTING
- || connectionStatus == CONNECTION_STATUS_DISCONNECTING;
- }
-
- public static final int getPairingStatusSummary(int bondState) {
- switch (bondState) {
- case BluetoothDevice.BOND_BONDED:
- return R.string.bluetooth_paired;
- case BluetoothDevice.BOND_BONDING:
- return R.string.bluetooth_pairing;
- case BluetoothDevice.BOND_NONE:
- return R.string.bluetooth_not_connected;
- default:
- return 0;
- }
- }
-}
diff --git a/src/com/android/settings/bluetooth/Utf8ByteLengthFilter.java b/src/com/android/settings/bluetooth/Utf8ByteLengthFilter.java
new file mode 100644
index 000000000..bae6e5682
--- /dev/null
+++ b/src/com/android/settings/bluetooth/Utf8ByteLengthFilter.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.text.InputFilter;
+import android.text.Spanned;
+
+/**
+ * This filter will constrain edits so that the text length is not
+ * greater than the specified number of bytes using UTF-8 encoding.
+ * <p>The JNI method used by {@link android.server.BluetoothService}
+ * to convert UTF-16 to UTF-8 doesn't support surrogate pairs,
+ * therefore code points outside of the basic multilingual plane
+ * (0000-FFFF) will be encoded as a pair of 3-byte UTF-8 characters,
+ * rather than a single 4-byte UTF-8 encoding. Dalvik implements this
+ * conversion in {@code convertUtf16ToUtf8()} in
+ * {@code dalvik/vm/UtfString.c}.
+ * <p>This JNI method is unlikely to change in the future due to
+ * backwards compatibility requirements. It's also unclear whether
+ * the installed base of Bluetooth devices would correctly handle the
+ * encoding of surrogate pairs in UTF-8 as 4 bytes rather than 6.
+ * However, this filter will still work in scenarios where surrogate
+ * pairs are encoded as 4 bytes, with the caveat that the maximum
+ * length will be constrained more conservatively than necessary.
+ */
+class Utf8ByteLengthFilter implements InputFilter {
+ private final int mMaxBytes;
+
+ Utf8ByteLengthFilter(int maxBytes) {
+ mMaxBytes = maxBytes;
+ }
+
+ public CharSequence filter(CharSequence source, int start, int end,
+ Spanned dest, int dstart, int dend) {
+ int srcByteCount = 0;
+ // count UTF-8 bytes in source substring
+ for (int i = start; i < end; i++) {
+ char c = source.charAt(i);
+ srcByteCount += (c < (char) 0x0080) ? 1 : (c < (char) 0x0800 ? 2 : 3);
+ }
+ int destLen = dest.length();
+ int destByteCount = 0;
+ // count UTF-8 bytes in destination excluding replaced section
+ for (int i = 0; i < destLen; i++) {
+ if (i < dstart || i >= dend) {
+ char c = dest.charAt(i);
+ destByteCount += (c < (char) 0x0080) ? 1 : (c < (char) 0x0800 ? 2 : 3);
+ }
+ }
+ int keepBytes = mMaxBytes - destByteCount;
+ if (keepBytes <= 0) {
+ return "";
+ } else if (keepBytes >= srcByteCount) {
+ return null; // use original dest string
+ } else {
+ // find end position of largest sequence that fits in keepBytes
+ for (int i = start; i < end; i++) {
+ char c = source.charAt(i);
+ keepBytes -= (c < (char) 0x0080) ? 1 : (c < (char) 0x0800 ? 2 : 3);
+ if (keepBytes < 0) {
+ return source.subSequence(start, i);
+ }
+ }
+ // If the entire substring fits, we should have returned null
+ // above, so this line should not be reached. If for some
+ // reason it is, return null to use the original dest string.
+ return null;
+ }
+ }
+}
diff --git a/src/com/android/settings/bluetooth/Utils.java b/src/com/android/settings/bluetooth/Utils.java
new file mode 100644
index 000000000..7d38e1700
--- /dev/null
+++ b/src/com/android/settings/bluetooth/Utils.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.app.AlertDialog;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.widget.Toast;
+
+import com.android.settings.R;
+
+/**
+ * Utils is a helper class that contains constants for various
+ * Android resource IDs, debug logging flags, and static methods
+ * for creating dialogs.
+ */
+final class Utils {
+ static final boolean V = false; // verbose logging
+ static final boolean D = true; // regular logging
+
+ private Utils() {
+ }
+
+ public static int getConnectionStateSummary(int connectionState) {
+ switch (connectionState) {
+ case BluetoothProfile.STATE_CONNECTED:
+ return R.string.bluetooth_connected;
+ case BluetoothProfile.STATE_CONNECTING:
+ return R.string.bluetooth_connecting;
+ case BluetoothProfile.STATE_DISCONNECTED:
+ return R.string.bluetooth_disconnected;
+ case BluetoothProfile.STATE_DISCONNECTING:
+ return R.string.bluetooth_disconnecting;
+ default:
+ return 0;
+ }
+ }
+
+ // Create (or recycle existing) and show disconnect dialog.
+ static AlertDialog showDisconnectDialog(Context context,
+ AlertDialog dialog,
+ DialogInterface.OnClickListener disconnectListener,
+ CharSequence title, CharSequence message) {
+ if (dialog == null) {
+ dialog = new AlertDialog.Builder(context)
+ .setPositiveButton(android.R.string.ok, disconnectListener)
+ .setNegativeButton(android.R.string.cancel, null)
+ .create();
+ } else {
+ if (dialog.isShowing()) {
+ dialog.dismiss();
+ }
+ // use disconnectListener for the correct profile(s)
+ CharSequence okText = context.getText(android.R.string.ok);
+ dialog.setButton(DialogInterface.BUTTON_POSITIVE,
+ okText, disconnectListener);
+ }
+ dialog.setTitle(title);
+ dialog.setMessage(message);
+ dialog.show();
+ return dialog;
+ }
+
+ // TODO: wire this up to show connection errors...
+ static void showConnectingError(Context context, String name) {
+ // if (!mIsConnectingErrorPossible) {
+ // return;
+ // }
+ // mIsConnectingErrorPossible = false;
+
+ showError(context, name, R.string.bluetooth_connecting_error_message);
+ }
+
+ static void showError(Context context, String name, int messageResId) {
+ String message = context.getString(messageResId, name);
+ new AlertDialog.Builder(context)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setTitle(R.string.bluetooth_error_title)
+ .setMessage(message)
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ }
+}
diff --git a/src/com/android/settings/widget/SettingsAppWidgetProvider.java b/src/com/android/settings/widget/SettingsAppWidgetProvider.java
index 8f17e05e6..ba2b61541 100644
--- a/src/com/android/settings/widget/SettingsAppWidgetProvider.java
+++ b/src/com/android/settings/widget/SettingsAppWidgetProvider.java
@@ -38,6 +38,7 @@ import android.provider.Settings;
import android.util.Log;
import android.widget.RemoteViews;
import com.android.settings.R;
+import com.android.settings.bluetooth.LocalBluetoothAdapter;
import com.android.settings.bluetooth.LocalBluetoothManager;
/**
@@ -50,7 +51,7 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider {
new ComponentName("com.android.settings",
"com.android.settings.widget.SettingsAppWidgetProvider");
- private static LocalBluetoothManager sLocalBluetoothManager = null;
+ private static LocalBluetoothAdapter sLocalBluetoothAdapter = null;
private static final int BUTTON_WIFI = 0;
private static final int BUTTON_BRIGHTNESS = 1;
@@ -411,18 +412,19 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider {
@Override
public int getActualState(Context context) {
- if (sLocalBluetoothManager == null) {
- sLocalBluetoothManager = LocalBluetoothManager.getInstance(context);
- if (sLocalBluetoothManager == null) {
+ if (sLocalBluetoothAdapter == null) {
+ LocalBluetoothManager manager = LocalBluetoothManager.getInstance(context);
+ if (manager == null) {
return STATE_UNKNOWN; // On emulator?
}
+ sLocalBluetoothAdapter = manager.getBluetoothAdapter();
}
- return bluetoothStateToFiveState(sLocalBluetoothManager.getBluetoothState());
+ return bluetoothStateToFiveState(sLocalBluetoothAdapter.getBluetoothState());
}
@Override
protected void requestStateChange(Context context, final boolean desiredState) {
- if (sLocalBluetoothManager == null) {
+ if (sLocalBluetoothAdapter == null) {
Log.d(TAG, "No LocalBluetoothManager");
return;
}
@@ -433,7 +435,7 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... args) {
- sLocalBluetoothManager.setBluetoothEnabled(desiredState);
+ sLocalBluetoothAdapter.setBluetoothEnabled(desiredState);
return null;
}
}.execute();
@@ -584,7 +586,7 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider {
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
// Update each requested appWidgetId
- RemoteViews view = buildUpdate(context, -1);
+ RemoteViews view = buildUpdate(context);
for (int i = 0; i < appWidgetIds.length; i++) {
appWidgetManager.updateAppWidget(appWidgetIds[i], view);
@@ -613,22 +615,22 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider {
/**
* Load image for given widget and build {@link RemoteViews} for it.
*/
- static RemoteViews buildUpdate(Context context, int appWidgetId) {
+ static RemoteViews buildUpdate(Context context) {
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.widget);
- views.setOnClickPendingIntent(R.id.btn_wifi, getLaunchPendingIntent(context, appWidgetId,
+ views.setOnClickPendingIntent(R.id.btn_wifi, getLaunchPendingIntent(context,
BUTTON_WIFI));
views.setOnClickPendingIntent(R.id.btn_brightness,
getLaunchPendingIntent(context,
- appWidgetId, BUTTON_BRIGHTNESS));
+ BUTTON_BRIGHTNESS));
views.setOnClickPendingIntent(R.id.btn_sync,
getLaunchPendingIntent(context,
- appWidgetId, BUTTON_SYNC));
+ BUTTON_SYNC));
views.setOnClickPendingIntent(R.id.btn_gps,
- getLaunchPendingIntent(context, appWidgetId, BUTTON_GPS));
+ getLaunchPendingIntent(context, BUTTON_GPS));
views.setOnClickPendingIntent(R.id.btn_bluetooth,
getLaunchPendingIntent(context,
- appWidgetId, BUTTON_BLUETOOTH));
+ BUTTON_BLUETOOTH));
updateButtons(views, context);
return views;
@@ -640,7 +642,7 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider {
* @param context
*/
public static void updateWidget(Context context) {
- RemoteViews views = buildUpdate(context, -1);
+ RemoteViews views = buildUpdate(context);
// Update specific list of appWidgetIds if given, otherwise default to all
final AppWidgetManager gm = AppWidgetManager.getInstance(context);
gm.updateAppWidget(THIS_APPWIDGET, views);
@@ -680,10 +682,9 @@ public class SettingsAppWidgetProvider extends AppWidgetProvider {
* Creates PendingIntent to notify the widget of a button click.
*
* @param context
- * @param appWidgetId
* @return
*/
- private static PendingIntent getLaunchPendingIntent(Context context, int appWidgetId,
+ private static PendingIntent getLaunchPendingIntent(Context context,
int buttonId) {
Intent launchIntent = new Intent();
launchIntent.setClass(context, SettingsAppWidgetProvider.class);