blob: 38c8a883d89c3b5f61920b18cd02e2f1a8fd507d [file] [log] [blame]
Jason Monk7ce96b92015-02-02 11:27:58 -05001/*
2 * Copyright (C) 2011 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.settingslib.bluetooth;
18
19import android.bluetooth.BluetoothAdapter;
20import android.bluetooth.BluetoothDevice;
21import android.bluetooth.BluetoothProfile;
Michael Wright9209c9c2015-09-03 17:57:01 +010022import android.bluetooth.le.BluetoothLeScanner;
Jason Monk7ce96b92015-02-02 11:27:58 -050023import android.content.Context;
24import android.os.ParcelUuid;
25import android.util.Log;
26
Stanley Tnga21efa52018-04-25 09:13:08 -070027import java.util.List;
Jason Monk7ce96b92015-02-02 11:27:58 -050028import java.util.Set;
29
30/**
31 * LocalBluetoothAdapter provides an interface between the Settings app
32 * and the functionality of the local {@link BluetoothAdapter}, specifically
33 * those related to state transitions of the adapter itself.
34 *
35 * <p>Connection and bonding state changes affecting specific devices
36 * are handled by {@link CachedBluetoothDeviceManager},
37 * {@link BluetoothEventManager}, and {@link LocalBluetoothProfileManager}.
38 */
Fan Zhang82dd3b02016-12-27 13:13:00 -080039public class LocalBluetoothAdapter {
Jason Monk7ce96b92015-02-02 11:27:58 -050040 private static final String TAG = "LocalBluetoothAdapter";
41
42 /** This class does not allow direct access to the BluetoothAdapter. */
43 private final BluetoothAdapter mAdapter;
44
45 private LocalBluetoothProfileManager mProfileManager;
46
47 private static LocalBluetoothAdapter sInstance;
48
49 private int mState = BluetoothAdapter.ERROR;
50
51 private static final int SCAN_EXPIRATION_MS = 5 * 60 * 1000; // 5 mins
52
53 private long mLastScan;
54
55 private LocalBluetoothAdapter(BluetoothAdapter adapter) {
56 mAdapter = adapter;
57 }
58
59 void setProfileManager(LocalBluetoothProfileManager manager) {
60 mProfileManager = manager;
61 }
62
63 /**
64 * Get the singleton instance of the LocalBluetoothAdapter. If this device
65 * doesn't support Bluetooth, then null will be returned. Callers must be
66 * prepared to handle a null return value.
67 * @return the LocalBluetoothAdapter object, or null if not supported
68 */
69 static synchronized LocalBluetoothAdapter getInstance() {
70 if (sInstance == null) {
71 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
72 if (adapter != null) {
73 sInstance = new LocalBluetoothAdapter(adapter);
74 }
75 }
76
77 return sInstance;
78 }
79
80 // Pass-through BluetoothAdapter methods that we can intercept if necessary
81
82 public void cancelDiscovery() {
83 mAdapter.cancelDiscovery();
84 }
85
86 public boolean enable() {
87 return mAdapter.enable();
88 }
89
90 public boolean disable() {
91 return mAdapter.disable();
92 }
93
jackqdyulei69061e22017-03-29 16:09:32 -070094 public String getAddress() {
95 return mAdapter.getAddress();
96 }
97
Jason Monk7ce96b92015-02-02 11:27:58 -050098 void getProfileProxy(Context context,
99 BluetoothProfile.ServiceListener listener, int profile) {
100 mAdapter.getProfileProxy(context, listener, profile);
101 }
102
103 public Set<BluetoothDevice> getBondedDevices() {
104 return mAdapter.getBondedDevices();
105 }
106
107 public String getName() {
108 return mAdapter.getName();
109 }
110
111 public int getScanMode() {
112 return mAdapter.getScanMode();
113 }
114
Michael Wright9209c9c2015-09-03 17:57:01 +0100115 public BluetoothLeScanner getBluetoothLeScanner() {
116 return mAdapter.getBluetoothLeScanner();
117 }
118
Jason Monk7ce96b92015-02-02 11:27:58 -0500119 public int getState() {
120 return mAdapter.getState();
121 }
122
123 public ParcelUuid[] getUuids() {
124 return mAdapter.getUuids();
125 }
126
127 public boolean isDiscovering() {
128 return mAdapter.isDiscovering();
129 }
130
131 public boolean isEnabled() {
132 return mAdapter.isEnabled();
133 }
134
Jason Monkbe3c5db2015-02-04 13:00:55 -0500135 public int getConnectionState() {
136 return mAdapter.getConnectionState();
137 }
138
Jason Monk7ce96b92015-02-02 11:27:58 -0500139 public void setDiscoverableTimeout(int timeout) {
140 mAdapter.setDiscoverableTimeout(timeout);
141 }
142
Marie Janssen23a48332017-01-24 14:09:59 -0800143 public long getDiscoveryEndMillis() {
144 return mAdapter.getDiscoveryEndMillis();
145 }
146
Jason Monk7ce96b92015-02-02 11:27:58 -0500147 public void setName(String name) {
148 mAdapter.setName(name);
149 }
150
151 public void setScanMode(int mode) {
152 mAdapter.setScanMode(mode);
153 }
154
155 public boolean setScanMode(int mode, int duration) {
156 return mAdapter.setScanMode(mode, duration);
157 }
158
159 public void startScanning(boolean force) {
160 // Only start if we're not already scanning
161 if (!mAdapter.isDiscovering()) {
162 if (!force) {
163 // Don't scan more than frequently than SCAN_EXPIRATION_MS,
164 // unless forced
165 if (mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) {
166 return;
167 }
168
169 // If we are playing music, don't scan unless forced.
170 A2dpProfile a2dp = mProfileManager.getA2dpProfile();
171 if (a2dp != null && a2dp.isA2dpPlaying()) {
172 return;
173 }
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700174 A2dpSinkProfile a2dpSink = mProfileManager.getA2dpSinkProfile();
175 if ((a2dpSink != null) && (a2dpSink.isA2dpPlaying())){
176 return;
177 }
Jason Monk7ce96b92015-02-02 11:27:58 -0500178 }
179
180 if (mAdapter.startDiscovery()) {
181 mLastScan = System.currentTimeMillis();
182 }
183 }
184 }
185
186 public void stopScanning() {
187 if (mAdapter.isDiscovering()) {
188 mAdapter.cancelDiscovery();
189 }
190 }
191
192 public synchronized int getBluetoothState() {
193 // Always sync state, in case it changed while paused
194 syncBluetoothState();
195 return mState;
196 }
197
Gurpreet Ghai64ece0e2016-08-10 15:14:40 +0530198 void setBluetoothStateInt(int state) {
199 synchronized(this) {
200 if (mState == state) {
201 return;
202 }
203 mState = state;
204 }
Jason Monk7ce96b92015-02-02 11:27:58 -0500205
206 if (state == BluetoothAdapter.STATE_ON) {
207 // if mProfileManager hasn't been constructed yet, it will
208 // get the adapter UUIDs in its constructor when it is.
209 if (mProfileManager != null) {
210 mProfileManager.setBluetoothStateOn();
211 }
212 }
213 }
214
215 // Returns true if the state changed; false otherwise.
216 boolean syncBluetoothState() {
217 int currentState = mAdapter.getState();
218 if (currentState != mState) {
219 setBluetoothStateInt(mAdapter.getState());
220 return true;
221 }
222 return false;
223 }
224
Sanket Agarwal090bf552016-04-21 14:10:55 -0700225 public boolean setBluetoothEnabled(boolean enabled) {
Jason Monk7ce96b92015-02-02 11:27:58 -0500226 boolean success = enabled
227 ? mAdapter.enable()
228 : mAdapter.disable();
229
230 if (success) {
231 setBluetoothStateInt(enabled
232 ? BluetoothAdapter.STATE_TURNING_ON
233 : BluetoothAdapter.STATE_TURNING_OFF);
234 } else {
235 if (Utils.V) {
236 Log.v(TAG, "setBluetoothEnabled call, manager didn't return " +
237 "success for enabled: " + enabled);
238 }
239
240 syncBluetoothState();
241 }
Sanket Agarwal090bf552016-04-21 14:10:55 -0700242 return success;
Jason Monk7ce96b92015-02-02 11:27:58 -0500243 }
Jason Monk64ff8a52015-06-02 14:05:18 -0400244
245 public BluetoothDevice getRemoteDevice(String address) {
246 return mAdapter.getRemoteDevice(address);
247 }
Pavlin Radoslavov03d44ce2018-01-21 02:59:15 -0800248
249 public int getMaxConnectedAudioDevices() {
250 return mAdapter.getMaxConnectedAudioDevices();
251 }
Stanley Tnga21efa52018-04-25 09:13:08 -0700252
253 public List<Integer> getSupportedProfiles() {
254 return mAdapter.getSupportedProfiles();
255 }
Jason Monk7ce96b92015-02-02 11:27:58 -0500256}