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