blob: 4ce9d3e2dff297d9a4ed4756749e3a34c03ab202 [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
Sanket Agarwal1bec6a52015-10-21 18:23:27 -070040 private final CachedBluetoothDeviceManager mDeviceManager;
41
42 static final ParcelUuid[] SRC_UUIDS = {
43 BluetoothUuid.AudioSource,
44 BluetoothUuid.AdvAudioDist,
45 };
46
47 static final String NAME = "A2DPSink";
48 private final LocalBluetoothProfileManager mProfileManager;
49
50 // Order of this profile in device profiles list
51 private static final int ORDINAL = 5;
52
53 // These callbacks run on the main thread.
54 private final class A2dpSinkServiceListener
55 implements BluetoothProfile.ServiceListener {
56
57 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -070058 mService = (BluetoothA2dpSink) proxy;
59 // We just bound to the service, so refresh the UI for any connected A2DP devices.
60 List<BluetoothDevice> deviceList = mService.getConnectedDevices();
61 while (!deviceList.isEmpty()) {
62 BluetoothDevice nextDevice = deviceList.remove(0);
63 CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
64 // we may add a new device here, but generally this should not happen
65 if (device == null) {
66 Log.w(TAG, "A2dpSinkProfile found new device: " + nextDevice);
timhypengf64f6902018-07-31 15:40:15 +080067 device = mDeviceManager.addDevice(nextDevice);
Sanket Agarwal1bec6a52015-10-21 18:23:27 -070068 }
69 device.onProfileStateChanged(A2dpSinkProfile.this, BluetoothProfile.STATE_CONNECTED);
70 device.refresh();
71 }
72 mIsProfileReady=true;
73 }
74
75 public void onServiceDisconnected(int profile) {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -070076 mIsProfileReady=false;
77 }
78 }
79
80 public boolean isProfileReady() {
81 return mIsProfileReady;
82 }
83
ryanywlin44de3a02018-05-02 15:15:37 +080084 @Override
85 public int getProfileId() {
86 return BluetoothProfile.A2DP_SINK;
87 }
88
timhypengf64f6902018-07-31 15:40:15 +080089 A2dpSinkProfile(Context context, CachedBluetoothDeviceManager deviceManager,
Sanket Agarwal1bec6a52015-10-21 18:23:27 -070090 LocalBluetoothProfileManager profileManager) {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -070091 mDeviceManager = deviceManager;
92 mProfileManager = profileManager;
timhypengf64f6902018-07-31 15:40:15 +080093 BluetoothAdapter.getDefaultAdapter().getProfileProxy(context, new A2dpSinkServiceListener(),
Sanket Agarwal1bec6a52015-10-21 18:23:27 -070094 BluetoothProfile.A2DP_SINK);
95 }
96
Leon Liao3b5e6bd2018-09-18 12:45:45 +080097 public boolean accessProfileEnabled() {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -070098 return true;
99 }
100
101 public boolean isAutoConnectable() {
102 return true;
103 }
104
105 public List<BluetoothDevice> getConnectedDevices() {
Chienyuan447fbde2018-09-05 21:28:59 +0800106 if (mService == null) {
107 return new ArrayList<BluetoothDevice>(0);
108 }
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700109 return mService.getDevicesMatchingConnectionStates(
110 new int[] {BluetoothProfile.STATE_CONNECTED,
111 BluetoothProfile.STATE_CONNECTING,
112 BluetoothProfile.STATE_DISCONNECTING});
113 }
114
115 public boolean connect(BluetoothDevice device) {
Chienyuan447fbde2018-09-05 21:28:59 +0800116 if (mService == null) {
117 return false;
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700118 }
119 return mService.connect(device);
120 }
121
122 public boolean disconnect(BluetoothDevice device) {
Chienyuan447fbde2018-09-05 21:28:59 +0800123 if (mService == null) {
124 return false;
125 }
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700126 // Downgrade priority as user is disconnecting the headset.
Chienyuan447fbde2018-09-05 21:28:59 +0800127 if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700128 mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
129 }
130 return mService.disconnect(device);
131 }
132
133 public int getConnectionStatus(BluetoothDevice device) {
134 if (mService == null) {
135 return BluetoothProfile.STATE_DISCONNECTED;
136 }
137 return mService.getConnectionState(device);
138 }
139
140 public boolean isPreferred(BluetoothDevice device) {
Chienyuan447fbde2018-09-05 21:28:59 +0800141 if (mService == null) {
142 return false;
143 }
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700144 return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
145 }
146
147 public int getPreferred(BluetoothDevice device) {
Chienyuan447fbde2018-09-05 21:28:59 +0800148 if (mService == null) {
149 return BluetoothProfile.PRIORITY_OFF;
150 }
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700151 return mService.getPriority(device);
152 }
153
154 public void setPreferred(BluetoothDevice device, boolean preferred) {
Chienyuan447fbde2018-09-05 21:28:59 +0800155 if (mService == null) {
156 return;
157 }
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700158 if (preferred) {
159 if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
160 mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
161 }
162 } else {
163 mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
164 }
165 }
166
167 boolean isA2dpPlaying() {
Chienyuan447fbde2018-09-05 21:28:59 +0800168 if (mService == null) {
169 return false;
170 }
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700171 List<BluetoothDevice> srcs = mService.getConnectedDevices();
172 if (!srcs.isEmpty()) {
173 if (mService.isA2dpPlaying(srcs.get(0))) {
174 return true;
175 }
176 }
177 return false;
178 }
179
180 public String toString() {
181 return NAME;
182 }
183
184 public int getOrdinal() {
185 return ORDINAL;
186 }
187
188 public int getNameResource(BluetoothDevice device) {
189 // we need to have same string in UI for even SINK Media Audio.
190 return R.string.bluetooth_profile_a2dp;
191 }
192
193 public int getSummaryResourceForDevice(BluetoothDevice device) {
194 int state = getConnectionStatus(device);
195 switch (state) {
196 case BluetoothProfile.STATE_DISCONNECTED:
197 return R.string.bluetooth_a2dp_profile_summary_use_for;
198
199 case BluetoothProfile.STATE_CONNECTED:
200 return R.string.bluetooth_a2dp_profile_summary_connected;
201
202 default:
Kunhung Lie7b7cb82018-05-17 11:04:54 +0800203 return BluetoothUtils.getConnectionStateSummary(state);
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700204 }
205 }
206
207 public int getDrawableResource(BluetoothClass btClass) {
Amin Shaikh10f363b2019-01-24 17:59:49 -0500208 return com.android.internal.R.drawable.ic_bt_headphones_a2dp;
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700209 }
210
211 protected void finalize() {
Chienyuan447fbde2018-09-05 21:28:59 +0800212 Log.d(TAG, "finalize()");
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700213 if (mService != null) {
214 try {
215 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.A2DP_SINK,
216 mService);
217 mService = null;
218 }catch (Throwable t) {
219 Log.w(TAG, "Error cleaning up A2DP proxy", t);
220 }
221 }
222 }
223}