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; 240654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Battaimport android.bluetooth.BluetoothPbap; 255809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganeshimport android.bluetooth.BluetoothProfile; 262aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chanimport android.bluetooth.BluetoothUuid; 27436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.content.Context; 28436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport android.content.Intent; 293327f7887328c55ef2d837a8e2a07cea2070c744Michael Chanimport android.os.ParcelUuid; 30f2f3ceebbdf724e8904712a2a21cb0e677b7ea0dMichael Chanimport android.util.Log; 3100ec05985d6715daab7b15f105f0a9f3ada2ab83Swaminatha Balajiimport android.os.Handler; 3200ec05985d6715daab7b15f105f0a9f3ada2ab83Swaminatha Balajiimport android.os.Message; 33afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 34632a10f470d5086d18fab3eec89cef1d03e899c6Jake Hambyimport java.util.ArrayList; 35436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyimport java.util.Collection; 36afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport java.util.HashMap; 37afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport java.util.Map; 382ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balajiimport java.util.Set; 3900ec05985d6715daab7b15f105f0a9f3ada2ab83Swaminatha Balajiimport java.util.List; 40afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 41afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project/** 42436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * LocalBluetoothProfileManager provides access to the LocalBluetoothProfile 43436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * objects for the available Bluetooth profiles. 44afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 45436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambyfinal class LocalBluetoothProfileManager { 462aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan private static final String TAG = "LocalBluetoothProfileManager"; 472aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 48436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby /** Singleton instance. */ 49436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private static LocalBluetoothProfileManager sInstance; 5032711b6752eb73324e1b10db975ac956888eda96Danica Chang 5157d5585595810044e7727d4303214f69ff2d77d4Michael Chan /** 5257d5585595810044e7727d4303214f69ff2d77d4Michael Chan * An interface for notifying BluetoothHeadset IPC clients when they have 5357d5585595810044e7727d4303214f69ff2d77d4Michael Chan * been connected to the BluetoothHeadset service. 54436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Only used by {@link DockService}. 5557d5585595810044e7727d4303214f69ff2d77d4Michael Chan */ 5657d5585595810044e7727d4303214f69ff2d77d4Michael Chan public interface ServiceListener { 5757d5585595810044e7727d4303214f69ff2d77d4Michael Chan /** 5857d5585595810044e7727d4303214f69ff2d77d4Michael Chan * Called to notify the client when this proxy object has been 5957d5585595810044e7727d4303214f69ff2d77d4Michael Chan * connected to the BluetoothHeadset service. Clients must wait for 6057d5585595810044e7727d4303214f69ff2d77d4Michael Chan * this callback before making IPC calls on the BluetoothHeadset 6157d5585595810044e7727d4303214f69ff2d77d4Michael Chan * service. 6257d5585595810044e7727d4303214f69ff2d77d4Michael Chan */ 63436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void onServiceConnected(); 6457d5585595810044e7727d4303214f69ff2d77d4Michael Chan 6557d5585595810044e7727d4303214f69ff2d77d4Michael Chan /** 6657d5585595810044e7727d4303214f69ff2d77d4Michael Chan * Called to notify the client that this proxy object has been 6757d5585595810044e7727d4303214f69ff2d77d4Michael Chan * disconnected from the BluetoothHeadset service. Clients must not 6857d5585595810044e7727d4303214f69ff2d77d4Michael Chan * make IPC calls on the BluetoothHeadset service after this callback. 6957d5585595810044e7727d4303214f69ff2d77d4Michael Chan * This callback will currently only occur if the application hosting 7057d5585595810044e7727d4303214f69ff2d77d4Michael Chan * the BluetoothHeadset service, but may be called more often in future. 7157d5585595810044e7727d4303214f69ff2d77d4Michael Chan */ 72436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void onServiceDisconnected(); 73f2f3ceebbdf724e8904712a2a21cb0e677b7ea0dMichael Chan } 742aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 75436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final Context mContext; 76436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final LocalBluetoothAdapter mLocalAdapter; 77436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final CachedBluetoothDeviceManager mDeviceManager; 78436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final BluetoothEventManager mEventManager; 798c04b90cc95b16f8d7e99a61d8e2c940ed83b0c4Jaikumar Ganesh 80436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private A2dpProfile mA2dpProfile; 81436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private HeadsetProfile mHeadsetProfile; 82436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final HidProfile mHidProfile; 83436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private OppProfile mOppProfile; 84436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final PanProfile mPanProfile; 850654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta private final PbapServerProfile mPbapProfile; 86b45e3c8fe9c08851800a6afa362d975944c0cd46Swaminatha Balaji 87afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project /** 88436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Mapping from profile name, e.g. "HEADSET" to profile object. 89afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 90436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final Map<String, LocalBluetoothProfile> 91436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mProfileNameMap = new HashMap<String, LocalBluetoothProfile>(); 92afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 93436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby LocalBluetoothProfileManager(Context context, 94436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby LocalBluetoothAdapter adapter, 95436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby CachedBluetoothDeviceManager deviceManager, 96436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothEventManager eventManager) { 97436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mContext = context; 98a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin 99436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mLocalAdapter = adapter; 100436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mDeviceManager = deviceManager; 101436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mEventManager = eventManager; 102436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // pass this reference to adapter and event manager (circular dependency) 103436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mLocalAdapter.setProfileManager(this); 104436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mEventManager.setProfileManager(this); 105498d12bac0df509a4f74a4df8a8c69ec22583a1aJaikumar Ganesh 106436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby ParcelUuid[] uuids = adapter.getUuids(); 107a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin 108436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // uuids may be null if Bluetooth is turned off 109436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (uuids != null) { 110436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby updateLocalProfiles(uuids); 111a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin } 112792d2132e408ded2b2d56646ba263808dd51fc31Adam Powell 113436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Always add HID and PAN profiles 114436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mHidProfile = new HidProfile(context, mLocalAdapter); 115436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby addProfile(mHidProfile, HidProfile.NAME, 116436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED); 11732711b6752eb73324e1b10db975ac956888eda96Danica Chang 118436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mPanProfile = new PanProfile(context); 119c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby addPanProfile(mPanProfile, PanProfile.NAME, 120c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby BluetoothPan.ACTION_CONNECTION_STATE_CHANGED); 121c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby 1220654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta //Create PBAP server profile, but do not add it to list of profiles 1230654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta // as we do not need to monitor the profile as part of profile list 1240654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta mPbapProfile = new PbapServerProfile(context); 1250654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta 126436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.d(TAG, "LocalBluetoothProfileManager construction complete"); 127afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 128afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 129afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project /** 130436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Initialize or update the local profile objects. If a UUID was previously 131436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * present but has been removed, we print a warning but don't remove the 132436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * profile object as it might be referenced elsewhere, or the UUID might 133436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * come back and we don't want multiple copies of the profile objects. 134436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * @param uuids 135afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 136436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void updateLocalProfiles(ParcelUuid[] uuids) { 137436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // A2DP 138436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSource)) { 139436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (mA2dpProfile == null) { 140436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.d(TAG, "Adding local A2DP profile"); 1412ac143fff796ff1bd5b73484db17b6934c05f18eSwaminatha Balaji mA2dpProfile = new A2dpProfile(mContext, this); 142436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby addProfile(mA2dpProfile, A2dpProfile.NAME, 143436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); 144648bf5fd9e099cd677f7609afde831ac446deef0The Android Open Source Project } 145436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } else if (mA2dpProfile != null) { 146436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.w(TAG, "Warning: A2DP profile was previously added but the UUID is now missing."); 147436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 148436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby 149436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Headset / Handsfree 150436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) || 151436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP_AG)) { 152436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (mHeadsetProfile == null) { 153436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.d(TAG, "Adding local HEADSET profile"); 154436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mHeadsetProfile = new HeadsetProfile(mContext, mLocalAdapter, 155436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mDeviceManager, this); 156436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby addProfile(mHeadsetProfile, HeadsetProfile.NAME, 157436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); 1580bd445b974292dc3910b6bb85dcee7e7c378968fMichael Chan } 159436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } else if (mHeadsetProfile != null) { 160436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.w(TAG, "Warning: HEADSET profile was previously added but the UUID is now missing."); 161afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 1622aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 163436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // OPP 164436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) { 165436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (mOppProfile == null) { 166436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.d(TAG, "Adding local OPP profile"); 167436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mOppProfile = new OppProfile(); 168436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Note: no event handler for OPP, only name map. 169436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mProfileNameMap.put(OppProfile.NAME, mOppProfile); 170afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 171436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } else if (mOppProfile != null) { 172436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing."); 173afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 1746eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh mEventManager.registerProfileIntentReceiver(); 175afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 176436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // There is no local SDP record for HID and Settings app doesn't control PBAP 177afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 1782aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 179436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private final Collection<ServiceListener> mServiceListeners = 180436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby new ArrayList<ServiceListener>(); 1812aef1f3c814b1f8aa00aeefff35caf293c738702Michael Chan 182436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private void addProfile(LocalBluetoothProfile profile, 183436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby String profileName, String stateChangedAction) { 1846eb84ac6de9eeacc1e199d74310cf91f5a98daf2Jaikumar Ganesh mEventManager.addProfileHandler(stateChangedAction, new StateChangedHandler(profile)); 185436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mProfileNameMap.put(profileName, profile); 186436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 187afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 188c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby private void addPanProfile(LocalBluetoothProfile profile, 189c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby String profileName, String stateChangedAction) { 190c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby mEventManager.addProfileHandler(stateChangedAction, 191c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby new PanStateChangedHandler(profile)); 192c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby mProfileNameMap.put(profileName, profile); 193c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby } 194c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby 195436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby LocalBluetoothProfile getProfileByName(String name) { 196436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mProfileNameMap.get(name); 197436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 19848e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani 199436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Called from LocalBluetoothAdapter when state changes to ON 200436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void setBluetoothStateOn() { 201436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby ParcelUuid[] uuids = mLocalAdapter.getUuids(); 202436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (uuids != null) { 203436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby updateLocalProfiles(uuids); 20448e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani } 205436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mEventManager.readPairedDevices(); 206afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 207a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin 208a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin /** 209436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Generic handler for connection state change events for the specified profile. 210a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin */ 211436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private class StateChangedHandler implements BluetoothEventManager.Handler { 212c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby final LocalBluetoothProfile mProfile; 213a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin 214436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby StateChangedHandler(LocalBluetoothProfile profile) { 215436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mProfile = profile; 216a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin } 217a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin 218436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public void onReceive(Context context, Intent intent, BluetoothDevice device) { 219436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); 220436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (cachedDevice == null) { 221436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.w(TAG, "StateChangedHandler found new device: " + device); 222436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby cachedDevice = mDeviceManager.addDevice(mLocalAdapter, 223436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby LocalBluetoothProfileManager.this, device); 224a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin } 225436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0); 226436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0); 227436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (newState == BluetoothProfile.STATE_DISCONNECTED && 228436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby oldState == BluetoothProfile.STATE_CONNECTING) { 229436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.i(TAG, "Failed to connect " + mProfile + " device"); 230a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin } 23148e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani 232436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby cachedDevice.onProfileStateChanged(mProfile, newState); 233436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby cachedDevice.refresh(); 23448e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani } 235a41e2f94b792e44872be87f40fce182e6b39f4baYue Lixin } 236792d2132e408ded2b2d56646ba263808dd51fc31Adam Powell 237c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby /** State change handler for NAP and PANU profiles. */ 238c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby private class PanStateChangedHandler extends StateChangedHandler { 239c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby 240c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby PanStateChangedHandler(LocalBluetoothProfile profile) { 241c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby super(profile); 242c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby } 243c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby 244c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby @Override 245c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby public void onReceive(Context context, Intent intent, BluetoothDevice device) { 246c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby PanProfile panProfile = (PanProfile) mProfile; 247c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby int role = intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, 0); 248c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby panProfile.setLocalRole(device, role); 249c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby super.onReceive(context, intent, device); 250c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby } 251c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby } 252c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby 253436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // called from DockService 254436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void addServiceListener(ServiceListener l) { 255436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mServiceListeners.add(l); 256436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 257792d2132e408ded2b2d56646ba263808dd51fc31Adam Powell 258436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // called from DockService 259436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void removeServiceListener(ServiceListener l) { 260436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mServiceListeners.remove(l); 261436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 262792d2132e408ded2b2d56646ba263808dd51fc31Adam Powell 263436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // not synchronized: use only from UI thread! (TODO: verify) 264436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void callServiceConnectedListeners() { 265436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby for (ServiceListener l : mServiceListeners) { 266436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby l.onServiceConnected(); 267792d2132e408ded2b2d56646ba263808dd51fc31Adam Powell } 268436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 26948e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani 270436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // not synchronized: use only from UI thread! (TODO: verify) 271436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby void callServiceDisconnectedListeners() { 272436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby for (ServiceListener listener : mServiceListeners) { 273436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby listener.onServiceDisconnected(); 27448e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani } 275792d2132e408ded2b2d56646ba263808dd51fc31Adam Powell } 27632711b6752eb73324e1b10db975ac956888eda96Danica Chang 277436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // This is called by DockService, so check Headset and A2DP. 278436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby public synchronized boolean isManagerReady() { 279436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // Getting just the headset profile is fine for now. Will need to deal with A2DP 280436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby // and others if they aren't always in a ready state. 281436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby LocalBluetoothProfile profile = mHeadsetProfile; 282436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (profile != null) { 283436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return profile.isProfileReady(); 2849ad703cdb9a8d0972c123b041d18aa7bbeb391a4Jaikumar Ganesh } 285436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby profile = mA2dpProfile; 286436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (profile != null) { 287436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return profile.isProfileReady(); 2889ad703cdb9a8d0972c123b041d18aa7bbeb391a4Jaikumar Ganesh } 289436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return false; 290436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 2919ad703cdb9a8d0972c123b041d18aa7bbeb391a4Jaikumar Ganesh 292436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby A2dpProfile getA2dpProfile() { 293436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mA2dpProfile; 294436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 29532711b6752eb73324e1b10db975ac956888eda96Danica Chang 296436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby HeadsetProfile getHeadsetProfile() { 297436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return mHeadsetProfile; 298436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 29932711b6752eb73324e1b10db975ac956888eda96Danica Chang 3000654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta PbapServerProfile getPbapProfile(){ 3010654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta return mPbapProfile; 3020654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta } 3030654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta 3040654b71534411f4d93502f6ed8d8e864ef5b88efGanesh Ganapathi Batta 305436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby /** 306436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * Fill in a list of LocalBluetoothProfile objects that are supported by 307436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * the local device and the remote device. 308436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * 309436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * @param uuids of the remote device 310436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * @param localUuids UUIDs of the local device 311436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby * @param profiles The list of profiles to fill 312c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby * @param removedProfiles list of profiles that were removed 313436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby */ 314436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby synchronized void updateProfiles(ParcelUuid[] uuids, ParcelUuid[] localUuids, 315c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby Collection<LocalBluetoothProfile> profiles, 3166bce91bb9b14f82089f6ac90ca06f63a3aa3045cSyed Ibrahim M Collection<LocalBluetoothProfile> removedProfiles, 3176bce91bb9b14f82089f6ac90ca06f63a3aa3045cSyed Ibrahim M boolean isPanNapConnected) { 318c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby // Copy previous profile list into removedProfiles 319c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby removedProfiles.clear(); 320c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby removedProfiles.addAll(profiles); 321436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby profiles.clear(); 32232711b6752eb73324e1b10db975ac956888eda96Danica Chang 323436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (uuids == null) { 324436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby return; 32532711b6752eb73324e1b10db975ac956888eda96Danica Chang } 32632711b6752eb73324e1b10db975ac956888eda96Danica Chang 327436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (mHeadsetProfile != null) { 328436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if ((BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG) && 329c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP)) || 330c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby (BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) && 331c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) { 332c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby profiles.add(mHeadsetProfile); 333c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby removedProfiles.remove(mHeadsetProfile); 33432711b6752eb73324e1b10db975ac956888eda96Danica Chang } 33532711b6752eb73324e1b10db975ac956888eda96Danica Chang } 33632711b6752eb73324e1b10db975ac956888eda96Danica Chang 337436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) && 338436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mA2dpProfile != null) { 339436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby profiles.add(mA2dpProfile); 340c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby removedProfiles.remove(mA2dpProfile); 34132711b6752eb73324e1b10db975ac956888eda96Danica Chang } 34232711b6752eb73324e1b10db975ac956888eda96Danica Chang 343436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) && 344436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mOppProfile != null) { 345436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby profiles.add(mOppProfile); 346c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby removedProfiles.remove(mOppProfile); 34732711b6752eb73324e1b10db975ac956888eda96Danica Chang } 34832711b6752eb73324e1b10db975ac956888eda96Danica Chang 349436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hid) && 350436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby mHidProfile != null) { 351436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby profiles.add(mHidProfile); 352c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby removedProfiles.remove(mHidProfile); 35332711b6752eb73324e1b10db975ac956888eda96Danica Chang } 35448e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani 3556bce91bb9b14f82089f6ac90ca06f63a3aa3045cSyed Ibrahim M if(isPanNapConnected) 3566bce91bb9b14f82089f6ac90ca06f63a3aa3045cSyed Ibrahim M Log.d(TAG, "Valid PAN-NAP connection exists."); 3576bce91bb9b14f82089f6ac90ca06f63a3aa3045cSyed Ibrahim M if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP) && 3586bce91bb9b14f82089f6ac90ca06f63a3aa3045cSyed Ibrahim M mPanProfile != null) || isPanNapConnected) { 359436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby profiles.add(mPanProfile); 360c777ee29c856e1d1a2a61ccd799b6e18b50febdcJake Hamby removedProfiles.remove(mPanProfile); 36148e90002839e662eb1667471aebeb0483e9fb7dbAmith Yamasani } 36232711b6752eb73324e1b10db975ac956888eda96Danica Chang } 36300ec05985d6715daab7b15f105f0a9f3ada2ab83Swaminatha Balaji 364afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project} 365