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