1afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project/* 2436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Copyright (C) 2011 The Android Open Source Project 3afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * 4afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * you may not use this file except in compliance with the License. 6afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * You may obtain a copy of the License at 7afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * 8afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * 10afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * See the License for the specific language governing permissions and 14afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * limitations under the License. 15afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 16afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 17afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectpackage com.android.settings.bluetooth; 18afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 19afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.bluetooth.BluetoothA2dp; 20d63c0112251ab4e4e977545368dd703d875012a4Nick Pellyimport android.bluetooth.BluetoothDevice; 21afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.bluetooth.BluetoothHeadset; 22792d2132e408ded2b2d56646ba263808dd51fc31Adam Powellimport android.bluetooth.BluetoothInputDevice; 2332711b6752eb73324e1b10db975ac956888eda96Danica Changimport android.bluetooth.BluetoothPan; 245809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganeshimport android.bluetooth.BluetoothProfile; 252aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chanimport android.bluetooth.BluetoothUuid; 26436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.content.Context; 27436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.content.Intent; 283327f7887328c55ef2d837a8e2a07cea2070c744Michael Chanimport android.os.ParcelUuid; 29f2f3ceebbdf724e8904712a2a21cb0e677b7ea0dMichael Chanimport android.util.Log; 30afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 31632a10f470d5086d18fab3eec89cef1d03e899c6Jake Hambyimport java.util.ArrayList; 32436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport java.util.Collection; 33afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport java.util.HashMap; 34afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport java.util.Map; 35afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 36afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project/** 37436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * LocalBluetoothProfileManager provides access to the LocalBluetoothProfile 38436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * objects for the available Bluetooth profiles. 39afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 40436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyfinal class LocalBluetoothProfileManager { 412aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan private static final String TAG = "LocalBluetoothProfileManager"; 422aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 43436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby /** Singleton instance. */ 44436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private static LocalBluetoothProfileManager sInstance; 4532711b6752eb73324e1b10db975ac956888eda96Danica Chang 4657d5585595810044e7727d4303214f69ff2d77d4Michael Chan /** 4757d5585595810044e7727d4303214f69ff2d77d4Michael Chan * An interface for notifying BluetoothHeadset IPC clients when they have 4857d5585595810044e7727d4303214f69ff2d77d4Michael Chan * been connected to the BluetoothHeadset service. 49436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Only used by {@link DockService}. 5057d5585595810044e7727d4303214f69ff2d77d4Michael Chan */ 5157d5585595810044e7727d4303214f69ff2d77d4Michael Chan public interface ServiceListener { 5257d5585595810044e7727d4303214f69ff2d77d4Michael Chan /** 5357d5585595810044e7727d4303214f69ff2d77d4Michael Chan * Called to notify the client when this proxy object has been 5457d5585595810044e7727d4303214f69ff2d77d4Michael Chan * connected to the BluetoothHeadset service. Clients must wait for 5557d5585595810044e7727d4303214f69ff2d77d4Michael Chan * this callback before making IPC calls on the BluetoothHeadset 5657d5585595810044e7727d4303214f69ff2d77d4Michael Chan * service. 5757d5585595810044e7727d4303214f69ff2d77d4Michael Chan */ 58436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void onServiceConnected(); 5957d5585595810044e7727d4303214f69ff2d77d4Michael Chan 6057d5585595810044e7727d4303214f69ff2d77d4Michael Chan /** 6157d5585595810044e7727d4303214f69ff2d77d4Michael Chan * Called to notify the client that this proxy object has been 6257d5585595810044e7727d4303214f69ff2d77d4Michael Chan * disconnected from the BluetoothHeadset service. Clients must not 6357d5585595810044e7727d4303214f69ff2d77d4Michael Chan * make IPC calls on the BluetoothHeadset service after this callback. 6457d5585595810044e7727d4303214f69ff2d77d4Michael Chan * This callback will currently only occur if the application hosting 6557d5585595810044e7727d4303214f69ff2d77d4Michael Chan * the BluetoothHeadset service, but may be called more often in future. 6657d5585595810044e7727d4303214f69ff2d77d4Michael Chan */ 67436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void onServiceDisconnected(); 68f2f3ceebbdf724e8904712a2a21cb0e677b7ea0dMichael Chan } 692aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 70436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final Context mContext; 71436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final LocalBluetoothAdapter mLocalAdapter; 72436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final CachedBluetoothDeviceManager mDeviceManager; 73436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final BluetoothEventManager mEventManager; 748c04b90cc95b16f8d7e99a61d8e2c940ed83b0c4Jaikumar Ganesh 75436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private A2dpProfile mA2dpProfile; 76436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private HeadsetProfile mHeadsetProfile; 77436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final HidProfile mHidProfile; 78436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private OppProfile mOppProfile; 79436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final PanProfile mPanProfile; 80afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 81afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project /** 82436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Mapping from profile name, e.g. "HEADSET" to profile object. 83afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 84436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final Map<String, LocalBluetoothProfile> 85436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mProfileNameMap = new HashMap<String, LocalBluetoothProfile>(); 86afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 87436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby LocalBluetoothProfileManager(Context context, 88436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby LocalBluetoothAdapter adapter, 89436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby CachedBluetoothDeviceManager deviceManager, 90436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothEventManager eventManager) { 91436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mContext = context; 92a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin 93436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mLocalAdapter = adapter; 94436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mDeviceManager = deviceManager; 95436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mEventManager = eventManager; 96436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // pass this reference to adapter and event manager (circular dependency) 97436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mLocalAdapter.setProfileManager(this); 98436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mEventManager.setProfileManager(this); 99498d12bac0df509a4f74a4df8a8c69ec22583a1aJaikumar Ganesh 100436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby ParcelUuid[] uuids = adapter.getUuids(); 101a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin 102436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // uuids may be null if Bluetooth is turned off 103436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (uuids != null) { 104436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby updateLocalProfiles(uuids); 105a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin } 106792d2132e408ded2b2d56646ba263808dd51fc31Adam Powell 107436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Always add HID and PAN profiles 108436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mHidProfile = new HidProfile(context, mLocalAdapter); 109436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby addProfile(mHidProfile, HidProfile.NAME, 110436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED); 11132711b6752eb73324e1b10db975ac956888eda96Danica Chang 112436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mPanProfile = new PanProfile(context); 113c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby addPanProfile(mPanProfile, PanProfile.NAME, 114c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby BluetoothPan.ACTION_CONNECTION_STATE_CHANGED); 115c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby 116436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.d(TAG, "LocalBluetoothProfileManager construction complete"); 117afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 118afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 119afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project /** 120436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Initialize or update the local profile objects. If a UUID was previously 121436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * present but has been removed, we print a warning but don't remove the 122436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * profile object as it might be referenced elsewhere, or the UUID might 123436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * come back and we don't want multiple copies of the profile objects. 124436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * @param uuids 125afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 126436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void updateLocalProfiles(ParcelUuid[] uuids) { 127436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // A2DP 128436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSource)) { 129436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (mA2dpProfile == null) { 130436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.d(TAG, "Adding local A2DP profile"); 131436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mA2dpProfile = new A2dpProfile(mContext); 132436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby addProfile(mA2dpProfile, A2dpProfile.NAME, 133436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); 134648bf5fd9e099cd677f7609afde831ac446deef0The Android Open Source Project } 135436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } else if (mA2dpProfile != null) { 136436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.w(TAG, "Warning: A2DP profile was previously added but the UUID is now missing."); 137436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 138436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 139436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Headset / Handsfree 140436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) || 141436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP_AG)) { 142436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (mHeadsetProfile == null) { 143436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.d(TAG, "Adding local HEADSET profile"); 144436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mHeadsetProfile = new HeadsetProfile(mContext, mLocalAdapter, 145436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mDeviceManager, this); 146436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby addProfile(mHeadsetProfile, HeadsetProfile.NAME, 147436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); 1480bd445b974292dc3910b6bb85dcee7e7c378968fMichael Chan } 149436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } else if (mHeadsetProfile != null) { 150436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.w(TAG, "Warning: HEADSET profile was previously added but the UUID is now missing."); 151afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 1522aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 153436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // OPP 154436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) { 155436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (mOppProfile == null) { 156436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.d(TAG, "Adding local OPP profile"); 157436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mOppProfile = new OppProfile(); 158436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Note: no event handler for OPP, only name map. 159436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mProfileNameMap.put(OppProfile.NAME, mOppProfile); 160afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 161436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } else if (mOppProfile != null) { 162436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing."); 163afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 1646eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh mEventManager.registerProfileIntentReceiver(); 165afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 166436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // There is no local SDP record for HID and Settings app doesn't control PBAP 167afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 1682aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 169436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final Collection<ServiceListener> mServiceListeners = 170436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby new ArrayList<ServiceListener>(); 1712aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 172436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private void addProfile(LocalBluetoothProfile profile, 173436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby String profileName, String stateChangedAction) { 1746eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh mEventManager.addProfileHandler(stateChangedAction, new StateChangedHandler(profile)); 175436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mProfileNameMap.put(profileName, profile); 176436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 177afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 178c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby private void addPanProfile(LocalBluetoothProfile profile, 179c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby String profileName, String stateChangedAction) { 180c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby mEventManager.addProfileHandler(stateChangedAction, 181c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby new PanStateChangedHandler(profile)); 182c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby mProfileNameMap.put(profileName, profile); 183c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby } 184c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby 185436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby LocalBluetoothProfile getProfileByName(String name) { 186436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mProfileNameMap.get(name); 187436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 18848e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani 189436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Called from LocalBluetoothAdapter when state changes to ON 190436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void setBluetoothStateOn() { 191436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby ParcelUuid[] uuids = mLocalAdapter.getUuids(); 192436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (uuids != null) { 193436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby updateLocalProfiles(uuids); 19448e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani } 195436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mEventManager.readPairedDevices(); 196afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 197a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin 198a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin /** 199436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Generic handler for connection state change events for the specified profile. 200a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin */ 201436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private class StateChangedHandler implements BluetoothEventManager.Handler { 202c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby final LocalBluetoothProfile mProfile; 203a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin 204436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby StateChangedHandler(LocalBluetoothProfile profile) { 205436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mProfile = profile; 206a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin } 207a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin 208436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onReceive(Context context, Intent intent, BluetoothDevice device) { 209436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); 210436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (cachedDevice == null) { 211436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.w(TAG, "StateChangedHandler found new device: " + device); 212436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby cachedDevice = mDeviceManager.addDevice(mLocalAdapter, 213436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby LocalBluetoothProfileManager.this, device); 214a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin } 215436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0); 216436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0); 217436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (newState == BluetoothProfile.STATE_DISCONNECTED && 218436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby oldState == BluetoothProfile.STATE_CONNECTING) { 219436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.i(TAG, "Failed to connect " + mProfile + " device"); 220a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin } 22148e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani 222436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby cachedDevice.onProfileStateChanged(mProfile, newState); 223436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby cachedDevice.refresh(); 22448e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani } 225a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin } 226792d2132e408ded2b2d56646ba263808dd51fc31Adam Powell 227c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby /** State change handler for NAP and PANU profiles. */ 228c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby private class PanStateChangedHandler extends StateChangedHandler { 229c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby 230c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby PanStateChangedHandler(LocalBluetoothProfile profile) { 231c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby super(profile); 232c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby } 233c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby 234c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby @Override 235c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby public void onReceive(Context context, Intent intent, BluetoothDevice device) { 236c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby PanProfile panProfile = (PanProfile) mProfile; 237c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby int role = intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, 0); 238c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby panProfile.setLocalRole(device, role); 239c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby super.onReceive(context, intent, device); 240c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby } 241c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby } 242c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby 243436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // called from DockService 244436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void addServiceListener(ServiceListener l) { 245436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mServiceListeners.add(l); 246436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 247792d2132e408ded2b2d56646ba263808dd51fc31Adam Powell 248436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // called from DockService 249436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void removeServiceListener(ServiceListener l) { 250436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mServiceListeners.remove(l); 251436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 252792d2132e408ded2b2d56646ba263808dd51fc31Adam Powell 253436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // not synchronized: use only from UI thread! (TODO: verify) 254436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void callServiceConnectedListeners() { 255436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby for (ServiceListener l : mServiceListeners) { 256436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby l.onServiceConnected(); 257792d2132e408ded2b2d56646ba263808dd51fc31Adam Powell } 258436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 25948e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani 260436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // not synchronized: use only from UI thread! (TODO: verify) 261436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void callServiceDisconnectedListeners() { 262436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby for (ServiceListener listener : mServiceListeners) { 263436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby listener.onServiceDisconnected(); 26448e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani } 265792d2132e408ded2b2d56646ba263808dd51fc31Adam Powell } 26632711b6752eb73324e1b10db975ac956888eda96Danica Chang 267436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // This is called by DockService, so check Headset and A2DP. 268436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public synchronized boolean isManagerReady() { 269436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Getting just the headset profile is fine for now. Will need to deal with A2DP 270436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // and others if they aren't always in a ready state. 271436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby LocalBluetoothProfile profile = mHeadsetProfile; 272436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (profile != null) { 273436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return profile.isProfileReady(); 2749ad703cdb9a8d0972c123b041d18aa7bbeb391a4Jaikumar Ganesh } 275436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby profile = mA2dpProfile; 276436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (profile != null) { 277436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return profile.isProfileReady(); 2789ad703cdb9a8d0972c123b041d18aa7bbeb391a4Jaikumar Ganesh } 279436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return false; 280436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 2819ad703cdb9a8d0972c123b041d18aa7bbeb391a4Jaikumar Ganesh 282436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby A2dpProfile getA2dpProfile() { 283436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mA2dpProfile; 284436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 28532711b6752eb73324e1b10db975ac956888eda96Danica Chang 286436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby HeadsetProfile getHeadsetProfile() { 287436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mHeadsetProfile; 288436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 28932711b6752eb73324e1b10db975ac956888eda96Danica Chang 290436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby /** 291436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Fill in a list of LocalBluetoothProfile objects that are supported by 292436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * the local device and the remote device. 293436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * 294436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * @param uuids of the remote device 295436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * @param localUuids UUIDs of the local device 296436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * @param profiles The list of profiles to fill 297c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby * @param removedProfiles list of profiles that were removed 298436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby */ 299436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby synchronized void updateProfiles(ParcelUuid[] uuids, ParcelUuid[] localUuids, 300c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby Collection<LocalBluetoothProfile> profiles, 301c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby Collection<LocalBluetoothProfile> removedProfiles) { 302c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby // Copy previous profile list into removedProfiles 303c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby removedProfiles.clear(); 304c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby removedProfiles.addAll(profiles); 305436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby profiles.clear(); 30632711b6752eb73324e1b10db975ac956888eda96Danica Chang 307436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (uuids == null) { 308436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return; 30932711b6752eb73324e1b10db975ac956888eda96Danica Chang } 31032711b6752eb73324e1b10db975ac956888eda96Danica Chang 311436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (mHeadsetProfile != null) { 312436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if ((BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG) && 313c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP)) || 314c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby (BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) && 315c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) { 316c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby profiles.add(mHeadsetProfile); 317c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby removedProfiles.remove(mHeadsetProfile); 31832711b6752eb73324e1b10db975ac956888eda96Danica Chang } 31932711b6752eb73324e1b10db975ac956888eda96Danica Chang } 32032711b6752eb73324e1b10db975ac956888eda96Danica Chang 321436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) && 322436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mA2dpProfile != null) { 323436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby profiles.add(mA2dpProfile); 324c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby removedProfiles.remove(mA2dpProfile); 32532711b6752eb73324e1b10db975ac956888eda96Danica Chang } 32632711b6752eb73324e1b10db975ac956888eda96Danica Chang 327436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) && 328436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mOppProfile != null) { 329436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby profiles.add(mOppProfile); 330c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby removedProfiles.remove(mOppProfile); 33132711b6752eb73324e1b10db975ac956888eda96Danica Chang } 33232711b6752eb73324e1b10db975ac956888eda96Danica Chang 333436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hid) && 334436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mHidProfile != null) { 335436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby profiles.add(mHidProfile); 336c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby removedProfiles.remove(mHidProfile); 33732711b6752eb73324e1b10db975ac956888eda96Danica Chang } 33848e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani 339436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP) && 340436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mPanProfile != null) { 341436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby profiles.add(mPanProfile); 342c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby removedProfiles.remove(mPanProfile); 34348e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani } 34432711b6752eb73324e1b10db975ac956888eda96Danica Chang } 345afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project} 346