blob: 22674cb6de9bdb32a32edab2c234002da895fa4f [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
197 synchronized void setBluetoothStateInt(int state) {
198 mState = state;
199
200 if (state == BluetoothAdapter.STATE_ON) {
201 // if mProfileManager hasn't been constructed yet, it will
202 // get the adapter UUIDs in its constructor when it is.
203 if (mProfileManager != null) {
204 mProfileManager.setBluetoothStateOn();
205 }
206 }
207 }
208
209 // Returns true if the state changed; false otherwise.
210 boolean syncBluetoothState() {
211 int currentState = mAdapter.getState();
212 if (currentState != mState) {
213 setBluetoothStateInt(mAdapter.getState());
214 return true;
215 }
216 return false;
217 }
218
Sanket Agarwal090bf552016-04-21 14:10:55 -0700219 public boolean setBluetoothEnabled(boolean enabled) {
Jason Monk7ce96b92015-02-02 11:27:58 -0500220 boolean success = enabled
221 ? mAdapter.enable()
222 : mAdapter.disable();
223
224 if (success) {
225 setBluetoothStateInt(enabled
226 ? BluetoothAdapter.STATE_TURNING_ON
227 : BluetoothAdapter.STATE_TURNING_OFF);
228 } else {
229 if (Utils.V) {
230 Log.v(TAG, "setBluetoothEnabled call, manager didn't return " +
231 "success for enabled: " + enabled);
232 }
233
234 syncBluetoothState();
235 }
Sanket Agarwal090bf552016-04-21 14:10:55 -0700236 return success;
Jason Monk7ce96b92015-02-02 11:27:58 -0500237 }
Jason Monk64ff8a52015-06-02 14:05:18 -0400238
239 public BluetoothDevice getRemoteDevice(String address) {
240 return mAdapter.getRemoteDevice(address);
241 }
Jason Monk7ce96b92015-02-02 11:27:58 -0500242}