• 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 
HfpClientProfile(Context context, LocalBluetoothAdapter adapter, CachedBluetoothDeviceManager deviceManager, LocalBluetoothProfileManager profileManager)95     HfpClientProfile(Context context, LocalBluetoothAdapter adapter,
96             CachedBluetoothDeviceManager deviceManager,
97             LocalBluetoothProfileManager profileManager) {
98         mLocalAdapter = adapter;
99         mDeviceManager = deviceManager;
100         mProfileManager = profileManager;
101         mLocalAdapter.getProfileProxy(context, new HfpClientServiceListener(),
102                 BluetoothProfile.HEADSET_CLIENT);
103     }
104 
105     @Override
isConnectable()106     public boolean isConnectable() {
107         return true;
108     }
109 
110     @Override
isAutoConnectable()111     public boolean isAutoConnectable() {
112         return true;
113     }
114 
getConnectedDevices()115     public List<BluetoothDevice> getConnectedDevices() {
116         if (mService == null) return new ArrayList<BluetoothDevice>(0);
117         return mService.getDevicesMatchingConnectionStates(
118               new int[] {BluetoothProfile.STATE_CONNECTED,
119                          BluetoothProfile.STATE_CONNECTING,
120                          BluetoothProfile.STATE_DISCONNECTING});
121     }
122 
123     @Override
connect(BluetoothDevice device)124     public boolean connect(BluetoothDevice device) {
125         if (mService == null) return false;
126         List<BluetoothDevice> srcs = getConnectedDevices();
127         if (srcs != null) {
128             for (BluetoothDevice src : srcs) {
129                 if (src.equals(device)) {
130                     // Connect to same device, Ignore it
131                     Log.d(TAG,"Ignoring Connect");
132                     return true;
133                 }
134             }
135         }
136         return mService.connect(device);
137     }
138 
139     @Override
disconnect(BluetoothDevice device)140     public boolean disconnect(BluetoothDevice device) {
141         if (mService == null) return false;
142         // Downgrade priority as user is disconnecting the headset.
143         if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
144             mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
145         }
146         return mService.disconnect(device);
147     }
148 
149     @Override
getConnectionStatus(BluetoothDevice device)150     public int getConnectionStatus(BluetoothDevice device) {
151         if (mService == null) {
152             return BluetoothProfile.STATE_DISCONNECTED;
153         }
154         return mService.getConnectionState(device);
155     }
156 
157     @Override
isPreferred(BluetoothDevice device)158     public boolean isPreferred(BluetoothDevice device) {
159         if (mService == null) return false;
160         return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
161     }
162 
163     @Override
getPreferred(BluetoothDevice device)164     public int getPreferred(BluetoothDevice device) {
165         if (mService == null) return BluetoothProfile.PRIORITY_OFF;
166         return mService.getPriority(device);
167     }
168 
169     @Override
setPreferred(BluetoothDevice device, boolean preferred)170     public void setPreferred(BluetoothDevice device, boolean preferred) {
171         if (mService == null) return;
172         if (preferred) {
173             if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
174                 mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
175             }
176         } else {
177             mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
178         }
179     }
180 
181     @Override
toString()182     public String toString() {
183         return NAME;
184     }
185 
186     @Override
getOrdinal()187     public int getOrdinal() {
188         return ORDINAL;
189     }
190 
191     @Override
getNameResource(BluetoothDevice device)192     public int getNameResource(BluetoothDevice device) {
193         return R.string.bluetooth_profile_headset;
194     }
195 
196     @Override
getSummaryResourceForDevice(BluetoothDevice device)197     public int getSummaryResourceForDevice(BluetoothDevice device) {
198         int state = getConnectionStatus(device);
199         switch (state) {
200             case BluetoothProfile.STATE_DISCONNECTED:
201                 return R.string.bluetooth_headset_profile_summary_use_for;
202 
203             case BluetoothProfile.STATE_CONNECTED:
204                 return R.string.bluetooth_headset_profile_summary_connected;
205 
206             default:
207                 return Utils.getConnectionStateSummary(state);
208         }
209     }
210 
211     @Override
getDrawableResource(BluetoothClass btClass)212     public int getDrawableResource(BluetoothClass btClass) {
213         return R.drawable.ic_bt_headset_hfp;
214     }
215 
finalize()216     protected void finalize() {
217         if (V) Log.d(TAG, "finalize()");
218         if (mService != null) {
219             try {
220                 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
221                     BluetoothProfile.HEADSET_CLIENT, mService);
222                 mService = null;
223             } catch (Throwable t) {
224                 Log.w(TAG, "Error cleaning up HfpClient proxy", t);
225             }
226         }
227     }
228 }
229