Files
app_Settings/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java
Ganesh Ganapathi Batta 0654b71534 Remove Profile Auto connection specific logic
Remove  profile auto connection specific logic as it is not implemented in
Bluetooth app
Disconnect PBAP server connection  when user initiates device level disconnection

Change-Id: I381ed96f6b57f414bbaccd694f55d2b992e330a4
2012-08-06 23:27:27 -07:00

365 lines
14 KiB
Java
Executable File

/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.bluetooth;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothInputDevice;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothPbap;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
import android.content.Intent;
import android.os.ParcelUuid;
import android.util.Log;
import android.os.Handler;
import android.os.Message;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.List;
/**
* LocalBluetoothProfileManager provides access to the LocalBluetoothProfile
* objects for the available Bluetooth profiles.
*/
final class LocalBluetoothProfileManager {
private static final String TAG = "LocalBluetoothProfileManager";
/** Singleton instance. */
private static LocalBluetoothProfileManager sInstance;
/**
* An interface for notifying BluetoothHeadset IPC clients when they have
* been connected to the BluetoothHeadset service.
* Only used by {@link DockService}.
*/
public interface ServiceListener {
/**
* Called to notify the client when this proxy object has been
* connected to the BluetoothHeadset service. Clients must wait for
* this callback before making IPC calls on the BluetoothHeadset
* service.
*/
void onServiceConnected();
/**
* Called to notify the client that this proxy object has been
* disconnected from the BluetoothHeadset service. Clients must not
* make IPC calls on the BluetoothHeadset service after this callback.
* This callback will currently only occur if the application hosting
* the BluetoothHeadset service, but may be called more often in future.
*/
void onServiceDisconnected();
}
private final Context mContext;
private final LocalBluetoothAdapter mLocalAdapter;
private final CachedBluetoothDeviceManager mDeviceManager;
private final BluetoothEventManager mEventManager;
private A2dpProfile mA2dpProfile;
private HeadsetProfile mHeadsetProfile;
private final HidProfile mHidProfile;
private OppProfile mOppProfile;
private final PanProfile mPanProfile;
private final PbapServerProfile mPbapProfile;
/**
* Mapping from profile name, e.g. "HEADSET" to profile object.
*/
private final Map<String, LocalBluetoothProfile>
mProfileNameMap = new HashMap<String, LocalBluetoothProfile>();
LocalBluetoothProfileManager(Context context,
LocalBluetoothAdapter adapter,
CachedBluetoothDeviceManager deviceManager,
BluetoothEventManager eventManager) {
mContext = context;
mLocalAdapter = adapter;
mDeviceManager = deviceManager;
mEventManager = eventManager;
// pass this reference to adapter and event manager (circular dependency)
mLocalAdapter.setProfileManager(this);
mEventManager.setProfileManager(this);
ParcelUuid[] uuids = adapter.getUuids();
// uuids may be null if Bluetooth is turned off
if (uuids != null) {
updateLocalProfiles(uuids);
}
// Always add HID and PAN profiles
mHidProfile = new HidProfile(context, mLocalAdapter);
addProfile(mHidProfile, HidProfile.NAME,
BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
mPanProfile = new PanProfile(context);
addPanProfile(mPanProfile, PanProfile.NAME,
BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
//Create PBAP server profile, but do not add it to list of profiles
// as we do not need to monitor the profile as part of profile list
mPbapProfile = new PbapServerProfile(context);
Log.d(TAG, "LocalBluetoothProfileManager construction complete");
}
/**
* Initialize or update the local profile objects. If a UUID was previously
* present but has been removed, we print a warning but don't remove the
* profile object as it might be referenced elsewhere, or the UUID might
* come back and we don't want multiple copies of the profile objects.
* @param uuids
*/
void updateLocalProfiles(ParcelUuid[] uuids) {
// A2DP
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSource)) {
if (mA2dpProfile == null) {
Log.d(TAG, "Adding local A2DP profile");
mA2dpProfile = new A2dpProfile(mContext, this);
addProfile(mA2dpProfile, A2dpProfile.NAME,
BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
}
} else if (mA2dpProfile != null) {
Log.w(TAG, "Warning: A2DP profile was previously added but the UUID is now missing.");
}
// Headset / Handsfree
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) ||
BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP_AG)) {
if (mHeadsetProfile == null) {
Log.d(TAG, "Adding local HEADSET profile");
mHeadsetProfile = new HeadsetProfile(mContext, mLocalAdapter,
mDeviceManager, this);
addProfile(mHeadsetProfile, HeadsetProfile.NAME,
BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
}
} else if (mHeadsetProfile != null) {
Log.w(TAG, "Warning: HEADSET profile was previously added but the UUID is now missing.");
}
// OPP
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) {
if (mOppProfile == null) {
Log.d(TAG, "Adding local OPP profile");
mOppProfile = new OppProfile();
// Note: no event handler for OPP, only name map.
mProfileNameMap.put(OppProfile.NAME, mOppProfile);
}
} else if (mOppProfile != null) {
Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing.");
}
mEventManager.registerProfileIntentReceiver();
// There is no local SDP record for HID and Settings app doesn't control PBAP
}
private final Collection<ServiceListener> mServiceListeners =
new ArrayList<ServiceListener>();
private void addProfile(LocalBluetoothProfile profile,
String profileName, String stateChangedAction) {
mEventManager.addProfileHandler(stateChangedAction, new StateChangedHandler(profile));
mProfileNameMap.put(profileName, profile);
}
private void addPanProfile(LocalBluetoothProfile profile,
String profileName, String stateChangedAction) {
mEventManager.addProfileHandler(stateChangedAction,
new PanStateChangedHandler(profile));
mProfileNameMap.put(profileName, profile);
}
LocalBluetoothProfile getProfileByName(String name) {
return mProfileNameMap.get(name);
}
// Called from LocalBluetoothAdapter when state changes to ON
void setBluetoothStateOn() {
ParcelUuid[] uuids = mLocalAdapter.getUuids();
if (uuids != null) {
updateLocalProfiles(uuids);
}
mEventManager.readPairedDevices();
}
/**
* Generic handler for connection state change events for the specified profile.
*/
private class StateChangedHandler implements BluetoothEventManager.Handler {
final LocalBluetoothProfile mProfile;
StateChangedHandler(LocalBluetoothProfile profile) {
mProfile = profile;
}
public void onReceive(Context context, Intent intent, BluetoothDevice device) {
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
if (cachedDevice == null) {
Log.w(TAG, "StateChangedHandler found new device: " + device);
cachedDevice = mDeviceManager.addDevice(mLocalAdapter,
LocalBluetoothProfileManager.this, device);
}
int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
if (newState == BluetoothProfile.STATE_DISCONNECTED &&
oldState == BluetoothProfile.STATE_CONNECTING) {
Log.i(TAG, "Failed to connect " + mProfile + " device");
}
cachedDevice.onProfileStateChanged(mProfile, newState);
cachedDevice.refresh();
}
}
/** State change handler for NAP and PANU profiles. */
private class PanStateChangedHandler extends StateChangedHandler {
PanStateChangedHandler(LocalBluetoothProfile profile) {
super(profile);
}
@Override
public void onReceive(Context context, Intent intent, BluetoothDevice device) {
PanProfile panProfile = (PanProfile) mProfile;
int role = intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, 0);
panProfile.setLocalRole(device, role);
super.onReceive(context, intent, device);
}
}
// called from DockService
void addServiceListener(ServiceListener l) {
mServiceListeners.add(l);
}
// called from DockService
void removeServiceListener(ServiceListener l) {
mServiceListeners.remove(l);
}
// not synchronized: use only from UI thread! (TODO: verify)
void callServiceConnectedListeners() {
for (ServiceListener l : mServiceListeners) {
l.onServiceConnected();
}
}
// not synchronized: use only from UI thread! (TODO: verify)
void callServiceDisconnectedListeners() {
for (ServiceListener listener : mServiceListeners) {
listener.onServiceDisconnected();
}
}
// This is called by DockService, so check Headset and A2DP.
public synchronized boolean isManagerReady() {
// Getting just the headset profile is fine for now. Will need to deal with A2DP
// and others if they aren't always in a ready state.
LocalBluetoothProfile profile = mHeadsetProfile;
if (profile != null) {
return profile.isProfileReady();
}
profile = mA2dpProfile;
if (profile != null) {
return profile.isProfileReady();
}
return false;
}
A2dpProfile getA2dpProfile() {
return mA2dpProfile;
}
HeadsetProfile getHeadsetProfile() {
return mHeadsetProfile;
}
PbapServerProfile getPbapProfile(){
return mPbapProfile;
}
/**
* Fill in a list of LocalBluetoothProfile objects that are supported by
* the local device and the remote device.
*
* @param uuids of the remote device
* @param localUuids UUIDs of the local device
* @param profiles The list of profiles to fill
* @param removedProfiles list of profiles that were removed
*/
synchronized void updateProfiles(ParcelUuid[] uuids, ParcelUuid[] localUuids,
Collection<LocalBluetoothProfile> profiles,
Collection<LocalBluetoothProfile> removedProfiles,
boolean isPanNapConnected) {
// Copy previous profile list into removedProfiles
removedProfiles.clear();
removedProfiles.addAll(profiles);
profiles.clear();
if (uuids == null) {
return;
}
if (mHeadsetProfile != null) {
if ((BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG) &&
BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP)) ||
(BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) &&
BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) {
profiles.add(mHeadsetProfile);
removedProfiles.remove(mHeadsetProfile);
}
}
if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) &&
mA2dpProfile != null) {
profiles.add(mA2dpProfile);
removedProfiles.remove(mA2dpProfile);
}
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) &&
mOppProfile != null) {
profiles.add(mOppProfile);
removedProfiles.remove(mOppProfile);
}
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hid) &&
mHidProfile != null) {
profiles.add(mHidProfile);
removedProfiles.remove(mHidProfile);
}
if(isPanNapConnected)
Log.d(TAG, "Valid PAN-NAP connection exists.");
if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP) &&
mPanProfile != null) || isPanNapConnected) {
profiles.add(mPanProfile);
removedProfiles.remove(mPanProfile);
}
}
}