diff options
30 files changed, 900 insertions, 721 deletions
@@ -88,8 +88,8 @@ LOCAL_SRC_FILES += \ core/java/android/backup/IBackupManager.aidl \ core/java/android/backup/IRestoreObserver.aidl \ core/java/android/backup/IRestoreSession.aidl \ + core/java/android/bluetooth/IBluetooth.aidl \ core/java/android/bluetooth/IBluetoothA2dp.aidl \ - core/java/android/bluetooth/IBluetoothDevice.aidl \ core/java/android/bluetooth/IBluetoothHeadset.aidl \ core/java/android/bluetooth/IBluetoothPbap.aidl \ core/java/android/content/IContentService.aidl \ diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java index a74fbe4..7c0d1d3 100644 --- a/core/java/android/app/ApplicationContext.java +++ b/core/java/android/app/ApplicationContext.java @@ -22,8 +22,8 @@ import com.google.android.collect.Maps; import org.xmlpull.v1.XmlPullParserException; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.IBluetoothDevice; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.IBluetooth; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; @@ -158,8 +158,6 @@ class ApplicationContext extends Context { private static ConnectivityManager sConnectivityManager; private static WifiManager sWifiManager; private static LocationManager sLocationManager; - private static boolean sIsBluetoothDeviceCached = false; - private static BluetoothDevice sBluetoothDevice; private static final HashMap<File, SharedPreferencesImpl> sSharedPrefs = new HashMap<File, SharedPreferencesImpl>(); @@ -184,6 +182,8 @@ class ApplicationContext extends Context { private StatusBarManager mStatusBarManager = null; private TelephonyManager mTelephonyManager = null; private ClipboardManager mClipboardManager = null; + private boolean mIsBluetoothAdapterCached = false; + private BluetoothAdapter mBluetoothAdapter; private boolean mRestricted; private final Object mSync = new Object(); @@ -830,7 +830,7 @@ class ApplicationContext extends Context { } else if (SENSOR_SERVICE.equals(name)) { return getSensorManager(); } else if (BLUETOOTH_SERVICE.equals(name)) { - return getBluetoothDevice(); + return getBluetoothAdapter(); } else if (VIBRATOR_SERVICE.equals(name)) { return getVibrator(); } else if (STATUS_BAR_SERVICE.equals(name)) { @@ -980,21 +980,16 @@ class ApplicationContext extends Context { return mSearchManager; } - private BluetoothDevice getBluetoothDevice() { - if (sIsBluetoothDeviceCached) { - return sBluetoothDevice; - } - synchronized (sSync) { + private synchronized BluetoothAdapter getBluetoothAdapter() { + if (!mIsBluetoothAdapterCached) { + mIsBluetoothAdapterCached = true; IBinder b = ServiceManager.getService(BLUETOOTH_SERVICE); - if (b == null) { - sBluetoothDevice = null; - } else { - IBluetoothDevice service = IBluetoothDevice.Stub.asInterface(b); - sBluetoothDevice = new BluetoothDevice(service); + if (b != null) { + IBluetooth service = IBluetooth.Stub.asInterface(b); + mBluetoothAdapter = new BluetoothAdapter(service); } - sIsBluetoothDeviceCached = true; } - return sBluetoothDevice; + return mBluetoothAdapter; } private SensorManager getSensorManager() { diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index 2ea45d5..6e48b66 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -25,7 +25,10 @@ import android.os.RemoteException; import android.os.IBinder; import android.util.Log; -import java.util.List; +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.HashSet; /** * Public API for controlling the Bluetooth A2DP Profile Service. @@ -47,7 +50,7 @@ import java.util.List; * * @hide */ -public class BluetoothA2dp { +public final class BluetoothA2dp { private static final String TAG = "BluetoothA2dp"; private static final boolean DBG = false; @@ -79,6 +82,7 @@ public class BluetoothA2dp { /** Default priority for a2dp devices that should not allow incoming * connections */ public static final int PRIORITY_OFF = 0; + private final IBluetoothA2dp mService; private final Context mContext; @@ -89,6 +93,7 @@ public class BluetoothA2dp { */ public BluetoothA2dp(Context c) { mContext = c; + IBinder b = ServiceManager.getService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE); if (b == null) { throw new RuntimeException("Bluetooth A2DP service not available!"); @@ -99,14 +104,14 @@ public class BluetoothA2dp { /** Initiate a connection to an A2DP sink. * Listen for SINK_STATE_CHANGED_ACTION to find out when the * connection is completed. - * @param address Remote BT address. + * @param device Remote BT device. * @return Result code, negative indicates an immediate error. * @hide */ - public int connectSink(String address) { - if (DBG) log("connectSink(" + address + ")"); + public int connectSink(BluetoothDevice device) { + if (DBG) log("connectSink(" + device + ")"); try { - return mService.connectSink(address); + return mService.connectSink(device); } catch (RemoteException e) { Log.w(TAG, "", e); return BluetoothError.ERROR_IPC; @@ -116,14 +121,14 @@ public class BluetoothA2dp { /** Initiate disconnect from an A2DP sink. * Listen for SINK_STATE_CHANGED_ACTION to find out when * disconnect is completed. - * @param address Remote BT address. + * @param device Remote BT device. * @return Result code, negative indicates an immediate error. * @hide */ - public int disconnectSink(String address) { - if (DBG) log("disconnectSink(" + address + ")"); + public int disconnectSink(BluetoothDevice device) { + if (DBG) log("disconnectSink(" + device + ")"); try { - return mService.disconnectSink(address); + return mService.disconnectSink(device); } catch (RemoteException e) { Log.w(TAG, "", e); return BluetoothError.ERROR_IPC; @@ -131,24 +136,25 @@ public class BluetoothA2dp { } /** Check if a specified A2DP sink is connected. - * @param address Remote BT address. + * @param device Remote BT device. * @return True if connected (or playing), false otherwise and on error. * @hide */ - public boolean isSinkConnected(String address) { - if (DBG) log("isSinkConnected(" + address + ")"); - int state = getSinkState(address); + public boolean isSinkConnected(BluetoothDevice device) { + if (DBG) log("isSinkConnected(" + device + ")"); + int state = getSinkState(device); return state == STATE_CONNECTED || state == STATE_PLAYING; } /** Check if any A2DP sink is connected. - * @return a List of connected A2DP sinks, or null on error. + * @return a unmodifiable set of connected A2DP sinks, or null on error. * @hide */ - public List<String> listConnectedSinks() { - if (DBG) log("listConnectedSinks()"); + public Set<BluetoothDevice> getConnectedSinks() { + if (DBG) log("getConnectedSinks()"); try { - return mService.listConnectedSinks(); + return Collections.unmodifiableSet( + new HashSet<BluetoothDevice>(Arrays.asList(mService.getConnectedSinks()))); } catch (RemoteException e) { Log.w(TAG, "", e); return null; @@ -156,14 +162,14 @@ public class BluetoothA2dp { } /** Get the state of an A2DP sink - * @param address Remote BT address. + * @param device Remote BT device. * @return State code, or negative on error * @hide */ - public int getSinkState(String address) { - if (DBG) log("getSinkState(" + address + ")"); + public int getSinkState(BluetoothDevice device) { + if (DBG) log("getSinkState(" + device + ")"); try { - return mService.getSinkState(address); + return mService.getSinkState(device); } catch (RemoteException e) { Log.w(TAG, "", e); return BluetoothError.ERROR_IPC; @@ -177,15 +183,15 @@ public class BluetoothA2dp { * Sinks with priority greater than zero will accept incoming connections * (if no sink is currently connected). * Priority for unpaired sink must be PRIORITY_NONE. - * @param address Paired sink + * @param device Paired sink * @param priority Integer priority, for example PRIORITY_AUTO or * PRIORITY_NONE * @return Result code, negative indicates an error */ - public int setSinkPriority(String address, int priority) { - if (DBG) log("setSinkPriority(" + address + ", " + priority + ")"); + public int setSinkPriority(BluetoothDevice device, int priority) { + if (DBG) log("setSinkPriority(" + device + ", " + priority + ")"); try { - return mService.setSinkPriority(address, priority); + return mService.setSinkPriority(device, priority); } catch (RemoteException e) { Log.w(TAG, "", e); return BluetoothError.ERROR_IPC; @@ -194,13 +200,13 @@ public class BluetoothA2dp { /** * Get priority of a2dp sink. - * @param address Sink + * @param device Sink * @return non-negative priority, or negative error code on error. */ - public int getSinkPriority(String address) { - if (DBG) log("getSinkPriority(" + address + ")"); + public int getSinkPriority(BluetoothDevice device) { + if (DBG) log("getSinkPriority(" + device + ")"); try { - return mService.getSinkPriority(address); + return mService.getSinkPriority(device); } catch (RemoteException e) { Log.w(TAG, "", e); return BluetoothError.ERROR_IPC; diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java new file mode 100644 index 0000000..d207540 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2009 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 android.bluetooth; + +import android.os.RemoteException; +import android.util.Log; + +import java.io.IOException; +import java.util.Collections; +import java.util.Set; +import java.util.HashSet; + +/** + * Represents the local Bluetooth adapter. + * + * @hide + */ +public final class BluetoothAdapter { + private static final String TAG = "BluetoothAdapter"; + + public static final int BLUETOOTH_STATE_OFF = 0; + public static final int BLUETOOTH_STATE_TURNING_ON = 1; + public static final int BLUETOOTH_STATE_ON = 2; + public static final int BLUETOOTH_STATE_TURNING_OFF = 3; + + /** Inquiry scan and page scan are both off. + * Device is neither discoverable nor connectable */ + public static final int SCAN_MODE_NONE = 0; + /** Page scan is on, inquiry scan is off. + * Device is connectable, but not discoverable */ + public static final int SCAN_MODE_CONNECTABLE = 1; + /** Page scan and inquiry scan are on. + * Device is connectable and discoverable */ + public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 3; + + public static final int RESULT_FAILURE = -1; + public static final int RESULT_SUCCESS = 0; + + /* The user will be prompted to enter a pin */ + public static final int PAIRING_VARIANT_PIN = 0; + /* The user will be prompted to enter a passkey */ + public static final int PAIRING_VARIANT_PASSKEY = 1; + /* The user will be prompted to confirm the passkey displayed on the screen */ + public static final int PAIRING_VARIANT_CONFIRMATION = 2; + + private final IBluetooth mService; + + /** + * Do not use this constructor. Use Context.getSystemService() instead. + * @hide + */ + public BluetoothAdapter(IBluetooth service) { + if (service == null) { + throw new IllegalArgumentException("service is null"); + } + mService = service; + } + + /** + * Get the remote BluetoothDevice associated with the given MAC address. + * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB". + * @param address valid Bluetooth MAC address + */ + public BluetoothDevice getRemoteDevice(String address) { + return new BluetoothDevice(address); + } + + /** + * Is Bluetooth currently turned on. + * + * @return true if Bluetooth enabled, false otherwise. + */ + public boolean isEnabled() { + try { + return mService.isEnabled(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + + /** + * Get the current state of Bluetooth. + * + * @return One of BLUETOOTH_STATE_ or BluetoothError.ERROR. + */ + public int getBluetoothState() { + try { + return mService.getBluetoothState(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return BluetoothError.ERROR; + } + + /** + * Enable the Bluetooth device. + * Turn on the underlying hardware. + * This is an asynchronous call, + * BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION can be used to check if + * and when the device is sucessfully enabled. + * @return false if we cannot enable the Bluetooth device. True does not + * imply the device was enabled, it only implies that so far there were no + * problems. + */ + public boolean enable() { + try { + return mService.enable(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + + /** + * Disable the Bluetooth device. + * This turns off the underlying hardware. + * + * @return true if successful, false otherwise. + */ + public boolean disable() { + try { + return mService.disable(true); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + + public String getAddress() { + try { + return mService.getAddress(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return null; + } + + /** + * Get the friendly Bluetooth name of this device. + * + * This name is visible to remote Bluetooth devices. Currently it is only + * possible to retrieve the Bluetooth name when Bluetooth is enabled. + * + * @return the Bluetooth name, or null if there was a problem. + */ + public String getName() { + try { + return mService.getName(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return null; + } + + /** + * Set the friendly Bluetooth name of this device. + * + * This name is visible to remote Bluetooth devices. The Bluetooth Service + * is responsible for persisting this name. + * + * @param name the name to set + * @return true, if the name was successfully set. False otherwise. + */ + public boolean setName(String name) { + try { + return mService.setName(name); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + + /** + * Get the current scan mode. + * Used to determine if the local device is connectable and/or discoverable + * @return Scan mode, one of SCAN_MODE_* or an error code + */ + public int getScanMode() { + try { + return mService.getScanMode(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return BluetoothError.ERROR_IPC; + } + + /** + * Set the current scan mode. + * Used to make the local device connectable and/or discoverable + * @param scanMode One of SCAN_MODE_* + */ + public void setScanMode(int scanMode) { + try { + mService.setScanMode(scanMode); + } catch (RemoteException e) {Log.e(TAG, "", e);} + } + + public int getDiscoverableTimeout() { + try { + return mService.getDiscoverableTimeout(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return -1; + } + + public void setDiscoverableTimeout(int timeout) { + try { + mService.setDiscoverableTimeout(timeout); + } catch (RemoteException e) {Log.e(TAG, "", e);} + } + + public boolean startDiscovery() { + try { + return mService.startDiscovery(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + + public void cancelDiscovery() { + try { + mService.cancelDiscovery(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + } + + public boolean isDiscovering() { + try { + return mService.isDiscovering(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + + /** + * List remote devices that are bonded (paired) to the local adapter. + * + * Bonding (pairing) is the process by which the user enters a pin code for + * the device, which generates a shared link key, allowing for + * authentication and encryption of future connections. In Android we + * require bonding before RFCOMM or SCO connections can be made to a remote + * device. + * + * This function lists which remote devices we have a link key for. It does + * not cause any RF transmission, and does not check if the remote device + * still has it's link key with us. If the other side no longer has its + * link key then the RFCOMM or SCO connection attempt will result in an + * error. + * + * This function does not check if the remote device is in range. + * + * Remote devices that have an in-progress bonding attempt are not + * returned. + * + * @return unmodifiable set of bonded devices, or null on error + */ + public Set<BluetoothDevice> getBondedDevices() { + try { + return toDeviceSet(mService.listBonds()); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return null; + } + + /** + * Construct a listening, secure RFCOMM server socket. + * The remote device connecting to this socket will be authenticated and + * communication on this socket will be encrypted. + * Call #accept to retrieve connections to this socket. + * @return An RFCOMM BluetoothServerSocket + * @throws IOException On error, for example Bluetooth not available, or + * insufficient permissions. + */ + public BluetoothServerSocket listenUsingRfcommOn(int port) throws IOException { + BluetoothServerSocket socket = new BluetoothServerSocket( + BluetoothSocket.TYPE_RFCOMM, true, true, port); + try { + socket.mSocket.bindListenNative(); + } catch (IOException e) { + try { + socket.close(); + } catch (IOException e2) { } + throw e; + } + return socket; + } + + /** + * Construct an unencrypted, unauthenticated, RFCOMM server socket. + * Call #accept to retrieve connections to this socket. + * @return An RFCOMM BluetoothServerSocket + * @throws IOException On error, for example Bluetooth not available, or + * insufficient permissions. + */ + public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException { + BluetoothServerSocket socket = new BluetoothServerSocket( + BluetoothSocket.TYPE_RFCOMM, false, false, port); + try { + socket.mSocket.bindListenNative(); + } catch (IOException e) { + try { + socket.close(); + } catch (IOException e2) { } + throw e; + } + return socket; + } + + /** + * Construct a SCO server socket. + * Call #accept to retrieve connections to this socket. + * @return A SCO BluetoothServerSocket + * @throws IOException On error, for example Bluetooth not available, or + * insufficient permissions. + */ + public static BluetoothServerSocket listenUsingScoOn() throws IOException { + BluetoothServerSocket socket = new BluetoothServerSocket( + BluetoothSocket.TYPE_SCO, false, false, -1); + try { + socket.mSocket.bindListenNative(); + } catch (IOException e) { + try { + socket.close(); + } catch (IOException e2) { } + throw e; + } + return socket; + } + + private Set<BluetoothDevice> toDeviceSet(String[] addresses) { + Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(addresses.length); + for (int i = 0; i < addresses.length; i++) { + devices.add(getRemoteDevice(addresses[i])); + } + return Collections.unmodifiableSet(devices); + } +} diff --git a/core/java/android/bluetooth/BluetoothAudioGateway.java b/core/java/android/bluetooth/BluetoothAudioGateway.java index f3afd2a..abd7723 100644 --- a/core/java/android/bluetooth/BluetoothAudioGateway.java +++ b/core/java/android/bluetooth/BluetoothAudioGateway.java @@ -9,24 +9,22 @@ import android.util.Log; /** * Listen's for incoming RFCOMM connection for the headset / handsfree service. * - * This class is planned for deletion, in favor of a generic Rfcomm class. + * TODO: Use the new generic BluetoothSocket class instead of this legacy code * * @hide */ -public class BluetoothAudioGateway { +public final class BluetoothAudioGateway { private static final String TAG = "BT Audio Gateway"; private static final boolean DBG = false; private int mNativeData; static { classInitNative(); } - private BluetoothDevice mBluetooth; - /* in */ private int mHandsfreeAgRfcommChannel = -1; private int mHeadsetAgRfcommChannel = -1; - /* out */ + /* out - written by native code */ private String mConnectingHeadsetAddress; private int mConnectingHeadsetRfcommChannel; /* -1 when not connected */ private int mConnectingHeadsetSocketFd; @@ -35,17 +33,18 @@ public class BluetoothAudioGateway { private int mConnectingHandsfreeSocketFd; private int mTimeoutRemainingMs; /* in/out */ + private final BluetoothAdapter mAdapter; + public static final int DEFAULT_HF_AG_CHANNEL = 10; public static final int DEFAULT_HS_AG_CHANNEL = 11; - public BluetoothAudioGateway(BluetoothDevice bluetooth) { - this(bluetooth, DEFAULT_HF_AG_CHANNEL, DEFAULT_HS_AG_CHANNEL); + public BluetoothAudioGateway(BluetoothAdapter adapter) { + this(adapter, DEFAULT_HF_AG_CHANNEL, DEFAULT_HS_AG_CHANNEL); } - public BluetoothAudioGateway(BluetoothDevice bluetooth, - int handsfreeAgRfcommChannel, - int headsetAgRfcommChannel) { - mBluetooth = bluetooth; + public BluetoothAudioGateway(BluetoothAdapter adapter, int handsfreeAgRfcommChannel, + int headsetAgRfcommChannel) { + mAdapter = adapter; mHandsfreeAgRfcommChannel = handsfreeAgRfcommChannel; mHeadsetAgRfcommChannel = headsetAgRfcommChannel; initializeNativeDataNative(); @@ -58,18 +57,17 @@ public class BluetoothAudioGateway { private Handler mCallback; public class IncomingConnectionInfo { - IncomingConnectionInfo(BluetoothDevice bluetooth, String address, int socketFd, - int rfcommChan) { - mBluetooth = bluetooth; - mAddress = address; + public BluetoothAdapter mAdapter; + public BluetoothDevice mRemoteDevice; + public int mSocketFd; + public int mRfcommChan; + IncomingConnectionInfo(BluetoothAdapter adapter, BluetoothDevice remoteDevice, + int socketFd, int rfcommChan) { + mAdapter = adapter; + mRemoteDevice = remoteDevice; mSocketFd = socketFd; mRfcommChan = rfcommChan; } - - public BluetoothDevice mBluetooth; - public String mAddress; - public int mSocketFd; - public int mRfcommChan; } public static final int MSG_INCOMING_HEADSET_CONNECTION = 100; @@ -111,12 +109,11 @@ public class BluetoothAudioGateway { mConnectingHeadsetRfcommChannel); Message msg = Message.obtain(mCallback); msg.what = MSG_INCOMING_HEADSET_CONNECTION; - msg.obj = - new IncomingConnectionInfo( - mBluetooth, - mConnectingHeadsetAddress, - mConnectingHeadsetSocketFd, - mConnectingHeadsetRfcommChannel); + msg.obj = new IncomingConnectionInfo( + mAdapter, + mAdapter.getRemoteDevice(mConnectingHeadsetAddress), + mConnectingHeadsetSocketFd, + mConnectingHeadsetRfcommChannel); msg.sendToTarget(); } if (mConnectingHandsfreeRfcommChannel >= 0) { @@ -126,12 +123,11 @@ public class BluetoothAudioGateway { Message msg = Message.obtain(); msg.setTarget(mCallback); msg.what = MSG_INCOMING_HANDSFREE_CONNECTION; - msg.obj = - new IncomingConnectionInfo( - mBluetooth, - mConnectingHandsfreeAddress, - mConnectingHandsfreeSocketFd, - mConnectingHandsfreeRfcommChannel); + msg.obj = new IncomingConnectionInfo( + mAdapter, + mAdapter.getRemoteDevice(mConnectingHandsfreeAddress), + mConnectingHandsfreeSocketFd, + mConnectingHandsfreeRfcommChannel); msg.sendToTarget(); } } diff --git a/core/java/android/bluetooth/BluetoothDevice.aidl b/core/java/android/bluetooth/BluetoothDevice.aidl new file mode 100644 index 0000000..daae74d --- /dev/null +++ b/core/java/android/bluetooth/BluetoothDevice.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2009 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 android.bluetooth; + +parcelable BluetoothDevice; diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index a64c6d7..27b2849 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2009 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,39 +16,25 @@ package android.bluetooth; +import android.content.Context; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; import android.os.RemoteException; +import android.os.ServiceManager; import android.util.Log; +import java.io.IOException; import java.io.UnsupportedEncodingException; /** - * The Android Bluetooth API is not finalized, and *will* change. Use at your - * own risk. - * - * Manages the local Bluetooth device. Scan for devices, create bondings, - * power up and down the adapter. + * Represents a remote Bluetooth device. * + * TODO: unhide * @hide */ -public class BluetoothDevice { - - public static final int BLUETOOTH_STATE_OFF = 0; - public static final int BLUETOOTH_STATE_TURNING_ON = 1; - public static final int BLUETOOTH_STATE_ON = 2; - public static final int BLUETOOTH_STATE_TURNING_OFF = 3; - - /** Inquiry scan and page scan are both off. - * Device is neither discoverable nor connectable */ - public static final int SCAN_MODE_NONE = 0; - /** Page scan is on, inquiry scan is off. - * Device is connectable, but not discoverable */ - public static final int SCAN_MODE_CONNECTABLE = 1; - /** Page scan and inquiry scan are on. - * Device is connectable and discoverable */ - public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 3; - - public static final int RESULT_FAILURE = -1; - public static final int RESULT_SUCCESS = 0; +public final class BluetoothDevice implements Parcelable { + private static final String TAG = "BluetoothDevice"; /** We do not have a link key for the remote device, and are therefore not * bonded */ @@ -81,84 +67,81 @@ public class BluetoothDevice { /* The user will be prompted to confirm the passkey displayed on the screen */ public static final int PAIRING_VARIANT_CONFIRMATION = 2; + private static final int ADDRESS_LENGTH = 17; - private static final String TAG = "BluetoothDevice"; + private static IBluetooth sService; /* Guarenteed constant after first object constructed */ + + private final String mAddress; - private final IBluetoothDevice mService; /** - * @hide - hide this because it takes a parameter of type - * IBluetoothDevice, which is a System private class. - * Also note that Context.getSystemService is a factory that - * returns a BlueToothDevice. That is the right way to get - * a BluetoothDevice. + * Create a new BluetoothDevice + * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB", + * and is validated in this constructor. + * @param address valid Bluetooth MAC address + * @throws RuntimeException Bluetooth is not available on this platform + * @throws IllegalArgumentException address is invalid + * @hide */ - public BluetoothDevice(IBluetoothDevice service) { - mService = service; + /*package*/ BluetoothDevice(String address) { + synchronized (BluetoothDevice.class) { + if (sService == null) { + IBinder b = ServiceManager.getService(Context.BLUETOOTH_SERVICE); + if (b == null) { + throw new RuntimeException("Bluetooth service not available"); + } + sService = IBluetooth.Stub.asInterface(b); + } + } + + if (!checkBluetoothAddress(address)) { + throw new IllegalArgumentException(address + " is not a valid Bluetooth address"); + } + + mAddress = address; } - /** - * Is Bluetooth currently turned on. - * - * @return true if Bluetooth enabled, false otherwise. - */ - public boolean isEnabled() { - try { - return mService.isEnabled(); - } catch (RemoteException e) {Log.e(TAG, "", e);} + @Override + public boolean equals(Object o) { + if (o instanceof BluetoothDevice) { + return mAddress.equals(((BluetoothDevice)o).getAddress()); + } return false; } - /** - * Get the current state of Bluetooth. - * - * @return One of BLUETOOTH_STATE_ or BluetoothError.ERROR. - */ - public int getBluetoothState() { - try { - return mService.getBluetoothState(); - } catch (RemoteException e) {Log.e(TAG, "", e);} - return BluetoothError.ERROR; + @Override + public int hashCode() { + return mAddress.hashCode(); } - /** - * Enable the Bluetooth device. - * Turn on the underlying hardware. - * This is an asynchronous call, - * BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION can be used to check if - * and when the device is sucessfully enabled. - * @return false if we cannot enable the Bluetooth device. True does not - * imply the device was enabled, it only implies that so far there were no - * problems. - */ - public boolean enable() { - try { - return mService.enable(); - } catch (RemoteException e) {Log.e(TAG, "", e);} - return false; + @Override + public String toString() { + return mAddress; } - /** - * Disable the Bluetooth device. - * This turns off the underlying hardware. - * - * @return true if successful, false otherwise. - */ - public boolean disable() { - try { - return mService.disable(true); - } catch (RemoteException e) {Log.e(TAG, "", e);} - return false; + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<BluetoothDevice> CREATOR = + new Parcelable.Creator<BluetoothDevice>() { + public BluetoothDevice createFromParcel(Parcel in) { + return new BluetoothDevice(in.readString()); + } + public BluetoothDevice[] newArray(int size) { + return new BluetoothDevice[size]; + } + }; + + public void writeToParcel(Parcel out, int flags) { + out.writeString(mAddress); } public String getAddress() { - try { - return mService.getAddress(); - } catch (RemoteException e) {Log.e(TAG, "", e);} - return null; + return mAddress; } /** - * Get the friendly Bluetooth name of this device. + * Get the friendly Bluetooth name of this remote device. * * This name is visible to remote Bluetooth devices. Currently it is only * possible to retrieve the Bluetooth name when Bluetooth is enabled. @@ -167,98 +150,12 @@ public class BluetoothDevice { */ public String getName() { try { - return mService.getName(); + return sService.getRemoteName(mAddress); } catch (RemoteException e) {Log.e(TAG, "", e);} return null; } /** - * Set the friendly Bluetooth name of this device. - * - * This name is visible to remote Bluetooth devices. The Bluetooth Service - * is responsible for persisting this name. - * - * @param name the name to set - * @return true, if the name was successfully set. False otherwise. - */ - public boolean setName(String name) { - try { - return mService.setName(name); - } catch (RemoteException e) {Log.e(TAG, "", e);} - return false; - } - - /** - * Get the current scan mode. - * Used to determine if the local device is connectable and/or discoverable - * @return Scan mode, one of SCAN_MODE_* or an error code - */ - public int getScanMode() { - try { - return mService.getScanMode(); - } catch (RemoteException e) {Log.e(TAG, "", e);} - return BluetoothError.ERROR_IPC; - } - - /** - * Set the current scan mode. - * Used to make the local device connectable and/or discoverable - * @param scanMode One of SCAN_MODE_* - */ - public void setScanMode(int scanMode) { - try { - mService.setScanMode(scanMode); - } catch (RemoteException e) {Log.e(TAG, "", e);} - } - - public int getDiscoverableTimeout() { - try { - return mService.getDiscoverableTimeout(); - } catch (RemoteException e) {Log.e(TAG, "", e);} - return -1; - } - public void setDiscoverableTimeout(int timeout) { - try { - mService.setDiscoverableTimeout(timeout); - } catch (RemoteException e) {Log.e(TAG, "", e);} - } - - public boolean startDiscovery() { - try { - return mService.startDiscovery(); - } catch (RemoteException e) {Log.e(TAG, "", e);} - return false; - } - - public void cancelDiscovery() { - try { - mService.cancelDiscovery(); - } catch (RemoteException e) {Log.e(TAG, "", e);} - } - - public boolean isDiscovering() { - try { - return mService.isDiscovering(); - } catch (RemoteException e) {Log.e(TAG, "", e);} - return false; - } - - /** - * Removes the remote device and the pairing information associated - * with it. - * - * @param address the Bluetooth hardware address you want to disconnect. - * @return true if the device was disconnected, false otherwise and on - * error. - */ - public boolean removeBond(String address) { - try { - return mService.removeBond(address); - } catch (RemoteException e) {Log.e(TAG, "", e);} - return false; - } - - /** * Create a bonding with a remote bluetooth device. * * This is an asynchronous call. The result of this bonding attempt can be @@ -268,9 +165,9 @@ public class BluetoothDevice { * @return false If there was an immediate problem creating the bonding, * true otherwise. */ - public boolean createBond(String address) { + public boolean createBond() { try { - return mService.createBond(address); + return sService.createBond(mAddress); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -278,41 +175,25 @@ public class BluetoothDevice { /** * Cancel an in-progress bonding request started with createBond. */ - public boolean cancelBondProcess(String address) { + public boolean cancelBondProcess() { try { - return mService.cancelBondProcess(address); + return sService.cancelBondProcess(mAddress); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } /** - * List remote devices that are bonded (paired) to the local device. - * - * Bonding (pairing) is the process by which the user enters a pin code for - * the device, which generates a shared link key, allowing for - * authentication and encryption of future connections. In Android we - * require bonding before RFCOMM or SCO connections can be made to a remote - * device. - * - * This function lists which remote devices we have a link key for. It does - * not cause any RF transmission, and does not check if the remote device - * still has it's link key with us. If the other side no longer has its - * link key then the RFCOMM or SCO connection attempt will result in an - * error. - * - * This function does not check if the remote device is in range. - * - * Remote devices that have an in-progress bonding attempt are not - * returned. + * Removes the remote device and the pairing information associated + * with it. * - * @return bluetooth hardware addresses of remote devices that are - * bonded. Array size is 0 if no devices are bonded. Null on error. + * @return true if the device was disconnected, false otherwise and on + * error. */ - public String[] listBonds() { + public boolean removeBond() { try { - return mService.listBonds(); + return sService.removeBond(mAddress); } catch (RemoteException e) {Log.e(TAG, "", e);} - return null; + return false; } /** @@ -325,70 +206,103 @@ public class BluetoothDevice { * @param address Bluetooth hardware address of the remote device to check. * @return Result code */ - public int getBondState(String address) { + public int getBondState() { try { - return mService.getBondState(address); + return sService.getBondState(mAddress); } catch (RemoteException e) {Log.e(TAG, "", e);} return BluetoothError.ERROR_IPC; } - public String getRemoteName(String address) { + public int getBluetoothClass() { try { - return mService.getRemoteName(address); - } catch (RemoteException e) {Log.e(TAG, "", e);} - return null; - } - - public int getRemoteClass(String address) { - try { - return mService.getRemoteClass(address); + return sService.getRemoteClass(mAddress); } catch (RemoteException e) {Log.e(TAG, "", e);} return BluetoothError.ERROR_IPC; } - public String[] getRemoteUuids(String address) { + public String[] getUuids() { try { - return mService.getRemoteUuids(address); + return sService.getRemoteUuids(mAddress); } catch (RemoteException e) {Log.e(TAG, "", e);} return null; } - public int getRemoteServiceChannel(String address, String uuid) { + public int getServiceChannel(String uuid) { try { - return mService.getRemoteServiceChannel(address, uuid); + return sService.getRemoteServiceChannel(mAddress, uuid); } catch (RemoteException e) {Log.e(TAG, "", e);} return BluetoothError.ERROR_IPC; } - public boolean setPin(String address, byte[] pin) { + public boolean setPin(byte[] pin) { try { - return mService.setPin(address, pin); + return sService.setPin(mAddress, pin); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } - public boolean setPasskey(String address, int passkey) { + public boolean setPasskey(int passkey) { try { - return mService.setPasskey(address, passkey); + return sService.setPasskey(mAddress, passkey); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } - public boolean setPairingConfirmation(String address, boolean confirm) { + public boolean setPairingConfirmation(boolean confirm) { try { - return mService.setPairingConfirmation(address, confirm); + return sService.setPairingConfirmation(mAddress, confirm); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } - public boolean cancelPairingUserInput(String address) { + public boolean cancelPairingUserInput() { try { - return mService.cancelPairingUserInput(address); + return sService.cancelPairingUserInput(mAddress); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } /** + * Construct a secure RFCOMM socket ready to start an outgoing connection. + * Call #connect on the returned #BluetoothSocket to begin the connection. + * The remote device will be authenticated and communication on this socket + * will be encrypted. + * @param port remote port + * @return an RFCOMM BluetoothSocket + * @throws IOException on error, for example Bluetooth not available, or + * insufficient permissions. + */ + public BluetoothSocket createRfcommSocket(int port) throws IOException { + return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, port); + } + + /** + * Construct an insecure RFCOMM socket ready to start an outgoing + * connection. + * Call #connect on the returned #BluetoothSocket to begin the connection. + * The remote device will not be authenticated and communication on this + * socket will not be encrypted. + * @param port remote port + * @return An RFCOMM BluetoothSocket + * @throws IOException On error, for example Bluetooth not available, or + * insufficient permissions. + */ + public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException { + return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port); + } + + /** + * Construct a SCO socket ready to start an outgoing connection. + * Call #connect on the returned #BluetoothSocket to begin the connection. + * @return a SCO BluetoothSocket + * @throws IOException on error, for example Bluetooth not available, or + * insufficient permissions. + */ + public BluetoothSocket createScoSocket() throws IOException { + return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1); + } + + /** * Check that a pin is valid and convert to byte array. * * Bluetooth pin's are 1 to 16 bytes of UTF8 characters. @@ -413,7 +327,6 @@ public class BluetoothDevice { return pinBytes; } - private static final int ADDRESS_LENGTH = 17; /** Sanity check a bluetooth address, such as "00:43:A8:23:10:F0" */ public static boolean checkBluetoothAddress(String address) { if (address == null || address.length() != ADDRESS_LENGTH) { diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index fe1e09a..0e3d2bb 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -49,7 +49,7 @@ import android.util.Log; * * @hide */ -public class BluetoothHeadset { +public final class BluetoothHeadset { private static final String TAG = "BluetoothHeadset"; private static final boolean DBG = false; @@ -163,16 +163,16 @@ public class BluetoothHeadset { } /** - * Get the Bluetooth address of the current headset. - * @return The Bluetooth address, or null if not in connected or connecting + * Get the BluetoothDevice for the current headset. + * @return current headset, or null if not in connected or connecting * state, or if this proxy object is not connected to the Headset * service. */ - public String getHeadsetAddress() { - if (DBG) log("getHeadsetAddress()"); + public BluetoothDevice getCurrentHeadset() { + if (DBG) log("getCurrentHeadset()"); if (mService != null) { try { - return mService.getHeadsetAddress(); + return mService.getCurrentHeadset(); } catch (RemoteException e) {Log.e(TAG, e.toString());} } else { Log.w(TAG, "Proxy not attached to service"); @@ -185,19 +185,19 @@ public class BluetoothHeadset { * Request to initiate a connection to a headset. * This call does not block. Fails if a headset is already connecting * or connected. - * Initiates auto-connection if address is null. Tries to connect to all + * Initiates auto-connection if device is null. Tries to connect to all * devices with priority greater than PRIORITY_AUTO in descending order. - * @param address The Bluetooth Address to connect to, or null to - * auto-connect to the last connected headset. - * @return False if there was a problem initiating the connection - * procedure, and no further HEADSET_STATE_CHANGED intents - * will be expected. + * @param device device to connect to, or null to auto-connect last connected + * headset + * @return false if there was a problem initiating the connection + * procedure, and no further HEADSET_STATE_CHANGED intents + * will be expected. */ - public boolean connectHeadset(String address) { - if (DBG) log("connectHeadset(" + address + ")"); + public boolean connectHeadset(BluetoothDevice device) { + if (DBG) log("connectHeadset(" + device + ")"); if (mService != null) { try { - if (mService.connectHeadset(address)) { + if (mService.connectHeadset(device)) { return true; } } catch (RemoteException e) {Log.e(TAG, e.toString());} @@ -213,11 +213,11 @@ public class BluetoothHeadset { * connecting). Returns false if not connected, or if this proxy object * if not currently connected to the headset service. */ - public boolean isConnected(String address) { - if (DBG) log("isConnected(" + address + ")"); + public boolean isConnected(BluetoothDevice device) { + if (DBG) log("isConnected(" + device + ")"); if (mService != null) { try { - return mService.isConnected(address); + return mService.isConnected(device); } catch (RemoteException e) {Log.e(TAG, e.toString());} } else { Log.w(TAG, "Proxy not attached to service"); @@ -295,16 +295,16 @@ public class BluetoothHeadset { * auto-connected. * Incoming connections are ignored regardless of priority if there is * already a headset connected. - * @param address Paired headset + * @param device paired headset * @param priority Integer priority, for example PRIORITY_AUTO or * PRIORITY_NONE - * @return True if successful, false if there was some error. + * @return true if successful, false if there was some error */ - public boolean setPriority(String address, int priority) { - if (DBG) log("setPriority(" + address + ", " + priority + ")"); + public boolean setPriority(BluetoothDevice device, int priority) { + if (DBG) log("setPriority(" + device + ", " + priority + ")"); if (mService != null) { try { - return mService.setPriority(address, priority); + return mService.setPriority(device, priority); } catch (RemoteException e) {Log.e(TAG, e.toString());} } else { Log.w(TAG, "Proxy not attached to service"); @@ -315,14 +315,14 @@ public class BluetoothHeadset { /** * Get priority of headset. - * @param address Headset - * @return non-negative priority, or negative error code on error. + * @param device headset + * @return non-negative priority, or negative error code on error */ - public int getPriority(String address) { - if (DBG) log("getPriority(" + address + ")"); + public int getPriority(BluetoothDevice device) { + if (DBG) log("getPriority(" + device + ")"); if (mService != null) { try { - return mService.getPriority(address); + return mService.getPriority(device); } catch (RemoteException e) {Log.e(TAG, e.toString());} } else { Log.w(TAG, "Proxy not attached to service"); diff --git a/core/java/android/bluetooth/BluetoothIntent.java b/core/java/android/bluetooth/BluetoothIntent.java index d6c79b4..2a0de61 100644 --- a/core/java/android/bluetooth/BluetoothIntent.java +++ b/core/java/android/bluetooth/BluetoothIntent.java @@ -31,8 +31,8 @@ import android.annotation.SdkConstant.SdkConstantType; public interface BluetoothIntent { public static final String SCAN_MODE = "android.bluetooth.intent.SCAN_MODE"; - public static final String ADDRESS = - "android.bluetooth.intent.ADDRESS"; + public static final String DEVICE = + "android.bluetooth.intent.DEVICE"; public static final String NAME = "android.bluetooth.intent.NAME"; public static final String ALIAS = diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java index 5782644..645e241 100644 --- a/core/java/android/bluetooth/BluetoothPbap.java +++ b/core/java/android/bluetooth/BluetoothPbap.java @@ -73,11 +73,11 @@ public class BluetoothPbap { /** There was an error trying to obtain the state */ public static final int STATE_ERROR = -1; - /** No Pce currently connected */ + /** No client currently connected */ public static final int STATE_DISCONNECTED = 0; /** Connection attempt in progress */ public static final int STATE_CONNECTING = 1; - /** A Pce is currently connected */ + /** Client is currently connected */ public static final int STATE_CONNECTED = 2; public static final int RESULT_FAILURE = 0; @@ -159,16 +159,16 @@ public class BluetoothPbap { } /** - * Get the Bluetooth address of the current Pce. - * @return The Bluetooth address, or null if not in connected or connecting - * state, or if this proxy object is not connected to the Pbap - * service. + * Get the currently connected remote Bluetooth device (PCE). + * @return The remote Bluetooth device, or null if not in connected or + * connecting state, or if this proxy object is not connected to + * the Pbap service. */ - public String getPceAddress() { - if (DBG) log("getPceAddress()"); + public BluetoothDevice getClient() { + if (DBG) log("getClient()"); if (mService != null) { try { - return mService.getPceAddress(); + return mService.getClient(); } catch (RemoteException e) {Log.e(TAG, e.toString());} } else { Log.w(TAG, "Proxy not attached to service"); @@ -178,15 +178,15 @@ public class BluetoothPbap { } /** - * Returns true if the specified Pcs is connected (does not include - * connecting). Returns false if not connected, or if this proxy object - * if not currently connected to the Pbap service. + * Returns true if the specified Bluetooth device is connected (does not + * include connecting). Returns false if not connected, or if this proxy + * object is not currently connected to the Pbap service. */ - public boolean isConnected(String address) { - if (DBG) log("isConnected(" + address + ")"); + public boolean isConnected(BluetoothDevice device) { + if (DBG) log("isConnected(" + device + ")"); if (mService != null) { try { - return mService.isConnected(address); + return mService.isConnected(device); } catch (RemoteException e) {Log.e(TAG, e.toString());} } else { Log.w(TAG, "Proxy not attached to service"); @@ -196,15 +196,15 @@ public class BluetoothPbap { } /** - * Disconnects the current Pce. Currently this call blocks, it may soon - * be made asynchornous. Returns false if this proxy object is + * Disconnects the current Pbap client (PCE). Currently this call blocks, + * it may soon be made asynchornous. Returns false if this proxy object is * not currently connected to the Pbap service. */ - public boolean disconnectPce() { - if (DBG) log("disconnectPce()"); + public boolean disconnect() { + if (DBG) log("disconnect()"); if (mService != null) { try { - mService.disconnectPce(); + mService.disconnect(); return true; } catch (RemoteException e) {Log.e(TAG, e.toString());} } else { diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java index f3baeab..8be300b 100644 --- a/core/java/android/bluetooth/BluetoothServerSocket.java +++ b/core/java/android/bluetooth/BluetoothServerSocket.java @@ -33,72 +33,7 @@ import java.io.IOException; * @hide */ public final class BluetoothServerSocket implements Closeable { - private final BluetoothSocket mSocket; - - /** - * Construct a listening, secure RFCOMM server socket. - * The remote device connecting to this socket will be authenticated and - * communication on this socket will be encrypted. - * Call #accept to retrieve connections to this socket. - * @return An RFCOMM BluetoothServerSocket - * @throws IOException On error, for example Bluetooth not available, or - * insufficient permissions. - */ - public static BluetoothServerSocket listenUsingRfcommOn(int port) throws IOException { - BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_RFCOMM, true, true, port); - try { - socket.mSocket.bindListenNative(); - } catch (IOException e) { - try { - socket.close(); - } catch (IOException e2) { } - throw e; - } - return socket; - } - - /** - * Construct an unencrypted, unauthenticated, RFCOMM server socket. - * Call #accept to retrieve connections to this socket. - * @return An RFCOMM BluetoothServerSocket - * @throws IOException On error, for example Bluetooth not available, or - * insufficient permissions. - */ - public static BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException { - BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_RFCOMM, false, false, port); - try { - socket.mSocket.bindListenNative(); - } catch (IOException e) { - try { - socket.close(); - } catch (IOException e2) { } - throw e; - } - return socket; - } - - /** - * Construct a SCO server socket. - * Call #accept to retrieve connections to this socket. - * @return A SCO BluetoothServerSocket - * @throws IOException On error, for example Bluetooth not available, or - * insufficient permissions. - */ - public static BluetoothServerSocket listenUsingScoOn() throws IOException { - BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_SCO, false, false, -1); - try { - socket.mSocket.bindListenNative(); - } catch (IOException e) { - try { - socket.close(); - } catch (IOException e2) { } - throw e; - } - return socket; - } + /*package*/ final BluetoothSocket mSocket; /** * Construct a socket for incoming connections. @@ -109,7 +44,7 @@ public final class BluetoothServerSocket implements Closeable { * @throws IOException On error, for example Bluetooth not available, or * insufficient priveleges */ - private BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port) + /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port) throws IOException { mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port); } diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java index de1f326..dda2cef 100644 --- a/core/java/android/bluetooth/BluetoothSocket.java +++ b/core/java/android/bluetooth/BluetoothSocket.java @@ -42,6 +42,7 @@ public final class BluetoothSocket implements Closeable { private final int mType; /* one of TYPE_RFCOMM etc */ private final int mPort; /* RFCOMM channel or L2CAP psm */ + private final BluetoothDevice mDevice; /* remote device */ private final String mAddress; /* remote address */ private final boolean mAuth; private final boolean mEncrypt; @@ -51,68 +52,27 @@ public final class BluetoothSocket implements Closeable { private int mSocketData; /* used by native code only */ /** - * Construct a secure RFCOMM socket ready to start an outgoing connection. - * Call #connect on the returned #BluetoothSocket to begin the connection. - * The remote device will be authenticated and communication on this socket - * will be encrypted. - * @param address remote Bluetooth address that this socket can connect to - * @param port remote port - * @return an RFCOMM BluetoothSocket - * @throws IOException on error, for example Bluetooth not available, or - * insufficient permissions. - */ - public static BluetoothSocket createRfcommSocket(String address, int port) - throws IOException { - return new BluetoothSocket(TYPE_RFCOMM, -1, true, true, address, port); - } - - /** - * Construct an insecure RFCOMM socket ready to start an outgoing - * connection. - * Call #connect on the returned #BluetoothSocket to begin the connection. - * The remote device will not be authenticated and communication on this - * socket will not be encrypted. - * @param address remote Bluetooth address that this socket can connect to - * @param port remote port - * @return An RFCOMM BluetoothSocket - * @throws IOException On error, for example Bluetooth not available, or - * insufficient permissions. - */ - public static BluetoothSocket createInsecureRfcommSocket(String address, int port) - throws IOException { - return new BluetoothSocket(TYPE_RFCOMM, -1, false, false, address, port); - } - - /** - * Construct a SCO socket ready to start an outgoing connection. - * Call #connect on the returned #BluetoothSocket to begin the connection. - * @param address remote Bluetooth address that this socket can connect to - * @return a SCO BluetoothSocket - * @throws IOException on error, for example Bluetooth not available, or - * insufficient permissions. - */ - public static BluetoothSocket createScoSocket(String address, int port) - throws IOException { - return new BluetoothSocket(TYPE_SCO, -1, true, true, address, port); - } - - /** - * Construct a Bluetooth. + * Construct a BluetoothSocket. * @param type type of socket * @param fd fd to use for connected socket, or -1 for a new socket * @param auth require the remote device to be authenticated * @param encrypt require the connection to be encrypted - * @param address remote Bluetooth address that this socket can connect to + * @param device remote device that this socket can connect to * @param port remote port * @throws IOException On error, for example Bluetooth not available, or * insufficient priveleges */ - /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address, - int port) throws IOException { + /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, + BluetoothDevice device, int port) throws IOException { mType = type; mAuth = auth; mEncrypt = encrypt; - mAddress = address; + mDevice = device; + if (device == null) { + mAddress = null; + } else { + mAddress = device.getAddress(); + } mPort = port; if (fd == -1) { initSocketNative(); @@ -123,6 +83,22 @@ public final class BluetoothSocket implements Closeable { mOutputStream = new BluetoothOutputStream(this); } + /** + * Construct a BluetoothSocket from address. + * @param type type of socket + * @param fd fd to use for connected socket, or -1 for a new socket + * @param auth require the remote device to be authenticated + * @param encrypt require the connection to be encrypted + * @param address remote device that this socket can connect to + * @param port remote port + * @throws IOException On error, for example Bluetooth not available, or + * insufficient priveleges + */ + private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address, + int port) throws IOException { + this(type, fd, auth, encrypt, new BluetoothDevice(address), port); + } + @Override protected void finalize() throws Throwable { try { @@ -154,12 +130,12 @@ public final class BluetoothSocket implements Closeable { } /** - * Return the address we are connecting, or connected, to. - * @return Bluetooth address, or null if this socket has not yet attempted + * Return the remote device we are connecting, or connected, to. + * @return remote device, or null if this socket has not yet attempted * or established a connection. */ - public String getAddress() { - return mAddress; + public BluetoothDevice getRemoteDevice() { + return mDevice; } /** diff --git a/core/java/android/bluetooth/HeadsetBase.java b/core/java/android/bluetooth/HeadsetBase.java index f987ffd..29cf41d 100644 --- a/core/java/android/bluetooth/HeadsetBase.java +++ b/core/java/android/bluetooth/HeadsetBase.java @@ -31,7 +31,7 @@ import android.util.Log; * * @hide */ -public class HeadsetBase { +public final class HeadsetBase { private static final String TAG = "Bluetooth HeadsetBase"; private static final boolean DBG = false; @@ -42,8 +42,9 @@ public class HeadsetBase { private static int sAtInputCount = 0; /* TODO: Consider not using a static variable */ - private final BluetoothDevice mBluetooth; - private final String mAddress; + private final BluetoothAdapter mAdapter; + private final BluetoothDevice mRemoteDevice; + private final String mAddress; // for native code private final int mRfcommChannel; private int mNativeData; private Thread mEventThread; @@ -73,12 +74,13 @@ public class HeadsetBase { private native void cleanupNativeDataNative(); - public HeadsetBase(PowerManager pm, BluetoothDevice bluetooth, String address, - int rfcommChannel) { + public HeadsetBase(PowerManager pm, BluetoothAdapter adapter, BluetoothDevice device, + int rfcommChannel) { mDirection = DIRECTION_OUTGOING; mConnectTimestamp = System.currentTimeMillis(); - mBluetooth = bluetooth; - mAddress = address; + mAdapter = adapter; + mRemoteDevice = device; + mAddress = device.getAddress(); mRfcommChannel = rfcommChannel; mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "HeadsetBase"); mWakeLock.setReferenceCounted(false); @@ -88,12 +90,13 @@ public class HeadsetBase { } /* Create from an already exisiting rfcomm connection */ - public HeadsetBase(PowerManager pm, BluetoothDevice bluetooth, String address, int socketFd, - int rfcommChannel, Handler handler) { + public HeadsetBase(PowerManager pm, BluetoothAdapter adapter, BluetoothDevice device, + int socketFd, int rfcommChannel, Handler handler) { mDirection = DIRECTION_INCOMING; mConnectTimestamp = System.currentTimeMillis(); - mBluetooth = bluetooth; - mAddress = address; + mAdapter = adapter; + mRemoteDevice = device; + mAddress = device.getAddress(); mRfcommChannel = rfcommChannel; mEventThreadHandler = handler; mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "HeadsetBase"); @@ -252,12 +255,8 @@ public class HeadsetBase { return mEventThread != null; } - public String getAddress() { - return mAddress; - } - - public String getName() { - return mBluetooth.getRemoteName(mAddress); + public BluetoothDevice getRemoteDevice() { + return mRemoteDevice; } public int getDirection() { diff --git a/core/java/android/bluetooth/IBluetoothDevice.aidl b/core/java/android/bluetooth/IBluetooth.aidl index a78752b..9e05a87 100644 --- a/core/java/android/bluetooth/IBluetoothDevice.aidl +++ b/core/java/android/bluetooth/IBluetooth.aidl @@ -21,7 +21,7 @@ package android.bluetooth; * * {@hide} */ -interface IBluetoothDevice +interface IBluetooth { boolean isEnabled(); int getBluetoothState(); diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl index 55ff27f..e6c6be2 100644 --- a/core/java/android/bluetooth/IBluetoothA2dp.aidl +++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl @@ -16,16 +16,18 @@ package android.bluetooth; +import android.bluetooth.BluetoothDevice; + /** * System private API for Bluetooth A2DP service * * {@hide} */ interface IBluetoothA2dp { - int connectSink(in String address); - int disconnectSink(in String address); - List<String> listConnectedSinks(); - int getSinkState(in String address); - int setSinkPriority(in String address, int priority); - int getSinkPriority(in String address); + int connectSink(in BluetoothDevice device); + int disconnectSink(in BluetoothDevice device); + BluetoothDevice[] getConnectedSinks(); // change to Set<> once AIDL supports + int getSinkState(in BluetoothDevice device); + int setSinkPriority(in BluetoothDevice device, int priority); + int getSinkPriority(in BluetoothDevice device); } diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl index 5f42fd6..6cccd50 100644 --- a/core/java/android/bluetooth/IBluetoothHeadset.aidl +++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl @@ -16,6 +16,8 @@ package android.bluetooth; +import android.bluetooth.BluetoothDevice; + /** * System private API for Bluetooth Headset service * @@ -23,13 +25,13 @@ package android.bluetooth; */ interface IBluetoothHeadset { int getState(); - String getHeadsetAddress(); - boolean connectHeadset(in String address); + BluetoothDevice getCurrentHeadset(); + boolean connectHeadset(in BluetoothDevice device); void disconnectHeadset(); - boolean isConnected(in String address); + boolean isConnected(in BluetoothDevice device); boolean startVoiceRecognition(); boolean stopVoiceRecognition(); - boolean setPriority(in String address, int priority); - int getPriority(in String address); + boolean setPriority(in BluetoothDevice device, int priority); + int getPriority(in BluetoothDevice device); int getBatteryUsageHint(); } diff --git a/core/java/android/bluetooth/IBluetoothPbap.aidl b/core/java/android/bluetooth/IBluetoothPbap.aidl index 06cdb7b..7cc77d1 100644 --- a/core/java/android/bluetooth/IBluetoothPbap.aidl +++ b/core/java/android/bluetooth/IBluetoothPbap.aidl @@ -16,6 +16,8 @@ package android.bluetooth; +import android.bluetooth.BluetoothDevice; + /** * System private API for Bluetooth pbap service * @@ -23,8 +25,8 @@ package android.bluetooth; */ interface IBluetoothPbap { int getState(); - String getPceAddress(); - boolean connectPce(in String address); - void disconnectPce(); - boolean isConnected(in String address); + BluetoothDevice getClient(); + boolean connect(in BluetoothDevice device); + void disconnect(); + boolean isConnected(in BluetoothDevice device); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index dbe6fb0..8ab67c5 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1144,10 +1144,10 @@ public abstract class Context { public static final String SENSOR_SERVICE = "sensor"; /** * Use with {@link #getSystemService} to retrieve a {@link - * android.bluetooth.BluetoothDevice} for interacting with Bluetooth. + * android.bluetooth.BluetoothAdapter} for using Bluetooth. * * @see #getSystemService - * @see android.bluetooth.BluetoothDevice + * @see android.bluetooth.BluetoothAdapter * @hide */ public static final String BLUETOOTH_SERVICE = "bluetooth"; diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java index 96ce9d6..d9fcb53 100644 --- a/core/java/android/server/BluetoothA2dpService.java +++ b/core/java/android/server/BluetoothA2dpService.java @@ -23,6 +23,7 @@ package android.server; import android.bluetooth.BluetoothA2dp; +import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothError; import android.bluetooth.BluetoothIntent; @@ -40,9 +41,9 @@ import android.util.Log; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; public class BluetoothA2dpService extends IBluetoothA2dp.Stub { @@ -67,26 +68,27 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { private static int mSinkCount; - private final Context mContext; private final IntentFilter mIntentFilter; - private HashMap<String, Integer> mAudioDevices; + private HashMap<BluetoothDevice, Integer> mAudioDevices; private final AudioManager mAudioManager; - private final BluetoothDeviceService mBluetoothService; + private final BluetoothService mBluetoothService; + private final BluetoothAdapter mAdapter; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - String address = intent.getStringExtra(BluetoothIntent.ADDRESS); + BluetoothDevice device = + intent.getParcelableExtra(BluetoothIntent.DEVICE); if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) { int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE, BluetoothError.ERROR); switch (state) { - case BluetoothDevice.BLUETOOTH_STATE_ON: + case BluetoothAdapter.BLUETOOTH_STATE_ON: onBluetoothEnable(); break; - case BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF: + case BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF: onBluetoothDisable(); break; } @@ -95,28 +97,28 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { BluetoothError.ERROR); switch(bondState) { case BluetoothDevice.BOND_BONDED: - setSinkPriority(address, BluetoothA2dp.PRIORITY_AUTO); + setSinkPriority(device, BluetoothA2dp.PRIORITY_AUTO); break; case BluetoothDevice.BOND_BONDING: case BluetoothDevice.BOND_NOT_BONDED: - setSinkPriority(address, BluetoothA2dp.PRIORITY_OFF); + setSinkPriority(device, BluetoothA2dp.PRIORITY_OFF); break; } } else if (action.equals(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION)) { - if (getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF && - isSinkDevice(address)) { + if (getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF && + isSinkDevice(device)) { // This device is a preferred sink. Make an A2DP connection // after a delay. We delay to avoid connection collisions, // and to give other profiles such as HFP a chance to // connect first. - Message msg = Message.obtain(mHandler, MESSAGE_CONNECT_TO, address); + Message msg = Message.obtain(mHandler, MESSAGE_CONNECT_TO, device); mHandler.sendMessageDelayed(msg, 6000); } } } }; - public BluetoothA2dpService(Context context, BluetoothDeviceService bluetoothService) { + public BluetoothA2dpService(Context context, BluetoothService bluetoothService) { mContext = context; mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); @@ -130,12 +132,14 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { throw new RuntimeException("Could not init BluetoothA2dpService"); } + mAdapter = (BluetoothAdapter) context.getSystemService(Context.BLUETOOTH_SERVICE); + mIntentFilter = new IntentFilter(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION); mIntentFilter.addAction(BluetoothIntent.BOND_STATE_CHANGED_ACTION); mIntentFilter.addAction(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION); mContext.registerReceiver(mReceiver, mIntentFilter); - mAudioDevices = new HashMap<String, Integer>(); + mAudioDevices = new HashMap<BluetoothDevice, Integer>(); if (mBluetoothService.isEnabled()) onBluetoothEnable(); @@ -155,18 +159,18 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_CONNECT_TO: - String address = (String)msg.obj; + BluetoothDevice device = (BluetoothDevice) msg.obj; // check bluetooth is still on, device is still preferred, and // nothing is currently connected if (mBluetoothService.isEnabled() && - getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF && + getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF && lookupSinksMatchingStates(new int[] { BluetoothA2dp.STATE_CONNECTING, BluetoothA2dp.STATE_CONNECTED, BluetoothA2dp.STATE_PLAYING, BluetoothA2dp.STATE_DISCONNECTING}).size() == 0) { - log("Auto-connecting A2DP to sink " + address); - connectSink(address); + log("Auto-connecting A2DP to sink " + device); + connectSink(device); } break; } @@ -185,8 +189,8 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { return -1; } - private boolean isSinkDevice(String address) { - String uuids[] = mBluetoothService.getRemoteUuids(address); + private boolean isSinkDevice(BluetoothDevice device) { + String uuids[] = mBluetoothService.getRemoteUuids(device.getAddress()); UUID uuid; if (uuids != null) { for (String deviceUuid: uuids) { @@ -199,11 +203,11 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { return false; } - private synchronized boolean addAudioSink (String address) { - String path = mBluetoothService.getObjectPathFromAddress(address); + private synchronized boolean addAudioSink (BluetoothDevice device) { + String path = mBluetoothService.getObjectPathFromAddress(device.getAddress()); String propValues[] = (String []) getSinkPropertiesNative(path); if (propValues == null) { - Log.e(TAG, "Error while getting AudioSink properties for device: " + address); + Log.e(TAG, "Error while getting AudioSink properties for device: " + device); return false; } Integer state = null; @@ -214,8 +218,8 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { break; } } - mAudioDevices.put(address, state); - handleSinkStateChange(address, BluetoothA2dp.STATE_DISCONNECTED, state); + mAudioDevices.put(device, state); + handleSinkStateChange(device, BluetoothA2dp.STATE_DISCONNECTED, state); return true; } @@ -226,6 +230,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { String [] paths = devices.split(","); for (String path: paths) { String address = mBluetoothService.getAddressFromObjectPath(path); + BluetoothDevice device = mAdapter.getRemoteDevice(address); String []uuids = mBluetoothService.getRemoteUuids(address); if (uuids != null) for (String uuid: uuids) { @@ -233,7 +238,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { if (BluetoothUuid.isAudioSink(remoteUuid) || BluetoothUuid.isAudioSource(remoteUuid) || BluetoothUuid.isAdvAudioDist(remoteUuid)) { - addAudioSink(address); + addAudioSink(device); break; } } @@ -244,36 +249,34 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { private synchronized void onBluetoothDisable() { if (!mAudioDevices.isEmpty()) { - String [] addresses = new String[mAudioDevices.size()]; - addresses = mAudioDevices.keySet().toArray(addresses); - for (String address : addresses) { - int state = getSinkState(address); + BluetoothDevice[] devices = new BluetoothDevice[mAudioDevices.size()]; + devices = mAudioDevices.keySet().toArray(devices); + for (BluetoothDevice device : devices) { + int state = getSinkState(device); switch (state) { case BluetoothA2dp.STATE_CONNECTING: case BluetoothA2dp.STATE_CONNECTED: case BluetoothA2dp.STATE_PLAYING: - disconnectSinkNative(mBluetoothService.getObjectPathFromAddress(address)); - handleSinkStateChange(address,state, BluetoothA2dp.STATE_DISCONNECTED); + disconnectSinkNative(mBluetoothService.getObjectPathFromAddress( + device.getAddress())); + handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTED); break; case BluetoothA2dp.STATE_DISCONNECTING: - handleSinkStateChange(address, BluetoothA2dp.STATE_DISCONNECTING, - BluetoothA2dp.STATE_DISCONNECTED); + handleSinkStateChange(device, BluetoothA2dp.STATE_DISCONNECTING, + BluetoothA2dp.STATE_DISCONNECTED); break; } } mAudioDevices.clear(); } - mAudioManager.setParameters(BLUETOOTH_ENABLED+"=false"); + mAudioManager.setParameters(BLUETOOTH_ENABLED + "=false"); } - public synchronized int connectSink(String address) { + public synchronized int connectSink(BluetoothDevice device) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); - if (DBG) log("connectSink(" + address + ")"); - if (!BluetoothDevice.checkBluetoothAddress(address)) { - return BluetoothError.ERROR; - } + if (DBG) log("connectSink(" + device + ")"); // ignore if there are any active sinks if (lookupSinksMatchingStates(new int[] { @@ -284,10 +287,10 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { return BluetoothError.ERROR; } - if (mAudioDevices.get(address) == null && !addAudioSink(address)) + if (mAudioDevices.get(device) == null && !addAudioSink(device)) return BluetoothError.ERROR; - int state = mAudioDevices.get(address); + int state = mAudioDevices.get(device); switch (state) { case BluetoothA2dp.STATE_CONNECTED: @@ -298,7 +301,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { return BluetoothError.SUCCESS; } - String path = mBluetoothService.getObjectPathFromAddress(address); + String path = mBluetoothService.getObjectPathFromAddress(device.getAddress()); if (path == null) return BluetoothError.ERROR; @@ -309,19 +312,17 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { return BluetoothError.SUCCESS; } - public synchronized int disconnectSink(String address) { + public synchronized int disconnectSink(BluetoothDevice device) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); - if (DBG) log("disconnectSink(" + address + ")"); - if (!BluetoothDevice.checkBluetoothAddress(address)) { - return BluetoothError.ERROR; - } - String path = mBluetoothService.getObjectPathFromAddress(address); + if (DBG) log("disconnectSink(" + device + ")"); + + String path = mBluetoothService.getObjectPathFromAddress(device.getAddress()); if (path == null) { return BluetoothError.ERROR; } - switch (getSinkState(address)) { + switch (getSinkState(device)) { case BluetoothA2dp.STATE_DISCONNECTED: return BluetoothError.ERROR; case BluetoothA2dp.STATE_DISCONNECTING: @@ -336,41 +337,36 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { } } - public synchronized List<String> listConnectedSinks() { + public synchronized BluetoothDevice[] getConnectedSinks() { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - return lookupSinksMatchingStates(new int[] {BluetoothA2dp.STATE_CONNECTED, - BluetoothA2dp.STATE_PLAYING}); + Set<BluetoothDevice> sinks = lookupSinksMatchingStates( + new int[] {BluetoothA2dp.STATE_CONNECTED, BluetoothA2dp.STATE_PLAYING}); + return sinks.toArray(new BluetoothDevice[sinks.size()]); } - public synchronized int getSinkState(String address) { + public synchronized int getSinkState(BluetoothDevice device) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - if (!BluetoothDevice.checkBluetoothAddress(address)) { - return BluetoothError.ERROR; - } - Integer state = mAudioDevices.get(address); + Integer state = mAudioDevices.get(device); if (state == null) return BluetoothA2dp.STATE_DISCONNECTED; return state; } - public synchronized int getSinkPriority(String address) { + public synchronized int getSinkPriority(BluetoothDevice device) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - if (!BluetoothDevice.checkBluetoothAddress(address)) { - return BluetoothError.ERROR; - } return Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.getBluetoothA2dpSinkPriorityKey(address), + Settings.Secure.getBluetoothA2dpSinkPriorityKey(device.getAddress()), BluetoothA2dp.PRIORITY_OFF); } - public synchronized int setSinkPriority(String address, int priority) { + public synchronized int setSinkPriority(BluetoothDevice device, int priority) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); - if (!BluetoothDevice.checkBluetoothAddress(address)) { + if (!BluetoothDevice.checkBluetoothAddress(device.getAddress())) { return BluetoothError.ERROR; } return Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.getBluetoothA2dpSinkPriorityKey(address), priority) ? + Settings.Secure.getBluetoothA2dpSinkPriorityKey(device.getAddress()), priority) ? BluetoothError.SUCCESS : BluetoothError.ERROR; } @@ -386,20 +382,22 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { return; } + BluetoothDevice device = mAdapter.getRemoteDevice(address); + if (name.equals(PROPERTY_STATE)) { int state = convertBluezSinkStringtoState(propValues[1]); - if (mAudioDevices.get(address) == null) { + if (mAudioDevices.get(device) == null) { // This is for an incoming connection for a device not known to us. // We have authorized it and bluez state has changed. - addAudioSink(address); + addAudioSink(device); } else { - int prevState = mAudioDevices.get(address); - handleSinkStateChange(address, prevState, state); + int prevState = mAudioDevices.get(device); + handleSinkStateChange(device, prevState, state); } } } - private void handleSinkStateChange(String address, int prevState, int state) { + private void handleSinkStateChange(BluetoothDevice device, int prevState, int state) { if (state != prevState) { if (state == BluetoothA2dp.STATE_DISCONNECTED || state == BluetoothA2dp.STATE_DISCONNECTING) { @@ -413,28 +411,28 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { } else if (state == BluetoothA2dp.STATE_CONNECTED) { mSinkCount ++; } - mAudioDevices.put(address, state); + mAudioDevices.put(device, state); Intent intent = new Intent(BluetoothA2dp.SINK_STATE_CHANGED_ACTION); - intent.putExtra(BluetoothIntent.ADDRESS, address); + intent.putExtra(BluetoothIntent.DEVICE, device); intent.putExtra(BluetoothA2dp.SINK_PREVIOUS_STATE, prevState); intent.putExtra(BluetoothA2dp.SINK_STATE, state); mContext.sendBroadcast(intent, BLUETOOTH_PERM); - if (DBG) log("A2DP state : address: " + address + " State:" + prevState + "->" + state); + if (DBG) log("A2DP state : device: " + device + " State:" + prevState + "->" + state); } } - private synchronized List<String> lookupSinksMatchingStates(int[] states) { - List<String> sinks = new ArrayList<String>(); + private synchronized Set<BluetoothDevice> lookupSinksMatchingStates(int[] states) { + Set<BluetoothDevice> sinks = new HashSet<BluetoothDevice>(); if (mAudioDevices.isEmpty()) { return sinks; } - for (String path: mAudioDevices.keySet()) { - int sinkState = getSinkState(path); + for (BluetoothDevice device: mAudioDevices.keySet()) { + int sinkState = getSinkState(device); for (int state : states) { if (state == sinkState) { - sinks.add(path); + sinks.add(device); break; } } @@ -446,9 +444,9 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mAudioDevices.isEmpty()) return; pw.println("Cached audio devices:"); - for (String address : mAudioDevices.keySet()) { - int state = mAudioDevices.get(address); - pw.println(address + " " + BluetoothA2dp.stateToString(state)); + for (BluetoothDevice device : mAudioDevices.keySet()) { + int state = mAudioDevices.get(device); + pw.println(device + " " + BluetoothA2dp.stateToString(state)); } } diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java index 1704733..6610d0e 100644 --- a/core/java/android/server/BluetoothEventLoop.java +++ b/core/java/android/server/BluetoothEventLoop.java @@ -18,6 +18,7 @@ package android.server; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothClass; +import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothError; import android.bluetooth.BluetoothIntent; @@ -46,8 +47,10 @@ class BluetoothEventLoop { private Thread mThread; private boolean mStarted; private boolean mInterrupted; + private final HashMap<String, Integer> mPasskeyAgentRequestData; - private final BluetoothDeviceService mBluetoothService; + private final BluetoothService mBluetoothService; + private final BluetoothAdapter mAdapter; private final Context mContext; private static final int EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 1; @@ -84,10 +87,12 @@ class BluetoothEventLoop { static { classInitNative(); } private static native void classInitNative(); - /* pacakge */ BluetoothEventLoop(Context context, BluetoothDeviceService bluetoothService) { + /* pacakge */ BluetoothEventLoop(Context context, BluetoothAdapter adapter, + BluetoothService bluetoothService) { mBluetoothService = bluetoothService; mContext = context; mPasskeyAgentRequestData = new HashMap(); + mAdapter = adapter; initializeNativeDataNative(); } @@ -137,7 +142,7 @@ class BluetoothEventLoop { } if (classValue != null) { Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION); - intent.putExtra(BluetoothIntent.ADDRESS, address); + intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address)); intent.putExtra(BluetoothIntent.CLASS, Integer.valueOf(classValue)); intent.putExtra(BluetoothIntent.RSSI, rssiValue); intent.putExtra(BluetoothIntent.NAME, name); @@ -158,7 +163,7 @@ class BluetoothEventLoop { private void onDeviceDisappeared(String address) { Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISAPPEARED_ACTION); - intent.putExtra(BluetoothIntent.ADDRESS, address); + intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address)); mContext.sendBroadcast(intent, BLUETOOTH_PERM); } @@ -251,7 +256,7 @@ class BluetoothEventLoop { if (pairable == null || discoverable == null) return; - int mode = BluetoothDeviceService.bluezStringToScanMode( + int mode = BluetoothService.bluezStringToScanMode( pairable.equals("true"), discoverable.equals("true")); if (mode >= 0) { @@ -299,15 +304,16 @@ class BluetoothEventLoop { Log.e(TAG, "onDevicePropertyChanged: Address of the remote device in null"); return; } + BluetoothDevice device = mAdapter.getRemoteDevice(address); if (name.equals("Name")) { Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION); - intent.putExtra(BluetoothIntent.ADDRESS, address); + intent.putExtra(BluetoothIntent.DEVICE, device); intent.putExtra(BluetoothIntent.NAME, propValues[1]); mContext.sendBroadcast(intent, BLUETOOTH_PERM); mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]); } else if (name.equals("Class")) { Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION); - intent.putExtra(BluetoothIntent.ADDRESS, address); + intent.putExtra(BluetoothIntent.DEVICE, device); intent.putExtra(BluetoothIntent.CLASS, propValues[1]); mContext.sendBroadcast(intent, BLUETOOTH_PERM); mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]); @@ -318,7 +324,7 @@ class BluetoothEventLoop { } else { intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISCONNECTED_ACTION); } - intent.putExtra(BluetoothIntent.ADDRESS, address); + intent.putExtra(BluetoothIntent.DEVICE, device); mContext.sendBroadcast(intent, BLUETOOTH_PERM); mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]); } else if (name.equals("UUIDs")) { @@ -351,7 +357,7 @@ class BluetoothEventLoop { address = address.toUpperCase(); mPasskeyAgentRequestData.put(address, new Integer(nativeData)); - if (mBluetoothService.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF) { + if (mBluetoothService.getBluetoothState() == BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF) { // shutdown path mBluetoothService.cancelPairingUserInput(address); return null; @@ -364,7 +370,7 @@ class BluetoothEventLoop { if (address == null) return; Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION); - intent.putExtra(BluetoothIntent.ADDRESS, address); + intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address)); intent.putExtra(BluetoothIntent.PASSKEY, passkey); intent.putExtra(BluetoothIntent.PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_CONFIRMATION); @@ -377,7 +383,7 @@ class BluetoothEventLoop { if (address == null) return; Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION); - intent.putExtra(BluetoothIntent.ADDRESS, address); + intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address)); intent.putExtra(BluetoothIntent.PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PASSKEY); mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); return; @@ -409,7 +415,7 @@ class BluetoothEventLoop { } } Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION); - intent.putExtra(BluetoothIntent.ADDRESS, address); + intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address)); intent.putExtra(BluetoothIntent.PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PIN); mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); return; @@ -428,7 +434,8 @@ class BluetoothEventLoop { (BluetoothUuid.isAudioSink(uuid) || BluetoothUuid.isAvrcpController(uuid) || BluetoothUuid.isAdvAudioDist(uuid))) { BluetoothA2dp a2dp = new BluetoothA2dp(mContext); - authorized = a2dp.getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF; + BluetoothDevice device = mAdapter.getRemoteDevice(address); + authorized = a2dp.getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF; if (authorized) { Log.i(TAG, "Allowing incoming A2DP / AVRCP connection from " + address); } else { diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothService.java index d2b4447..acee3af 100644 --- a/core/java/android/server/BluetoothDeviceService.java +++ b/core/java/android/server/BluetoothService.java @@ -16,7 +16,7 @@ /** * TODO: Move this to - * java/services/com/android/server/BluetoothDeviceService.java + * java/services/com/android/server/BluetoothService.java * and make the contructor package private again. * * @hide @@ -25,11 +25,12 @@ package android.server; import android.bluetooth.BluetoothClass; +import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothError; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothIntent; -import android.bluetooth.IBluetoothDevice; +import android.bluetooth.IBluetooth; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -55,8 +56,8 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; -public class BluetoothDeviceService extends IBluetoothDevice.Stub { - private static final String TAG = "BluetoothDeviceService"; +public class BluetoothService extends IBluetooth.Stub { + private static final String TAG = "BluetoothService"; private static final boolean DBG = true; private int mNativeData; @@ -65,11 +66,11 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { private boolean mIsAirplaneSensitive; private int mBluetoothState; private boolean mRestart = false; // need to call enable() after disable() + private boolean mIsDiscovering; + private BluetoothAdapter mAdapter; // constant after init() private final BondState mBondState = new BondState(); // local cache of bondings - private boolean mIsDiscovering; private final IBatteryStats mBatteryStats; - private final Context mContext; private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; @@ -78,14 +79,14 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { private static final int MESSAGE_REGISTER_SDP_RECORDS = 1; private static final int MESSAGE_FINISH_DISABLE = 2; - private Map<String, String> mProperties; - private HashMap <String, Map<String, String>> mRemoteDeviceProperties; + private final Map<String, String> mAdapterProperties; + private final HashMap <String, Map<String, String>> mDeviceProperties; static { classInitNative(); } - public BluetoothDeviceService(Context context) { + public BluetoothService(Context context) { mContext = context; // Need to do this in place of: @@ -93,11 +94,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { // Since we can not import BatteryStatsService from here. This class really needs to be // moved to java/services/com/android/server/ mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); - } - /** Must be called after construction, and before any other method. - */ - public synchronized void init() { initializeNativeDataNative(); if (isEnabledNative() == 1) { @@ -105,12 +102,16 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { disableNative(); } - setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_OFF); + mBluetoothState = BluetoothAdapter.BLUETOOTH_STATE_OFF; mIsDiscovering = false; - mEventLoop = new BluetoothEventLoop(mContext, this); + mAdapterProperties = new HashMap<String, String>(); + mDeviceProperties = new HashMap<String, Map<String,String>>(); registerForAirplaneMode(); - mProperties = new HashMap<String, String>(); - mRemoteDeviceProperties = new HashMap<String, Map<String,String>>(); + } + + public synchronized void initAfterRegistration() { + mAdapter = (BluetoothAdapter) mContext.getSystemService(Context.BLUETOOTH_SERVICE); + mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this); } @Override @@ -127,7 +128,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { public boolean isEnabled() { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - return mBluetoothState == BluetoothDevice.BLUETOOTH_STATE_ON; + return mBluetoothState == BluetoothAdapter.BLUETOOTH_STATE_ON; } public int getBluetoothState() { @@ -152,9 +153,9 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); switch (mBluetoothState) { - case BluetoothDevice.BLUETOOTH_STATE_OFF: + case BluetoothAdapter.BLUETOOTH_STATE_OFF: return true; - case BluetoothDevice.BLUETOOTH_STATE_ON: + case BluetoothAdapter.BLUETOOTH_STATE_ON: break; default: return false; @@ -162,11 +163,11 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { if (mEnableThread != null && mEnableThread.isAlive()) { return false; } - setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF); + setBluetoothState(BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF); // Allow 3 seconds for profiles to gracefully disconnect // TODO: Introduce a callback mechanism so that each profile can notify - // BluetoothDeviceService when it is done shutting down + // BluetoothService when it is done shutting down mHandler.sendMessageDelayed( mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000); return true; @@ -174,7 +175,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { private synchronized void finishDisable(boolean saveSetting) { - if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF) { + if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF) { return; } mEventLoop.stop(); @@ -189,17 +190,17 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { // update mode Intent intent = new Intent(BluetoothIntent.SCAN_MODE_CHANGED_ACTION); - intent.putExtra(BluetoothIntent.SCAN_MODE, BluetoothDevice.SCAN_MODE_NONE); + intent.putExtra(BluetoothIntent.SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE); mContext.sendBroadcast(intent, BLUETOOTH_PERM); mIsDiscovering = false; - mProperties.clear(); + mAdapterProperties.clear(); if (saveSetting) { persistBluetoothOnSetting(false); } - setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_OFF); + setBluetoothState(BluetoothAdapter.BLUETOOTH_STATE_OFF); // Log bluetooth off to battery stats. long ident = Binder.clearCallingIdentity(); @@ -236,13 +237,13 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { if (mIsAirplaneSensitive && isAirplaneModeOn()) { return false; } - if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_OFF) { + if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_OFF) { return false; } if (mEnableThread != null && mEnableThread.isAlive()) { return false; } - setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_TURNING_ON); + setBluetoothState(BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON); mEnableThread = new EnableThread(saveSetting); mEnableThread.start(); return true; @@ -250,7 +251,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { /** Forcibly restart Bluetooth if it is on */ /* package */ synchronized void restart() { - if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_ON) { + if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_ON) { return; } mRestart = true; @@ -356,8 +357,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { mEnableThread = null; setBluetoothState(res ? - BluetoothDevice.BLUETOOTH_STATE_ON : - BluetoothDevice.BLUETOOTH_STATE_OFF); + BluetoothAdapter.BLUETOOTH_STATE_ON : + BluetoothAdapter.BLUETOOTH_STATE_OFF); if (res) { // Update mode @@ -410,7 +411,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { )); public synchronized void loadBondState() { - if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_TURNING_ON) { + if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON) { return; } String []bonds = null; @@ -442,7 +443,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" + reason + ")"); Intent intent = new Intent(BluetoothIntent.BOND_STATE_CHANGED_ACTION); - intent.putExtra(BluetoothIntent.ADDRESS, address); + intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address)); intent.putExtra(BluetoothIntent.BOND_STATE, state); intent.putExtra(BluetoothIntent.BOND_PREVIOUS_STATE, oldState); if (state == BluetoothDevice.BOND_NOT_BONDED) { @@ -539,7 +540,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { /*package*/synchronized void getAllProperties() { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - mProperties.clear(); + mAdapterProperties.clear(); String properties[] = (String [])getAdapterPropertiesNative(); // The String Array consists of key-value pairs. @@ -568,17 +569,17 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { } else { newValue = properties[++i]; } - mProperties.put(name, newValue); + mAdapterProperties.put(name, newValue); } // Add adapter object path property. String adapterPath = getAdapterPathNative(); if (adapterPath != null) - mProperties.put("ObjectPath", adapterPath + "/dev_"); + mAdapterProperties.put("ObjectPath", adapterPath + "/dev_"); } /* package */ synchronized void setProperty(String name, String value) { - mProperties.put(name, value); + mAdapterProperties.put(name, value); } public synchronized boolean setName(String name) { @@ -646,10 +647,10 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { } /*package*/ synchronized String getProperty (String name) { - if (!mProperties.isEmpty()) - return mProperties.get(name); + if (!mAdapterProperties.isEmpty()) + return mAdapterProperties.get(name); getAllProperties(); - return mProperties.get(name); + return mAdapterProperties.get(name); } public synchronized String getAddress() { @@ -678,7 +679,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { if (!BluetoothDevice.checkBluetoothAddress(address)) { return null; } - Map <String, String> properties = mRemoteDeviceProperties.get(address); + Map <String, String> properties = mDeviceProperties.get(address); if (properties != null) return properties.get("Name"); return null; } @@ -805,7 +806,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { } /*package*/ boolean isRemoteDeviceInCache(String address) { - return (mRemoteDeviceProperties.get(address) != null); + return (mDeviceProperties.get(address) != null); } /*package*/ String[] getRemoteDeviceProperties(String address) { @@ -814,7 +815,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { } /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) { - Map<String, String> properties = mRemoteDeviceProperties.get(address); + Map<String, String> properties = mDeviceProperties.get(address); if (properties != null) { return properties.get(property); } else { @@ -835,7 +836,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { /* * We get a DeviceFound signal every time RSSI changes or name changes. * Don't create a new Map object every time */ - Map<String, String> propertyValues = mRemoteDeviceProperties.get(address); + Map<String, String> propertyValues = mDeviceProperties.get(address); if (propertyValues != null) { propertyValues.clear(); } else { @@ -864,19 +865,19 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { } propertyValues.put(name, newValue); } - mRemoteDeviceProperties.put(address, propertyValues); + mDeviceProperties.put(address, propertyValues); } /* package */ void removeRemoteDeviceProperties(String address) { - mRemoteDeviceProperties.remove(address); + mDeviceProperties.remove(address); } /* package */ synchronized void setRemoteDeviceProperty(String address, String name, String value) { - Map <String, String> propVal = mRemoteDeviceProperties.get(address); + Map <String, String> propVal = mDeviceProperties.get(address); if (propVal != null) { propVal.put(name, value); - mRemoteDeviceProperties.put(address, propVal); + mDeviceProperties.put(address, propVal); } else { Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address); } @@ -1059,16 +1060,16 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive + "\n"); switch(mBluetoothState) { - case BluetoothDevice.BLUETOOTH_STATE_OFF: + case BluetoothAdapter.BLUETOOTH_STATE_OFF: pw.println("\nBluetooth OFF\n"); return; - case BluetoothDevice.BLUETOOTH_STATE_TURNING_ON: + case BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON: pw.println("\nBluetooth TURNING ON\n"); return; - case BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF: + case BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF: pw.println("\nBluetooth TURNING OFF\n"); return; - case BluetoothDevice.BLUETOOTH_STATE_ON: + case BluetoothAdapter.BLUETOOTH_STATE_ON: pw.println("\nBluetooth ON\n"); } @@ -1079,7 +1080,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { BluetoothHeadset headset = new BluetoothHeadset(mContext, null); pw.println("\n--Known devices--"); - for (String address : mRemoteDeviceProperties.keySet()) { + for (String address : mDeviceProperties.keySet()) { pw.printf("%s %10s (%d) %s\n", address, toBondStateString(mBondState.getBondState(address)), mBondState.getAttempt(address), @@ -1113,7 +1114,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { pw.println("getState() = STATE_ERROR"); break; } - pw.println("getHeadsetAddress() = " + headset.getHeadsetAddress()); + pw.println("getCurrentHeadset() = " + headset.getCurrentHeadset()); pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint()); headset.close(); @@ -1121,20 +1122,20 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) { if (pairable && discoverable) - return BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE; + return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; else if (pairable && !discoverable) - return BluetoothDevice.SCAN_MODE_CONNECTABLE; + return BluetoothAdapter.SCAN_MODE_CONNECTABLE; else - return BluetoothDevice.SCAN_MODE_NONE; + return BluetoothAdapter.SCAN_MODE_NONE; } /* package */ static String scanModeToBluezString(int mode) { switch (mode) { - case BluetoothDevice.SCAN_MODE_NONE: + case BluetoothAdapter.SCAN_MODE_NONE: return "off"; - case BluetoothDevice.SCAN_MODE_CONNECTABLE: + case BluetoothAdapter.SCAN_MODE_CONNECTABLE: return "connectable"; - case BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE: + case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: return "discoverable"; } return null; diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java index 77d6e20..4c9451e 100644 --- a/core/java/com/android/internal/app/ShutdownThread.java +++ b/core/java/com/android/internal/app/ShutdownThread.java @@ -21,8 +21,8 @@ import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.ProgressDialog; import android.app.AlertDialog; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.IBluetoothDevice; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.IBluetooth; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; @@ -179,13 +179,13 @@ public final class ShutdownThread extends Thread { final ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); - final IBluetoothDevice bluetooth = - IBluetoothDevice.Stub.asInterface(ServiceManager.checkService( + final IBluetooth bluetooth = + IBluetooth.Stub.asInterface(ServiceManager.checkService( Context.BLUETOOTH_SERVICE)); try { bluetoothOff = bluetooth == null || - bluetooth.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_OFF; + bluetooth.getBluetoothState() == BluetoothAdapter.BLUETOOTH_STATE_OFF; if (!bluetoothOff) { Log.w(TAG, "Disabling Bluetooth..."); bluetooth.disable(false); // disable but don't persist new state @@ -213,7 +213,7 @@ public final class ShutdownThread extends Thread { if (!bluetoothOff) { try { bluetoothOff = - bluetooth.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_OFF; + bluetooth.getBluetoothState() == BluetoothAdapter.BLUETOOTH_STATE_OFF; } catch (RemoteException ex) { Log.e(TAG, "RemoteException during bluetooth shutdown", ex); bluetoothOff = true; diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 36d2684..015268b 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -114,7 +114,7 @@ LOCAL_SRC_FILES:= \ android_bluetooth_BluetoothAudioGateway.cpp \ android_bluetooth_BluetoothSocket.cpp \ android_bluetooth_ScoSocket.cpp \ - android_server_BluetoothDeviceService.cpp \ + android_server_BluetoothService.cpp \ android_server_BluetoothEventLoop.cpp \ android_server_BluetoothA2dpService.cpp \ android_message_digest_sha1.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 63dc9e8..2e73372 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -146,7 +146,7 @@ extern int register_android_bluetooth_HeadsetBase(JNIEnv* env); extern int register_android_bluetooth_BluetoothAudioGateway(JNIEnv* env); extern int register_android_bluetooth_BluetoothSocket(JNIEnv *env); extern int register_android_bluetooth_ScoSocket(JNIEnv *env); -extern int register_android_server_BluetoothDeviceService(JNIEnv* env); +extern int register_android_server_BluetoothService(JNIEnv* env); extern int register_android_server_BluetoothEventLoop(JNIEnv *env); extern int register_android_server_BluetoothA2dpService(JNIEnv* env); extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env); @@ -1241,7 +1241,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_bluetooth_BluetoothAudioGateway), REG_JNI(register_android_bluetooth_BluetoothSocket), REG_JNI(register_android_bluetooth_ScoSocket), - REG_JNI(register_android_server_BluetoothDeviceService), + REG_JNI(register_android_server_BluetoothService), REG_JNI(register_android_server_BluetoothEventLoop), REG_JNI(register_android_server_BluetoothA2dpService), REG_JNI(register_android_message_digest_sha1), diff --git a/core/jni/android_server_BluetoothDeviceService.cpp b/core/jni/android_server_BluetoothService.cpp index 444e628..326052b 100644 --- a/core/jni/android_server_BluetoothDeviceService.cpp +++ b/core/jni/android_server_BluetoothService.cpp @@ -16,7 +16,7 @@ #define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter" #define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device" -#define LOG_TAG "BluetoothDeviceService.cpp" +#define LOG_TAG "BluetoothService.cpp" #include "android_bluetooth_common.h" #include "android_runtime/AndroidRuntime.h" @@ -49,7 +49,7 @@ namespace android { #ifdef HAVE_BLUETOOTH // We initialize these variables when we load class -// android.server.BluetoothDeviceService +// android.server.BluetoothService static jfieldID field_mNativeData; static jfieldID field_mEventLoop; @@ -732,9 +732,9 @@ static JNINativeMethod sMethods[] = { (void *)cancelPairingUserInputNative}, }; -int register_android_server_BluetoothDeviceService(JNIEnv *env) { +int register_android_server_BluetoothService(JNIEnv *env) { return AndroidRuntime::registerNativeMethods(env, - "android/server/BluetoothDeviceService", sMethods, NELEM(sMethods)); + "android/server/BluetoothService", sMethods, NELEM(sMethods)); } } /* namespace android */ diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 5a59712..05b68d4 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -17,16 +17,16 @@ package android.media; import android.app.ActivityManagerNative; +import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.bluetooth.BluetoothIntent; -import android.content.BroadcastReceiver; -import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothA2dp; -import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothClass; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothIntent; +import android.bluetooth.BluetoothHeadset; import android.content.pm.PackageManager; import android.database.ContentObserver; @@ -236,8 +236,6 @@ public class AudioService extends IAudioService.Stub { // Forced device usage for communications private int mForcedUseForComm; - private BluetoothDevice mBluetoothDevice = null; - /////////////////////////////////////////////////////////////////////////// // Construction /////////////////////////////////////////////////////////////////////////// @@ -1371,8 +1369,8 @@ public class AudioService extends IAudioService.Stub { if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) { int state = intent.getIntExtra(BluetoothA2dp.SINK_STATE, BluetoothA2dp.STATE_DISCONNECTED); - String address = intent.getStringExtra(BluetoothIntent.ADDRESS); - + BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothIntent.DEVICE); + String address = btDevice.getAddress(); boolean isConnected = (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && ((String)mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)).equals(address)); @@ -1387,30 +1385,27 @@ public class AudioService extends IAudioService.Stub { AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, AudioSystem.DEVICE_STATE_AVAILABLE, address); - mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), address); + mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), + address); } } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) { int state = intent.getIntExtra(BluetoothIntent.HEADSET_STATE, BluetoothHeadset.STATE_ERROR); - String address = intent.getStringExtra(BluetoothIntent.ADDRESS); + BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothIntent.DEVICE); + String address = btDevice.getAddress(); int device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; - if (mBluetoothDevice == null) { - mBluetoothDevice = (BluetoothDevice)mContext.getSystemService(Context.BLUETOOTH_SERVICE); - } - if (mBluetoothDevice != null) { - int btClass = mBluetoothDevice.getRemoteClass(address); - if (BluetoothClass.Device.Major.getDeviceMajor(btClass) == BluetoothClass.Device.Major.AUDIO_VIDEO) { - switch (BluetoothClass.Device.getDevice(btClass)) { - case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET: - case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE: - device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; - break; - case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO: - device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; - break; - default: - break; - } + int btClass = btDevice.getBluetoothClass(); + if (BluetoothClass.Device.Major.getDeviceMajor(btClass) == BluetoothClass.Device.Major.AUDIO_VIDEO) { + switch (BluetoothClass.Device.getDevice(btClass)) { + case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET: + case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE: + device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; + break; + case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO: + device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; + break; + default: + break; } } @@ -1426,7 +1421,7 @@ public class AudioService extends IAudioService.Stub { AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE, address); - mConnectedDevices.put( new Integer(device), address); + mConnectedDevices.put(new Integer(device), address); } } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) { int state = intent.getIntExtra("state", 0); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index a5bd254..56a279a 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -30,7 +30,7 @@ import java.util.zip.CRC32; import android.backup.BackupDataInput; import android.backup.BackupDataOutput; import android.backup.BackupHelperAgent; -import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothAdapter; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; @@ -393,7 +393,7 @@ public class SettingsBackupAgent extends BackupHelperAgent { } private void enableBluetooth(boolean enable) { - BluetoothDevice bt = (BluetoothDevice) getSystemService(Context.BLUETOOTH_SERVICE); + BluetoothAdapter bt = (BluetoothAdapter) getSystemService(Context.BLUETOOTH_SERVICE); if (bt != null) { if (!enable) { bt.disable(); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index ce476eb..98f35f4 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -36,7 +36,7 @@ import android.os.*; import android.provider.Contacts.People; import android.provider.Settings; import android.server.BluetoothA2dpService; -import android.server.BluetoothDeviceService; +import android.server.BluetoothService; import android.server.search.SearchManagerService; import android.util.EventLog; import android.util.Log; @@ -89,7 +89,7 @@ class ServerThread extends Thread { IPackageManager pm = null; Context context = null; WindowManagerService wm = null; - BluetoothDeviceService bluetooth = null; + BluetoothService bluetooth = null; BluetoothA2dpService bluetoothA2dp = null; HeadsetObserver headset = null; DockObserver dock = null; @@ -176,9 +176,9 @@ class ServerThread extends Thread { ServiceManager.addService(Context.BLUETOOTH_SERVICE, null); } else { Log.i(TAG, "Starting Bluetooth Service."); - bluetooth = new BluetoothDeviceService(context); - bluetooth.init(); + bluetooth = new BluetoothService(context); ServiceManager.addService(Context.BLUETOOTH_SERVICE, bluetooth); + bluetooth.initAfterRegistration(); bluetoothA2dp = new BluetoothA2dpService(context, bluetooth); ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE, bluetoothA2dp); diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java index e71d329..33d899a 100644 --- a/services/java/com/android/server/status/StatusBarPolicy.java +++ b/services/java/com/android/server/status/StatusBarPolicy.java @@ -18,7 +18,7 @@ package com.android.server.status; import android.app.AlertDialog; import android.bluetooth.BluetoothA2dp; -import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothError; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothIntent; @@ -473,10 +473,10 @@ public class StatusBarPolicy { mBluetoothData = IconData.makeIcon("bluetooth", null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0); mBluetoothIcon = service.addIcon(mBluetoothData, null); - BluetoothDevice bluetooth = - (BluetoothDevice) mContext.getSystemService(Context.BLUETOOTH_SERVICE); - if (bluetooth != null) { - mBluetoothEnabled = bluetooth.isEnabled(); + BluetoothAdapter adapter = + (BluetoothAdapter) mContext.getSystemService(Context.BLUETOOTH_SERVICE); + if (adapter != null) { + mBluetoothEnabled = adapter.isEnabled(); } else { mBluetoothEnabled = false; } @@ -1083,7 +1083,7 @@ public class StatusBarPolicy { if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) { int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE, BluetoothError.ERROR); - mBluetoothEnabled = state == BluetoothDevice.BLUETOOTH_STATE_ON; + mBluetoothEnabled = state == BluetoothAdapter.BLUETOOTH_STATE_ON; } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) { mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE, BluetoothHeadset.STATE_ERROR); diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java index 083cda3..fa24a98 100644 --- a/wifi/java/android/net/wifi/WifiStateTracker.java +++ b/wifi/java/android/net/wifi/WifiStateTracker.java @@ -39,6 +39,7 @@ import android.util.Log; import android.util.Config; import android.app.Notification; import android.app.PendingIntent; +import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothA2dp; import android.content.ContentResolver; @@ -49,6 +50,7 @@ import com.android.internal.app.IBatteryStats; import java.util.List; import java.util.ArrayList; +import java.util.Set; import java.net.UnknownHostException; /** @@ -645,10 +647,10 @@ public class WifiStateTracker extends NetworkStateTracker { private void checkIsBluetoothPlaying() { boolean isBluetoothPlaying = false; - List<String> connected = mBluetoothA2dp.listConnectedSinks(); + Set<BluetoothDevice> connected = mBluetoothA2dp.getConnectedSinks(); - for (String address : connected) { - if (mBluetoothA2dp.getSinkState(address) == BluetoothA2dp.STATE_PLAYING) { + for (BluetoothDevice device : connected) { + if (mBluetoothA2dp.getSinkState(device) == BluetoothA2dp.STATE_PLAYING) { isBluetoothPlaying = true; break; } |