BluetoothControllerImpl.java revision fac2538e463138a8a1a92bc94af3f310d28718b4
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 com.android.systemui.statusbar.policy;
18
19import android.app.ActivityManager;
20import android.bluetooth.BluetoothAdapter;
21import android.content.Context;
22import android.os.Handler;
23import android.os.Looper;
24import android.os.Message;
25import android.os.UserHandle;
26import android.os.UserManager;
27import android.util.Log;
28
29import com.android.settingslib.bluetooth.BluetoothCallback;
30import com.android.settingslib.bluetooth.CachedBluetoothDevice;
31import com.android.settingslib.bluetooth.LocalBluetoothManager;
32
33import java.io.FileDescriptor;
34import java.io.PrintWriter;
35import java.util.ArrayList;
36import java.util.Collection;
37
38public class BluetoothControllerImpl implements BluetoothController, BluetoothCallback,
39        CachedBluetoothDevice.Callback {
40    private static final String TAG = "BluetoothController";
41    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
42
43    private final LocalBluetoothManager mLocalBluetoothManager;
44    private final UserManager mUserManager;
45    private final int mCurrentUser;
46
47    private boolean mEnabled;
48    private int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
49    private CachedBluetoothDevice mLastDevice;
50
51    private final H mHandler = new H();
52    private int mState;
53
54    public BluetoothControllerImpl(Context context, Looper bgLooper) {
55        mLocalBluetoothManager = LocalBluetoothManager.getInstance(context, null);
56        if (mLocalBluetoothManager != null) {
57            mLocalBluetoothManager.getEventManager().setReceiverHandler(new Handler(bgLooper));
58            mLocalBluetoothManager.getEventManager().registerCallback(this);
59            onBluetoothStateChanged(
60                    mLocalBluetoothManager.getBluetoothAdapter().getBluetoothState());
61        }
62        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
63        mCurrentUser = ActivityManager.getCurrentUser();
64    }
65
66    @Override
67    public boolean canConfigBluetooth() {
68        return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH,
69                UserHandle.of(mCurrentUser));
70    }
71
72    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
73        pw.println("BluetoothController state:");
74        pw.print("  mLocalBluetoothManager="); pw.println(mLocalBluetoothManager);
75        if (mLocalBluetoothManager == null) {
76            return;
77        }
78        pw.print("  mEnabled="); pw.println(mEnabled);
79        pw.print("  mConnectionState="); pw.println(stateToString(mConnectionState));
80        pw.print("  mLastDevice="); pw.println(mLastDevice);
81        pw.print("  mCallbacks.size="); pw.println(mHandler.mCallbacks.size());
82        pw.println("  Bluetooth Devices:");
83        for (CachedBluetoothDevice device :
84                mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()) {
85            pw.println("    " + getDeviceString(device));
86        }
87    }
88
89    private static String stateToString(int state) {
90        switch (state) {
91            case BluetoothAdapter.STATE_CONNECTED:
92                return "CONNECTED";
93            case BluetoothAdapter.STATE_CONNECTING:
94                return "CONNECTING";
95            case BluetoothAdapter.STATE_DISCONNECTED:
96                return "DISCONNECTED";
97            case BluetoothAdapter.STATE_DISCONNECTING:
98                return "DISCONNECTING";
99        }
100        return "UNKNOWN(" + state + ")";
101    }
102
103    private String getDeviceString(CachedBluetoothDevice device) {
104        return device.getName() + " " + device.getBondState() + " " + device.isConnected();
105    }
106
107    @Override
108    public void addStateChangedCallback(Callback cb) {
109        mHandler.obtainMessage(H.MSG_ADD_CALLBACK, cb).sendToTarget();
110        mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
111    }
112
113    @Override
114    public void removeStateChangedCallback(Callback cb) {
115        mHandler.obtainMessage(H.MSG_REMOVE_CALLBACK, cb).sendToTarget();
116    }
117
118    @Override
119    public boolean isBluetoothEnabled() {
120        return mEnabled;
121    }
122
123    @Override
124    public int getBluetoothState() {
125        return mState;
126    }
127
128    @Override
129    public boolean isBluetoothConnected() {
130        return mConnectionState == BluetoothAdapter.STATE_CONNECTED;
131    }
132
133    @Override
134    public boolean isBluetoothConnecting() {
135        return mConnectionState == BluetoothAdapter.STATE_CONNECTING;
136    }
137
138    @Override
139    public void setBluetoothEnabled(boolean enabled) {
140        if (mLocalBluetoothManager != null) {
141            mLocalBluetoothManager.getBluetoothAdapter().setBluetoothEnabled(enabled);
142        }
143    }
144
145    @Override
146    public boolean isBluetoothSupported() {
147        return mLocalBluetoothManager != null;
148    }
149
150    @Override
151    public void connect(final CachedBluetoothDevice device) {
152        if (mLocalBluetoothManager == null || device == null) return;
153        device.connect(true);
154    }
155
156    @Override
157    public void disconnect(CachedBluetoothDevice device) {
158        if (mLocalBluetoothManager == null || device == null) return;
159        device.disconnect();
160    }
161
162    @Override
163    public String getLastDeviceName() {
164        return mLastDevice != null ? mLastDevice.getName() : null;
165    }
166
167    @Override
168    public Collection<CachedBluetoothDevice> getDevices() {
169        return mLocalBluetoothManager != null
170                ? mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()
171                : null;
172    }
173
174    private void updateConnected() {
175        // Make sure our connection state is up to date.
176        int state = mLocalBluetoothManager.getBluetoothAdapter().getConnectionState();
177        if (state != mConnectionState) {
178            mConnectionState = state;
179            mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
180        }
181        if (mLastDevice != null && mLastDevice.isConnected()) {
182            // Our current device is still valid.
183            return;
184        }
185        mLastDevice = null;
186        for (CachedBluetoothDevice device : getDevices()) {
187            if (device.isConnected()) {
188                mLastDevice = device;
189            }
190        }
191        if (mLastDevice == null && mConnectionState == BluetoothAdapter.STATE_CONNECTED) {
192            // If somehow we think we are connected, but have no connected devices, we aren't
193            // connected.
194            mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
195            mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
196        }
197    }
198
199    @Override
200    public void onBluetoothStateChanged(int bluetoothState) {
201        mEnabled = bluetoothState == BluetoothAdapter.STATE_ON
202                || bluetoothState == BluetoothAdapter.STATE_TURNING_ON;
203        mState = bluetoothState;
204        mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
205    }
206
207    @Override
208    public void onScanningStateChanged(boolean started) {
209        // Don't care.
210    }
211
212    @Override
213    public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
214        cachedDevice.registerCallback(this);
215        updateConnected();
216        mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
217    }
218
219    @Override
220    public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
221        updateConnected();
222        mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
223    }
224
225    @Override
226    public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
227        updateConnected();
228        mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
229    }
230
231    @Override
232    public void onDeviceAttributesChanged() {
233        updateConnected();
234        mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
235    }
236
237    @Override
238    public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
239        mLastDevice = cachedDevice;
240        updateConnected();
241        mConnectionState = state;
242        mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
243    }
244
245    private final class H extends Handler {
246        private final ArrayList<BluetoothController.Callback> mCallbacks = new ArrayList<>();
247
248        private static final int MSG_PAIRED_DEVICES_CHANGED = 1;
249        private static final int MSG_STATE_CHANGED = 2;
250        private static final int MSG_ADD_CALLBACK = 3;
251        private static final int MSG_REMOVE_CALLBACK = 4;
252
253        @Override
254        public void handleMessage(Message msg) {
255            switch (msg.what) {
256                case MSG_PAIRED_DEVICES_CHANGED:
257                    firePairedDevicesChanged();
258                    break;
259                case MSG_STATE_CHANGED:
260                    fireStateChange();
261                    break;
262                case MSG_ADD_CALLBACK:
263                    mCallbacks.add((BluetoothController.Callback) msg.obj);
264                    break;
265                case MSG_REMOVE_CALLBACK:
266                    mCallbacks.remove((BluetoothController.Callback) msg.obj);
267                    break;
268            }
269        }
270
271        private void firePairedDevicesChanged() {
272            for (BluetoothController.Callback cb : mCallbacks) {
273                cb.onBluetoothDevicesChanged();
274            }
275        }
276
277        private void fireStateChange() {
278            for (BluetoothController.Callback cb : mCallbacks) {
279                fireStateChange(cb);
280            }
281        }
282
283        private void fireStateChange(BluetoothController.Callback cb) {
284            cb.onBluetoothStateChange(mEnabled);
285        }
286    }
287}
288