blob: a64c6d72d43c3ca83cb3ad2ddce0698015245739 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.bluetooth;
import android.os.RemoteException;
import android.util.Log;
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.
*
* @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;
/** We do not have a link key for the remote device, and are therefore not
* bonded */
public static final int BOND_NOT_BONDED = 0;
/** We have a link key for the remote device, and are probably bonded. */
public static final int BOND_BONDED = 1;
/** We are currently attempting bonding */
public static final int BOND_BONDING = 2;
//TODO: Unify these result codes in BluetoothResult or BluetoothError
/** A bond attempt failed because pins did not match, or remote device did
* not respond to pin request in time */
public static final int UNBOND_REASON_AUTH_FAILED = 1;
/** A bond attempt failed because the other side explicilty rejected
* bonding */
public static final int UNBOND_REASON_AUTH_REJECTED = 2;
/** A bond attempt failed because we canceled the bonding process */
public static final int UNBOND_REASON_AUTH_CANCELED = 3;
/** A bond attempt failed because we could not contact the remote device */
public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
/** A bond attempt failed because a discovery is in progress */
public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
/** An existing bond was explicitly revoked */
public static final int UNBOND_REASON_REMOVED = 6;
/* 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 static final String TAG = "BluetoothDevice";
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.
*/
public BluetoothDevice(IBluetoothDevice service) {
mService = service;
}
/**
* 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;
}
/**
* 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
* observed through BluetoothIntent.BOND_STATE_CHANGED_ACTION intents.
*
* @param address the remote device Bluetooth address.
* @return false If there was an immediate problem creating the bonding,
* true otherwise.
*/
public boolean createBond(String address) {
try {
return mService.createBond(address);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
/**
* Cancel an in-progress bonding request started with createBond.
*/
public boolean cancelBondProcess(String address) {
try {
return mService.cancelBondProcess(address);
} 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.
*
* @return bluetooth hardware addresses of remote devices that are
* bonded. Array size is 0 if no devices are bonded. Null on error.
*/
public String[] listBonds() {
try {
return mService.listBonds();
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
/**
* Get the bonding state of a remote device.
*
* Result is one of:
* BluetoothError.*
* BOND_*
*
* @param address Bluetooth hardware address of the remote device to check.
* @return Result code
*/
public int getBondState(String address) {
try {
return mService.getBondState(address);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return BluetoothError.ERROR_IPC;
}
public String getRemoteName(String address) {
try {
return mService.getRemoteName(address);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
public int getRemoteClass(String address) {
try {
return mService.getRemoteClass(address);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return BluetoothError.ERROR_IPC;
}
public String[] getRemoteUuids(String address) {
try {
return mService.getRemoteUuids(address);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
public int getRemoteServiceChannel(String address, String uuid) {
try {
return mService.getRemoteServiceChannel(address, uuid);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return BluetoothError.ERROR_IPC;
}
public boolean setPin(String address, byte[] pin) {
try {
return mService.setPin(address, pin);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
public boolean setPasskey(String address, int passkey) {
try {
return mService.setPasskey(address, passkey);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
public boolean setPairingConfirmation(String address, boolean confirm) {
try {
return mService.setPairingConfirmation(address, confirm);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
public boolean cancelPairingUserInput(String address) {
try {
return mService.cancelPairingUserInput(address);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
/**
* Check that a pin is valid and convert to byte array.
*
* Bluetooth pin's are 1 to 16 bytes of UTF8 characters.
* @param pin pin as java String
* @return the pin code as a UTF8 byte array, or null if it is an invalid
* Bluetooth pin.
*/
public static byte[] convertPinToBytes(String pin) {
if (pin == null) {
return null;
}
byte[] pinBytes;
try {
pinBytes = pin.getBytes("UTF8");
} catch (UnsupportedEncodingException uee) {
Log.e(TAG, "UTF8 not supported?!?"); // this should not happen
return null;
}
if (pinBytes.length <= 0 || pinBytes.length > 16) {
return null;
}
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) {
return false;
}
for (int i = 0; i < ADDRESS_LENGTH; i++) {
char c = address.charAt(i);
switch (i % 3) {
case 0:
case 1:
if (Character.digit(c, 16) != -1) {
break; // hex character, OK
}
return false;
case 2:
if (c == ':') {
break; // OK
}
return false;
}
}
return true;
}
}