• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.settingslib.bluetooth;
18 
19 import android.bluetooth.BluetoothA2dpSink;
20 import android.bluetooth.BluetoothAdapter;
21 import android.bluetooth.BluetoothClass;
22 import android.bluetooth.BluetoothDevice;
23 import android.bluetooth.BluetoothProfile;
24 import android.bluetooth.BluetoothUuid;
25 import android.content.Context;
26 import android.os.ParcelUuid;
27 import android.util.Log;
28 
29 import com.android.settingslib.R;
30 
31 import java.util.ArrayList;
32 import java.util.List;
33 
34 final class A2dpSinkProfile implements LocalBluetoothProfile {
35     private static final String TAG = "A2dpSinkProfile";
36     private static boolean V = true;
37 
38     private BluetoothA2dpSink mService;
39     private boolean mIsProfileReady;
40 
41     private final LocalBluetoothAdapter mLocalAdapter;
42     private final CachedBluetoothDeviceManager mDeviceManager;
43 
44     static final ParcelUuid[] SRC_UUIDS = {
45         BluetoothUuid.AudioSource,
46         BluetoothUuid.AdvAudioDist,
47     };
48 
49     static final String NAME = "A2DPSink";
50     private final LocalBluetoothProfileManager mProfileManager;
51 
52     // Order of this profile in device profiles list
53     private static final int ORDINAL = 5;
54 
55     // These callbacks run on the main thread.
56     private final class A2dpSinkServiceListener
57             implements BluetoothProfile.ServiceListener {
58 
onServiceConnected(int profile, BluetoothProfile proxy)59         public void onServiceConnected(int profile, BluetoothProfile proxy) {
60             if (V) Log.d(TAG,"Bluetooth service connected");
61             mService = (BluetoothA2dpSink) proxy;
62             // We just bound to the service, so refresh the UI for any connected A2DP devices.
63             List<BluetoothDevice> deviceList = mService.getConnectedDevices();
64             while (!deviceList.isEmpty()) {
65                 BluetoothDevice nextDevice = deviceList.remove(0);
66                 CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
67                 // we may add a new device here, but generally this should not happen
68                 if (device == null) {
69                     Log.w(TAG, "A2dpSinkProfile found new device: " + nextDevice);
70                     device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
71                 }
72                 device.onProfileStateChanged(A2dpSinkProfile.this, BluetoothProfile.STATE_CONNECTED);
73                 device.refresh();
74             }
75             mIsProfileReady=true;
76         }
77 
onServiceDisconnected(int profile)78         public void onServiceDisconnected(int profile) {
79             if (V) Log.d(TAG,"Bluetooth service disconnected");
80             mIsProfileReady=false;
81         }
82     }
83 
isProfileReady()84     public boolean isProfileReady() {
85         return mIsProfileReady;
86     }
87 
88     @Override
getProfileId()89     public int getProfileId() {
90         return BluetoothProfile.A2DP_SINK;
91     }
92 
A2dpSinkProfile(Context context, LocalBluetoothAdapter adapter, CachedBluetoothDeviceManager deviceManager, LocalBluetoothProfileManager profileManager)93     A2dpSinkProfile(Context context, LocalBluetoothAdapter adapter,
94             CachedBluetoothDeviceManager deviceManager,
95             LocalBluetoothProfileManager profileManager) {
96         mLocalAdapter = adapter;
97         mDeviceManager = deviceManager;
98         mProfileManager = profileManager;
99         mLocalAdapter.getProfileProxy(context, new A2dpSinkServiceListener(),
100                 BluetoothProfile.A2DP_SINK);
101     }
102 
isConnectable()103     public boolean isConnectable() {
104         return true;
105     }
106 
isAutoConnectable()107     public boolean isAutoConnectable() {
108         return true;
109     }
110 
getConnectedDevices()111     public List<BluetoothDevice> getConnectedDevices() {
112         if (mService == null) return new ArrayList<BluetoothDevice>(0);
113         return mService.getDevicesMatchingConnectionStates(
114               new int[] {BluetoothProfile.STATE_CONNECTED,
115                          BluetoothProfile.STATE_CONNECTING,
116                          BluetoothProfile.STATE_DISCONNECTING});
117     }
118 
connect(BluetoothDevice device)119     public boolean connect(BluetoothDevice device) {
120         if (mService == null) return false;
121         List<BluetoothDevice> srcs = getConnectedDevices();
122         if (srcs != null) {
123             for (BluetoothDevice src : srcs) {
124                 if (src.equals(device)) {
125                     // Connect to same device, Ignore it
126                     Log.d(TAG,"Ignoring Connect");
127                     return true;
128                 }
129             }
130         }
131         return mService.connect(device);
132     }
133 
disconnect(BluetoothDevice device)134     public boolean disconnect(BluetoothDevice device) {
135         if (mService == null) return false;
136         // Downgrade priority as user is disconnecting the headset.
137         if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
138             mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
139         }
140         return mService.disconnect(device);
141     }
142 
getConnectionStatus(BluetoothDevice device)143     public int getConnectionStatus(BluetoothDevice device) {
144         if (mService == null) {
145             return BluetoothProfile.STATE_DISCONNECTED;
146         }
147         return mService.getConnectionState(device);
148     }
149 
isPreferred(BluetoothDevice device)150     public boolean isPreferred(BluetoothDevice device) {
151         if (mService == null) return false;
152         return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
153     }
154 
getPreferred(BluetoothDevice device)155     public int getPreferred(BluetoothDevice device) {
156         if (mService == null) return BluetoothProfile.PRIORITY_OFF;
157         return mService.getPriority(device);
158     }
159 
setPreferred(BluetoothDevice device, boolean preferred)160     public void setPreferred(BluetoothDevice device, boolean preferred) {
161         if (mService == null) return;
162         if (preferred) {
163             if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
164                 mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
165             }
166         } else {
167             mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
168         }
169     }
170 
isA2dpPlaying()171     boolean isA2dpPlaying() {
172         if (mService == null) return false;
173         List<BluetoothDevice> srcs = mService.getConnectedDevices();
174         if (!srcs.isEmpty()) {
175             if (mService.isA2dpPlaying(srcs.get(0))) {
176                 return true;
177             }
178         }
179         return false;
180     }
181 
toString()182     public String toString() {
183         return NAME;
184     }
185 
getOrdinal()186     public int getOrdinal() {
187         return ORDINAL;
188     }
189 
getNameResource(BluetoothDevice device)190     public int getNameResource(BluetoothDevice device) {
191         // we need to have same string in UI for even SINK Media Audio.
192         return R.string.bluetooth_profile_a2dp;
193     }
194 
getSummaryResourceForDevice(BluetoothDevice device)195     public int getSummaryResourceForDevice(BluetoothDevice device) {
196         int state = getConnectionStatus(device);
197         switch (state) {
198             case BluetoothProfile.STATE_DISCONNECTED:
199                 return R.string.bluetooth_a2dp_profile_summary_use_for;
200 
201             case BluetoothProfile.STATE_CONNECTED:
202                 return R.string.bluetooth_a2dp_profile_summary_connected;
203 
204             default:
205                 return Utils.getConnectionStateSummary(state);
206         }
207     }
208 
getDrawableResource(BluetoothClass btClass)209     public int getDrawableResource(BluetoothClass btClass) {
210         return R.drawable.ic_bt_headphones_a2dp;
211     }
212 
finalize()213     protected void finalize() {
214         if (V) Log.d(TAG, "finalize()");
215         if (mService != null) {
216             try {
217                 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.A2DP_SINK,
218                                                                        mService);
219                 mService = null;
220             }catch (Throwable t) {
221                 Log.w(TAG, "Error cleaning up A2DP proxy", t);
222             }
223         }
224     }
225 }
226