BluetoothDevice.java revision 228b2f3a813e93413a0f9e2f29dfbfc54590a356
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.bluetooth;
18
19import android.os.RemoteException;
20import android.util.Log;
21
22import java.io.UnsupportedEncodingException;
23
24/**
25 * The Android Bluetooth API is not finalized, and *will* change. Use at your
26 * own risk.
27 *
28 * Manages the local Bluetooth device. Scan for devices, create bondings,
29 * power up and down the adapter.
30 *
31 * @hide
32 */
33public class BluetoothDevice {
34
35    public static final int BLUETOOTH_STATE_OFF = 0;
36    public static final int BLUETOOTH_STATE_TURNING_ON = 1;
37    public static final int BLUETOOTH_STATE_ON = 2;
38    public static final int BLUETOOTH_STATE_TURNING_OFF = 3;
39
40    /** Inquiry scan and page scan are both off.
41     *  Device is neither discoverable nor connectable */
42    public static final int SCAN_MODE_NONE = 0;
43    /** Page scan is on, inquiry scan is off.
44     *  Device is connectable, but not discoverable */
45    public static final int SCAN_MODE_CONNECTABLE = 1;
46    /** Page scan and inquiry scan are on.
47     *  Device is connectable and discoverable */
48    public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 3;
49
50    public static final int RESULT_FAILURE = -1;
51    public static final int RESULT_SUCCESS = 0;
52
53    /** We do not have a link key for the remote device, and are therefore not
54     * bonded */
55    public static final int BOND_NOT_BONDED = 0;
56    /** We have a link key for the remote device, and are probably bonded. */
57    public static final int BOND_BONDED = 1;
58    /** We are currently attempting bonding */
59    public static final int BOND_BONDING = 2;
60
61    //TODO: Unify these result codes in BluetoothResult or BluetoothError
62    /** A bond attempt failed because pins did not match, or remote device did
63     * not respond to pin request in time */
64    public static final int UNBOND_REASON_AUTH_FAILED = 1;
65    /** A bond attempt failed because the other side explicilty rejected
66     * bonding */
67    public static final int UNBOND_REASON_AUTH_REJECTED = 2;
68    /** A bond attempt failed because we canceled the bonding process */
69    public static final int UNBOND_REASON_AUTH_CANCELED = 3;
70    /** A bond attempt failed because we could not contact the remote device */
71    public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
72    /** A bond attempt failed because a discovery is in progress */
73    public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
74    /** An existing bond was explicitly revoked */
75    public static final int UNBOND_REASON_REMOVED = 6;
76
77    /* The user will be prompted to enter a pin */
78    public static final int PAIRING_VARIANT_PIN = 0;
79    /* The user will be prompted to enter a passkey */
80    public static final int PAIRING_VARIANT_PASSKEY = 1;
81    /* The user will be prompted to confirm the passkey displayed on the screen */
82    public static final int PAIRING_VARIANT_CONFIRMATION = 2;
83
84
85    private static final String TAG = "BluetoothDevice";
86
87    private final IBluetoothDevice mService;
88    /**
89     * @hide - hide this because it takes a parameter of type
90     * IBluetoothDevice, which is a System private class.
91     * Also note that Context.getSystemService is a factory that
92     * returns a BlueToothDevice. That is the right way to get
93     * a BluetoothDevice.
94     */
95    public BluetoothDevice(IBluetoothDevice service) {
96        mService = service;
97    }
98
99    /**
100     * Is Bluetooth currently turned on.
101     *
102     * @return true if Bluetooth enabled, false otherwise.
103     */
104    public boolean isEnabled() {
105        try {
106            return mService.isEnabled();
107        } catch (RemoteException e) {Log.e(TAG, "", e);}
108        return false;
109    }
110
111    /**
112     * Get the current state of Bluetooth.
113     *
114     * @return One of BLUETOOTH_STATE_ or BluetoothError.ERROR.
115     */
116    public int getBluetoothState() {
117        try {
118            return mService.getBluetoothState();
119        } catch (RemoteException e) {Log.e(TAG, "", e);}
120        return BluetoothError.ERROR;
121    }
122
123    /**
124     * Enable the Bluetooth device.
125     * Turn on the underlying hardware.
126     * This is an asynchronous call,
127     * BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION can be used to check if
128     * and when the device is sucessfully enabled.
129     * @return false if we cannot enable the Bluetooth device. True does not
130     * imply the device was enabled, it only implies that so far there were no
131     * problems.
132     */
133    public boolean enable() {
134        try {
135            return mService.enable();
136        } catch (RemoteException e) {Log.e(TAG, "", e);}
137        return false;
138    }
139
140    /**
141     * Disable the Bluetooth device.
142     * This turns off the underlying hardware.
143     *
144     * @return true if successful, false otherwise.
145     */
146    public boolean disable() {
147        try {
148            return mService.disable(true);
149        } catch (RemoteException e) {Log.e(TAG, "", e);}
150        return false;
151    }
152
153    public String getAddress() {
154        try {
155            return mService.getAddress();
156        } catch (RemoteException e) {Log.e(TAG, "", e);}
157        return null;
158    }
159
160    /**
161     * Get the friendly Bluetooth name of this device.
162     *
163     * This name is visible to remote Bluetooth devices. Currently it is only
164     * possible to retrieve the Bluetooth name when Bluetooth is enabled.
165     *
166     * @return the Bluetooth name, or null if there was a problem.
167     */
168    public String getName() {
169        try {
170            return mService.getName();
171        } catch (RemoteException e) {Log.e(TAG, "", e);}
172        return null;
173    }
174
175    /**
176     * Set the friendly Bluetooth name of this device.
177     *
178     * This name is visible to remote Bluetooth devices. The Bluetooth Service
179     * is responsible for persisting this name.
180     *
181     * @param name the name to set
182     * @return     true, if the name was successfully set. False otherwise.
183     */
184    public boolean setName(String name) {
185        try {
186            return mService.setName(name);
187        } catch (RemoteException e) {Log.e(TAG, "", e);}
188        return false;
189    }
190
191    /**
192     * Get the current scan mode.
193     * Used to determine if the local device is connectable and/or discoverable
194     * @return Scan mode, one of SCAN_MODE_* or an error code
195     */
196    public int getScanMode() {
197        try {
198            return mService.getScanMode();
199        } catch (RemoteException e) {Log.e(TAG, "", e);}
200        return BluetoothError.ERROR_IPC;
201    }
202
203    /**
204     * Set the current scan mode.
205     * Used to make the local device connectable and/or discoverable
206     * @param scanMode One of SCAN_MODE_*
207     */
208    public void setScanMode(int scanMode) {
209        try {
210            mService.setScanMode(scanMode);
211        } catch (RemoteException e) {Log.e(TAG, "", e);}
212    }
213
214    public int getDiscoverableTimeout() {
215        try {
216            return mService.getDiscoverableTimeout();
217        } catch (RemoteException e) {Log.e(TAG, "", e);}
218        return -1;
219    }
220    public void setDiscoverableTimeout(int timeout) {
221        try {
222            mService.setDiscoverableTimeout(timeout);
223        } catch (RemoteException e) {Log.e(TAG, "", e);}
224    }
225
226    public boolean startDiscovery() {
227        try {
228            return mService.startDiscovery();
229        } catch (RemoteException e) {Log.e(TAG, "", e);}
230        return false;
231    }
232
233    public void cancelDiscovery() {
234        try {
235            mService.cancelDiscovery();
236        } catch (RemoteException e) {Log.e(TAG, "", e);}
237    }
238
239    public boolean isDiscovering() {
240        try {
241            return mService.isDiscovering();
242        } catch (RemoteException e) {Log.e(TAG, "", e);}
243        return false;
244    }
245
246    /**
247     * Removes the remote device and the pairing information associated
248     * with it.
249     *
250     * @param address the Bluetooth hardware address you want to disconnect.
251     * @return true if the device was disconnected, false otherwise and on
252     *         error.
253     */
254    public boolean removeBond(String address) {
255        try {
256            return mService.removeBond(address);
257        } catch (RemoteException e) {Log.e(TAG, "", e);}
258        return false;
259    }
260
261    /**
262     * Create a bonding with a remote bluetooth device.
263     *
264     * This is an asynchronous call. The result of this bonding attempt can be
265     * observed through BluetoothIntent.BOND_STATE_CHANGED_ACTION intents.
266     *
267     * @param address the remote device Bluetooth address.
268     * @return false If there was an immediate problem creating the bonding,
269     *         true otherwise.
270     */
271    public boolean createBond(String address) {
272        try {
273            return mService.createBond(address);
274        } catch (RemoteException e) {Log.e(TAG, "", e);}
275        return false;
276    }
277
278    /**
279     * Cancel an in-progress bonding request started with createBond.
280     */
281    public boolean cancelBondProcess(String address) {
282        try {
283            return mService.cancelBondProcess(address);
284        } catch (RemoteException e) {Log.e(TAG, "", e);}
285        return false;
286    }
287
288    /**
289     * List remote devices that are bonded (paired) to the local device.
290     *
291     * Bonding (pairing) is the process by which the user enters a pin code for
292     * the device, which generates a shared link key, allowing for
293     * authentication and encryption of future connections. In Android we
294     * require bonding before RFCOMM or SCO connections can be made to a remote
295     * device.
296     *
297     * This function lists which remote devices we have a link key for. It does
298     * not cause any RF transmission, and does not check if the remote device
299     * still has it's link key with us. If the other side no longer has its
300     * link key then the RFCOMM or SCO connection attempt will result in an
301     * error.
302     *
303     * This function does not check if the remote device is in range.
304     *
305     * Remote devices that have an in-progress bonding attempt are not
306     * returned.
307     *
308     * @return bluetooth hardware addresses of remote devices that are
309     *         bonded. Array size is 0 if no devices are bonded. Null on error.
310     */
311    public String[] listBonds() {
312        try {
313            return mService.listBonds();
314        } catch (RemoteException e) {Log.e(TAG, "", e);}
315        return null;
316    }
317
318    /**
319     * Get the bonding state of a remote device.
320     *
321     * Result is one of:
322     * BluetoothError.*
323     * BOND_*
324     *
325     * @param address Bluetooth hardware address of the remote device to check.
326     * @return Result code
327     */
328    public int getBondState(String address) {
329        try {
330            return mService.getBondState(address);
331        } catch (RemoteException e) {Log.e(TAG, "", e);}
332        return BluetoothError.ERROR_IPC;
333    }
334
335    public String getRemoteName(String address) {
336        try {
337            return mService.getRemoteName(address);
338        } catch (RemoteException e) {Log.e(TAG, "", e);}
339        return null;
340    }
341
342    public int getRemoteClass(String address) {
343        try {
344            return mService.getRemoteClass(address);
345        } catch (RemoteException e) {Log.e(TAG, "", e);}
346        return BluetoothError.ERROR_IPC;
347    }
348
349     public String[] getRemoteUuids(String address) {
350        try {
351            return mService.getRemoteUuids(address);
352        } catch (RemoteException e) {Log.e(TAG, "", e);}
353        return null;
354    }
355
356    public int getRemoteServiceChannel(String address, String uuid) {
357         try {
358             return mService.getRemoteServiceChannel(address, uuid);
359         } catch (RemoteException e) {Log.e(TAG, "", e);}
360         return BluetoothError.ERROR_IPC;
361    }
362
363    public boolean setPin(String address, byte[] pin) {
364        try {
365            return mService.setPin(address, pin);
366        } catch (RemoteException e) {Log.e(TAG, "", e);}
367        return false;
368    }
369
370    public boolean setPasskey(String address, int passkey) {
371        try {
372            return mService.setPasskey(address, passkey);
373        } catch (RemoteException e) {Log.e(TAG, "", e);}
374        return false;
375    }
376
377    public boolean setPairingConfirmation(String address, boolean confirm) {
378        try {
379            return mService.setPairingConfirmation(address, confirm);
380        } catch (RemoteException e) {Log.e(TAG, "", e);}
381        return false;
382    }
383
384    public boolean cancelPairingUserInput(String address) {
385        try {
386            return mService.cancelPairingUserInput(address);
387        } catch (RemoteException e) {Log.e(TAG, "", e);}
388        return false;
389    }
390
391    /**
392     * Check that a pin is valid and convert to byte array.
393     *
394     * Bluetooth pin's are 1 to 16 bytes of UTF8 characters.
395     * @param pin pin as java String
396     * @return the pin code as a UTF8 byte array, or null if it is an invalid
397     *         Bluetooth pin.
398     */
399    public static byte[] convertPinToBytes(String pin) {
400        if (pin == null) {
401            return null;
402        }
403        byte[] pinBytes;
404        try {
405            pinBytes = pin.getBytes("UTF8");
406        } catch (UnsupportedEncodingException uee) {
407            Log.e(TAG, "UTF8 not supported?!?");  // this should not happen
408            return null;
409        }
410        if (pinBytes.length <= 0 || pinBytes.length > 16) {
411            return null;
412        }
413        return pinBytes;
414    }
415
416    private static final int ADDRESS_LENGTH = 17;
417    /** Sanity check a bluetooth address, such as "00:43:A8:23:10:F0" */
418    public static boolean checkBluetoothAddress(String address) {
419        if (address == null || address.length() != ADDRESS_LENGTH) {
420            return false;
421        }
422        for (int i = 0; i < ADDRESS_LENGTH; i++) {
423            char c = address.charAt(i);
424            switch (i % 3) {
425            case 0:
426            case 1:
427                if (Character.digit(c, 16) != -1) {
428                    break;  // hex character, OK
429                }
430                return false;
431            case 2:
432                if (c == ':') {
433                    break;  // OK
434                }
435                return false;
436            }
437        }
438        return true;
439    }
440}
441