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