AdapterService.java revision 6c91bc0a163cc7600c40d7fb979777fd911d1ef1
1/*
2 * Copyright (C) 2012 Google Inc.
3 */
4
5/**
6 * @hide
7 */
8
9package com.android.bluetooth.btservice;
10
11import android.app.Application;
12import android.app.Service;
13import android.bluetooth.BluetoothAdapter;
14import android.bluetooth.BluetoothDevice;
15import android.bluetooth.BluetoothProfile;
16import android.bluetooth.IBluetooth;
17import android.content.BroadcastReceiver;
18import android.content.ContentResolver;
19import android.content.Context;
20import android.content.Intent;
21import android.content.IntentFilter;
22import android.os.Binder;
23import android.os.IBinder;
24import android.os.Message;
25import android.os.ParcelUuid;
26import android.os.RemoteException;
27import android.os.ServiceManager;
28import android.provider.Settings;
29import android.util.Log;
30import android.util.Pair;
31
32import com.android.bluetooth.hfp.HeadsetService;
33import com.android.bluetooth.a2dp.A2dpService;
34import com.android.bluetooth.Utils;
35import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties;
36
37import java.util.HashMap;
38import java.util.Set;
39
40public class AdapterService extends Application {
41    private static final String TAG = "BluetoothAdapterService";
42    private static final boolean DBG = true;
43
44    static final String BLUETOOTH_ADMIN_PERM =
45        android.Manifest.permission.BLUETOOTH_ADMIN;
46    static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
47
48    private AdapterProperties mAdapterProperties;
49    private int mAdapterState;
50    private Context mContext;
51    private boolean mIsAirplaneSensitive;
52    private boolean mIsAirplaneToggleable;
53    private static AdapterService sAdapterService;
54
55    private BluetoothAdapter mAdapter;
56    private AdapterState mAdapterStateMachine;
57    private BondStateMachine mBondStateMachine;
58    private JniCallbacks mJniCallbacks;
59
60
61    private RemoteDevices mRemoteDevices;
62    static {
63        System.loadLibrary("bluetooth_jni");
64        classInitNative();
65    }
66
67    @Override
68    public void onCreate() {
69        super.onCreate();
70        ServiceManager.addService(Context.BLUETOOTH_SERVICE, mBinder);
71
72        mAdapter = BluetoothAdapter.getDefaultAdapter();
73        mContext = this;
74        sAdapterService = this;
75
76        IntentFilter filter = new IntentFilter();
77        filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
78        registerForAirplaneMode(filter);
79        registerReceiver(mReceiver, filter);
80
81        mRemoteDevices = RemoteDevices.getInstance(this, mContext);
82        mAdapterProperties = AdapterProperties.getInstance(this, mContext);
83        mAdapterStateMachine = new AdapterState(this, mContext, mAdapterProperties);
84        mBondStateMachine = new BondStateMachine(this, mContext, mAdapterProperties);
85        mJniCallbacks = JniCallbacks.getInstance(mRemoteDevices, mAdapterProperties,
86                                                 mAdapterStateMachine, mBondStateMachine);
87
88
89        initNative();
90        mAdapterStateMachine.start();
91        mBondStateMachine.start();
92        //TODO(BT): Remove this when BT is no longer a persitent process.
93        int bluetoothOn = Settings.Secure.getInt(mContext.getContentResolver(),
94                                            Settings.Secure.BLUETOOTH_ON, 0);
95        if (!isAirplaneModeOn() && bluetoothOn != 0) mAdapter.enable();
96        startService(new Intent(this, HeadsetService.class));
97        startService(new Intent(this, A2dpService.class));
98    }
99
100    @Override
101    protected void finalize() throws Throwable {
102        mContext.unregisterReceiver(mReceiver);
103        try {
104            cleanupNative();
105        } finally {
106            super.finalize();
107        }
108    }
109
110    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
111        @Override
112        public void onReceive(Context context, Intent intent) {
113            if (intent == null) return;
114
115            String action = intent.getAction();
116            if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
117                ContentResolver resolver = context.getContentResolver();
118                // Query the airplane mode from Settings.System just to make sure that
119                // some random app is not sending this intent and disabling bluetooth
120                if (isAirplaneModeOn()) {
121                    mAdapterStateMachine.sendMessage(AdapterState.AIRPLANE_MODE_ON);
122                } else {
123                    mAdapterStateMachine.sendMessage(AdapterState.AIRPLANE_MODE_OFF);
124                }
125            }
126        }
127    };
128
129
130
131    private void registerForAirplaneMode(IntentFilter filter) {
132        final ContentResolver resolver = mContext.getContentResolver();
133        final String airplaneModeRadios = Settings.System.getString(resolver,
134                Settings.System.AIRPLANE_MODE_RADIOS);
135        final String toggleableRadios = Settings.System.getString(resolver,
136                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
137
138        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
139                airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
140        mIsAirplaneToggleable = toggleableRadios == null ? false :
141                toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH);
142
143        if (mIsAirplaneSensitive) {
144            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
145        }
146    }
147
148    /* Returns true if airplane mode is currently on */
149    private final boolean isAirplaneModeOn() {
150        return Settings.System.getInt(mContext.getContentResolver(),
151                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
152    }
153
154    /**
155     * Handlers for incoming service calls
156     */
157    private final IBluetooth.Stub mBinder = new IBluetooth.Stub() {
158        public boolean isEnabled() {
159            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
160            return mAdapterProperties.getState() == BluetoothAdapter.STATE_ON;
161        }
162
163        public int getState() {
164            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
165            return mAdapterProperties.getState();
166        }
167
168        public boolean enable() {
169            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
170                    "Need BLUETOOTH ADMIN permission");
171            // Persist the setting
172            Message m =
173                    mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON);
174            m.arg1 = 1;
175            mAdapterStateMachine.sendMessage(m);
176            return true;
177        }
178
179        public boolean disable(boolean persist) {
180            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
181                    "Need BLUETOOTH ADMIN permission");
182            int val = (persist ? 1 : 0);
183            Message m =
184                    mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF);
185            m.arg1 = val;
186            mAdapterStateMachine.sendMessage(m);
187            return true;
188        }
189
190        public String getAddress() {
191            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
192            String addrString = null;
193            byte[] address = mAdapterProperties.getAddress();
194            return Utils.getAddressStringFromByte(address);
195        }
196
197        public ParcelUuid[] getUuids() {
198            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
199            return mAdapterProperties.getUuids();
200        }
201
202        public String getName() {
203            enforceCallingOrSelfPermission(BLUETOOTH_PERM,
204                    "Need BLUETOOTH permission");
205            return mAdapterProperties.getName();
206        }
207
208        public boolean setName(String name) {
209            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
210                    "Need BLUETOOTH ADMIN permission");
211            return mAdapterProperties.setName(name);
212        }
213
214        public int getScanMode() {
215            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
216            return mAdapterProperties.getScanMode();
217        }
218
219        public boolean setScanMode(int mode, int duration) {
220            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
221            setDiscoverableTimeout(duration);
222
223            int newMode = convertScanModeToHal(mode);
224            return mAdapterProperties.setScanMode(newMode);
225        }
226
227        public int getDiscoverableTimeout() {
228            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
229            return mAdapterProperties.getDiscoverableTimeout();
230        }
231
232        public boolean setDiscoverableTimeout(int timeout) {
233            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
234            return mAdapterProperties.setDiscoverableTimeout(timeout);
235        }
236
237        public boolean startDiscovery() {
238            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
239                    "Need BLUETOOTH ADMIN permission");
240            return startDiscoveryNative();
241        }
242
243        public boolean cancelDiscovery() {
244            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
245                    "Need BLUETOOTH ADMIN permission");
246            return cancelDiscoveryNative();
247        }
248
249        public boolean isDiscovering() {
250            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
251            return mAdapterProperties.isDiscovering();
252        }
253
254        public BluetoothDevice[] getBondedDevices() {
255            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
256            debugLog("Get Bonded Devices being called");
257            return mAdapterProperties.getBondedDevices();
258        }
259
260        public int getAdapterConnectionState() {
261            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
262            return mAdapterProperties.getConnectionState();
263        }
264
265        public int getProfileConnectionState(int profile) {
266            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
267            return mAdapterProperties.getProfileConnectionState(profile);
268        }
269
270        public boolean createBond(BluetoothDevice device) {
271            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
272                "Need BLUETOOTH ADMIN permission");
273            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
274            if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) {
275                return false;
276            }
277
278            Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);
279            msg.obj = device;
280            mBondStateMachine.sendMessage(msg);
281            return true;
282        }
283
284        public boolean cancelBondProcess(BluetoothDevice device) {
285            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
286            byte[] addr = Utils.getBytesFromAddress(device.getAddress());
287            return cancelBondNative(addr);
288        }
289
290        public boolean removeBond(BluetoothDevice device) {
291            enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
292                "Need BLUETOOTH ADMIN permission");
293            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
294            if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDED) {
295                return false;
296            }
297            Message msg = mBondStateMachine.obtainMessage(BondStateMachine.REMOVE_BOND);
298            msg.obj = device;
299            mBondStateMachine.sendMessage(msg);
300            return true;
301        }
302
303        public int getBondState(BluetoothDevice device) {
304            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
305            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
306            if (deviceProp == null) {
307                return BluetoothDevice.BOND_NONE;
308            }
309            return deviceProp.getBondState();
310        }
311
312        public String getRemoteName(BluetoothDevice device) {
313            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
314            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
315            if (deviceProp == null) return null;
316            return deviceProp.getName();
317        }
318
319        public String getRemoteAlias(BluetoothDevice device) {
320            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
321            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
322            if (deviceProp == null) return null;
323            return deviceProp.getAlias();
324        }
325
326        public boolean setRemoteAlias(BluetoothDevice device, String name) {
327            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
328            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
329            if (deviceProp == null) return false;
330            deviceProp.setAlias(name);
331            return true;
332        }
333
334        public int getRemoteClass(BluetoothDevice device) {
335            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
336            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
337            if (deviceProp == null) return 0;
338
339            return deviceProp.getBluetoothClass();
340        }
341
342        public ParcelUuid[] getRemoteUuids(BluetoothDevice device) {
343            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
344            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
345            if (deviceProp == null) return null;
346            return deviceProp.getUuids();
347        }
348
349        public boolean fetchRemoteUuids(BluetoothDevice device) {
350            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
351            mRemoteDevices.performSdp(device);
352            return true;
353        }
354
355        public boolean setPin(BluetoothDevice device, boolean accept, int len, byte[] pinCode) {
356            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
357            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
358            if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
359                return false;
360            }
361
362            byte[] addr = Utils.getBytesFromAddress(device.getAddress());
363            return pinReplyNative(addr, accept, len, pinCode);
364        }
365
366        public boolean setPasskey(BluetoothDevice device, boolean accept, int len, byte[] passkey) {
367            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
368            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
369            if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
370                return false;
371            }
372
373            byte[] addr = Utils.getBytesFromAddress(device.getAddress());
374            return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY, accept,
375                    Utils.byteArrayToInt(passkey));
376        }
377
378        public boolean setPairingConfirmation(BluetoothDevice device, boolean accept) {
379            enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
380            DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
381            if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
382                return false;
383            }
384
385            byte[] addr = Utils.getBytesFromAddress(device.getAddress());
386            return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION,
387                    accept, 0);
388        }
389
390        public void sendConnectionStateChange(BluetoothDevice
391                device, int profile, int state, int prevState) {
392            // Since this is a binder call check if Bluetooth is on still
393            if (getState() == BluetoothAdapter.STATE_OFF) return;
394
395            mAdapterProperties.sendConnectionStateChange(device, profile, state, prevState);
396
397        }
398
399    };
400
401    private int convertScanModeToHal(int mode) {
402        switch (mode) {
403            case BluetoothAdapter.SCAN_MODE_NONE:
404                return AbstractionLayer.BT_SCAN_MODE_NONE;
405            case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
406                return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE;
407            case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
408                return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE;
409        }
410        errorLog("Incorrect scan mode in convertScanModeToHal");
411        return -1;
412    }
413
414    int convertScanModeFromHal(int mode) {
415        switch (mode) {
416            case AbstractionLayer.BT_SCAN_MODE_NONE:
417                return BluetoothAdapter.SCAN_MODE_NONE;
418            case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE:
419                return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
420            case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE:
421                return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
422        }
423        errorLog("Incorrect scan mode in convertScanModeFromHal");
424        return -1;
425    }
426
427    private static void debugLog(String msg) {
428        Log.d(TAG, msg);
429    }
430
431    private static void errorLog(String msg) {
432        Log.e(TAG, msg);
433    }
434
435    void persistBluetoothSetting(boolean setOn) {
436        long origCallerIdentityToken = Binder.clearCallingIdentity();
437        Settings.Secure.putInt(mContext.getContentResolver(),
438                               Settings.Secure.BLUETOOTH_ON,
439                               setOn ? 1 : 0);
440        Binder.restoreCallingIdentity(origCallerIdentityToken);
441    }
442
443    private boolean getBluetoothPersistedSetting() {
444        ContentResolver contentResolver = mContext.getContentResolver();
445        return (Settings.Secure.getInt(contentResolver,
446                                       Settings.Secure.BLUETOOTH_ON, 0) > 0);
447    }
448
449    private native static void classInitNative();
450    private native boolean initNative();
451    private native void cleanupNative();
452    /*package*/ native boolean enableNative();
453    /*package*/ native boolean disableNative();
454    /*package*/ native boolean setAdapterPropertyNative(int type, byte[] val);
455    /*package*/ native boolean getAdapterPropertiesNative();
456    /*package*/ native boolean getAdapterPropertyNative(int type);
457    /*package*/ native boolean setAdapterPropertyNative(int type);
458    /*package*/ native boolean
459        setDevicePropertyNative(byte[] address, int type, byte[] val);
460    /*package*/ native boolean getDevicePropertyNative(byte[] address, int type);
461
462    /*package*/ native boolean createBondNative(byte[] address);
463    /*package*/ native boolean removeBondNative(byte[] address);
464    /*package*/ native boolean cancelBondNative(byte[] address);
465
466    private native boolean startDiscoveryNative();
467    private native boolean cancelDiscoveryNative();
468
469    private native boolean pinReplyNative(byte[] address, boolean accept, int len, byte[] pin);
470    private native boolean sspReplyNative(byte[] address, int type, boolean
471            accept, int passkey);
472}
473