blob: 656f23ffb70cfbdf257d697b49888d6256c9ad45 [file] [log] [blame]
Sanket Agarwal1bec6a52015-10-21 18:23:27 -07001/*
2 * Copyright (C) 2015 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.BluetoothA2dpSink;
20import android.bluetooth.BluetoothAdapter;
21import android.bluetooth.BluetoothClass;
22import android.bluetooth.BluetoothDevice;
23import android.bluetooth.BluetoothProfile;
24import android.bluetooth.BluetoothUuid;
25import android.content.Context;
26import android.os.ParcelUuid;
27import android.util.Log;
28
29import com.android.settingslib.R;
30
31import java.util.ArrayList;
32import java.util.List;
33
34final class A2dpSinkProfile implements LocalBluetoothProfile {
35 private static final String TAG = "A2dpSinkProfile";
Sanket Agarwal1bec6a52015-10-21 18:23:27 -070036
37 private BluetoothA2dpSink mService;
38 private boolean mIsProfileReady;
39
40 private final LocalBluetoothAdapter mLocalAdapter;
41 private final CachedBluetoothDeviceManager mDeviceManager;
42
43 static final ParcelUuid[] SRC_UUIDS = {
44 BluetoothUuid.AudioSource,
45 BluetoothUuid.AdvAudioDist,
46 };
47
48 static final String NAME = "A2DPSink";
49 private final LocalBluetoothProfileManager mProfileManager;
50
51 // Order of this profile in device profiles list
52 private static final int ORDINAL = 5;
53
54 // These callbacks run on the main thread.
55 private final class A2dpSinkServiceListener
56 implements BluetoothProfile.ServiceListener {
57
58 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Chienyuandcbc7de2018-09-05 21:28:59 +080059 Log.d(TAG, "Bluetooth service connected, profile:" + profile);
Sanket Agarwal1bec6a52015-10-21 18:23:27 -070060 mService = (BluetoothA2dpSink) proxy;
61 // We just bound to the service, so refresh the UI for any connected A2DP devices.
62 List<BluetoothDevice> deviceList = mService.getConnectedDevices();
63 while (!deviceList.isEmpty()) {
64 BluetoothDevice nextDevice = deviceList.remove(0);
65 CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
66 // we may add a new device here, but generally this should not happen
67 if (device == null) {
68 Log.w(TAG, "A2dpSinkProfile found new device: " + nextDevice);
69 device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
70 }
71 device.onProfileStateChanged(A2dpSinkProfile.this, BluetoothProfile.STATE_CONNECTED);
72 device.refresh();
73 }
74 mIsProfileReady=true;
75 }
76
77 public void onServiceDisconnected(int profile) {
Chienyuandcbc7de2018-09-05 21:28:59 +080078 Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
Sanket Agarwal1bec6a52015-10-21 18:23:27 -070079 mIsProfileReady=false;
80 }
81 }
82
83 public boolean isProfileReady() {
84 return mIsProfileReady;
85 }
86
ryanywlin44de3a02018-05-02 15:15:37 +080087 @Override
88 public int getProfileId() {
89 return BluetoothProfile.A2DP_SINK;
90 }
91
Sanket Agarwal1bec6a52015-10-21 18:23:27 -070092 A2dpSinkProfile(Context context, LocalBluetoothAdapter adapter,
93 CachedBluetoothDeviceManager deviceManager,
94 LocalBluetoothProfileManager profileManager) {
95 mLocalAdapter = adapter;
96 mDeviceManager = deviceManager;
97 mProfileManager = profileManager;
98 mLocalAdapter.getProfileProxy(context, new A2dpSinkServiceListener(),
99 BluetoothProfile.A2DP_SINK);
100 }
101
Leon Liao3b5e6bd2018-09-18 12:45:45 +0800102 public boolean accessProfileEnabled() {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700103 return true;
104 }
105
106 public boolean isAutoConnectable() {
107 return true;
108 }
109
110 public List<BluetoothDevice> getConnectedDevices() {
Chienyuandcbc7de2018-09-05 21:28:59 +0800111 if (mService == null) {
112 return new ArrayList<BluetoothDevice>(0);
113 }
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700114 return mService.getDevicesMatchingConnectionStates(
115 new int[] {BluetoothProfile.STATE_CONNECTED,
116 BluetoothProfile.STATE_CONNECTING,
117 BluetoothProfile.STATE_DISCONNECTING});
118 }
119
120 public boolean connect(BluetoothDevice device) {
Chienyuandcbc7de2018-09-05 21:28:59 +0800121 if (mService == null) {
122 return false;
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700123 }
124 return mService.connect(device);
125 }
126
127 public boolean disconnect(BluetoothDevice device) {
Chienyuandcbc7de2018-09-05 21:28:59 +0800128 if (mService == null) {
129 return false;
130 }
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700131 // Downgrade priority as user is disconnecting the headset.
Chienyuandcbc7de2018-09-05 21:28:59 +0800132 if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700133 mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
134 }
135 return mService.disconnect(device);
136 }
137
138 public int getConnectionStatus(BluetoothDevice device) {
139 if (mService == null) {
140 return BluetoothProfile.STATE_DISCONNECTED;
141 }
142 return mService.getConnectionState(device);
143 }
144
145 public boolean isPreferred(BluetoothDevice device) {
Chienyuandcbc7de2018-09-05 21:28:59 +0800146 if (mService == null) {
147 return false;
148 }
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700149 return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
150 }
151
152 public int getPreferred(BluetoothDevice device) {
Chienyuandcbc7de2018-09-05 21:28:59 +0800153 if (mService == null) {
154 return BluetoothProfile.PRIORITY_OFF;
155 }
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700156 return mService.getPriority(device);
157 }
158
159 public void setPreferred(BluetoothDevice device, boolean preferred) {
Chienyuandcbc7de2018-09-05 21:28:59 +0800160 if (mService == null) {
161 return;
162 }
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700163 if (preferred) {
164 if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
165 mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
166 }
167 } else {
168 mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
169 }
170 }
171
172 boolean isA2dpPlaying() {
Chienyuandcbc7de2018-09-05 21:28:59 +0800173 if (mService == null) {
174 return false;
175 }
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700176 List<BluetoothDevice> srcs = mService.getConnectedDevices();
177 if (!srcs.isEmpty()) {
178 if (mService.isA2dpPlaying(srcs.get(0))) {
179 return true;
180 }
181 }
182 return false;
183 }
184
185 public String toString() {
186 return NAME;
187 }
188
189 public int getOrdinal() {
190 return ORDINAL;
191 }
192
193 public int getNameResource(BluetoothDevice device) {
194 // we need to have same string in UI for even SINK Media Audio.
195 return R.string.bluetooth_profile_a2dp;
196 }
197
198 public int getSummaryResourceForDevice(BluetoothDevice device) {
199 int state = getConnectionStatus(device);
200 switch (state) {
201 case BluetoothProfile.STATE_DISCONNECTED:
202 return R.string.bluetooth_a2dp_profile_summary_use_for;
203
204 case BluetoothProfile.STATE_CONNECTED:
205 return R.string.bluetooth_a2dp_profile_summary_connected;
206
207 default:
208 return Utils.getConnectionStateSummary(state);
209 }
210 }
211
212 public int getDrawableResource(BluetoothClass btClass) {
213 return R.drawable.ic_bt_headphones_a2dp;
214 }
215
216 protected void finalize() {
Chienyuandcbc7de2018-09-05 21:28:59 +0800217 Log.d(TAG, "finalize()");
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700218 if (mService != null) {
219 try {
220 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.A2DP_SINK,
Chienyuandcbc7de2018-09-05 21:28:59 +0800221 mService);
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700222 mService = null;
223 }catch (Throwable t) {
224 Log.w(TAG, "Error cleaning up A2DP proxy", t);
225 }
226 }
227 }
228}