LocalBluetoothProfileManager.java revision 7ce96b9e610de2782ec5f2af806e7bc0f90c8578
17ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk/*
27ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * Copyright (C) 2011 The Android Open Source Project
37ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk *
47ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * Licensed under the Apache License, Version 2.0 (the "License");
57ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * you may not use this file except in compliance with the License.
67ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * You may obtain a copy of the License at
77ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk *
87ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk *      http://www.apache.org/licenses/LICENSE-2.0
97ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk *
107ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * Unless required by applicable law or agreed to in writing, software
117ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * distributed under the License is distributed on an "AS IS" BASIS,
127ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * See the License for the specific language governing permissions and
147ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * limitations under the License.
157ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk */
167ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
177ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkpackage com.android.settingslib.bluetooth;
187ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
197ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.bluetooth.BluetoothA2dp;
207ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.bluetooth.BluetoothDevice;
217ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.bluetooth.BluetoothHeadset;
227ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.bluetooth.BluetoothMap;
237ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.bluetooth.BluetoothInputDevice;
247ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.bluetooth.BluetoothPan;
257ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.bluetooth.BluetoothPbap;
267ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.bluetooth.BluetoothProfile;
277ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.bluetooth.BluetoothUuid;
287ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.content.Context;
297ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.content.Intent;
307ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.os.ParcelUuid;
317ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.util.Log;
327ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.os.Handler;
337ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport android.os.Message;
347ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
357ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport java.util.ArrayList;
367ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport java.util.Collection;
377ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport java.util.HashMap;
387ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport java.util.Map;
397ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport java.util.Set;
407ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkimport java.util.List;
417ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
427ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk/**
437ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * LocalBluetoothProfileManager provides access to the LocalBluetoothProfile
447ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk * objects for the available Bluetooth profiles.
457ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk */
467ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monkpublic final class LocalBluetoothProfileManager {
477ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private static final String TAG = "LocalBluetoothProfileManager";
487ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private static final boolean DEBUG = Utils.D;
497ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    /** Singleton instance. */
507ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private static LocalBluetoothProfileManager sInstance;
517ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
527ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    /**
537ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     * An interface for notifying BluetoothHeadset IPC clients when they have
547ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     * been connected to the BluetoothHeadset service.
557ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     * Only used by com.android.settings.bluetooth.DockService.
567ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     */
577ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    public interface ServiceListener {
587ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        /**
597ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk         * Called to notify the client when this proxy object has been
607ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk         * connected to the BluetoothHeadset service. Clients must wait for
617ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk         * this callback before making IPC calls on the BluetoothHeadset
627ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk         * service.
637ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk         */
647ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        void onServiceConnected();
657ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
667ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        /**
677ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk         * Called to notify the client that this proxy object has been
687ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk         * disconnected from the BluetoothHeadset service. Clients must not
697ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk         * make IPC calls on the BluetoothHeadset service after this callback.
707ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk         * This callback will currently only occur if the application hosting
717ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk         * the BluetoothHeadset service, but may be called more often in future.
727ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk         */
737ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        void onServiceDisconnected();
747ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
757ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
767ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private final Context mContext;
777ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private final LocalBluetoothAdapter mLocalAdapter;
787ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private final CachedBluetoothDeviceManager mDeviceManager;
797ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private final BluetoothEventManager mEventManager;
807ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
817ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private A2dpProfile mA2dpProfile;
827ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private HeadsetProfile mHeadsetProfile;
837ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private MapProfile mMapProfile;
847ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private final HidProfile mHidProfile;
857ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private OppProfile mOppProfile;
867ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private final PanProfile mPanProfile;
877ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private final PbapServerProfile mPbapProfile;
887ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
897ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    /**
907ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     * Mapping from profile name, e.g. "HEADSET" to profile object.
917ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     */
927ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private final Map<String, LocalBluetoothProfile>
937ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            mProfileNameMap = new HashMap<String, LocalBluetoothProfile>();
947ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
957ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    LocalBluetoothProfileManager(Context context,
967ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            LocalBluetoothAdapter adapter,
977ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            CachedBluetoothDeviceManager deviceManager,
987ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            BluetoothEventManager eventManager) {
997ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mContext = context;
1007ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1017ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mLocalAdapter = adapter;
1027ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mDeviceManager = deviceManager;
1037ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mEventManager = eventManager;
1047ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        // pass this reference to adapter and event manager (circular dependency)
1057ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mLocalAdapter.setProfileManager(this);
1067ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mEventManager.setProfileManager(this);
1077ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1087ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        ParcelUuid[] uuids = adapter.getUuids();
1097ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1107ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        // uuids may be null if Bluetooth is turned off
1117ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if (uuids != null) {
1127ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            updateLocalProfiles(uuids);
1137ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
1147ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1157ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        // Always add HID and PAN profiles
1167ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mHidProfile = new HidProfile(context, mLocalAdapter, mDeviceManager, this);
1177ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        addProfile(mHidProfile, HidProfile.NAME,
1187ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
1197ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1207ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mPanProfile = new PanProfile(context);
1217ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        addPanProfile(mPanProfile, PanProfile.NAME,
1227ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
1237ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1247ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if(DEBUG) Log.d(TAG, "Adding local MAP profile");
1257ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mMapProfile = new MapProfile(mContext, mLocalAdapter,
1267ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                mDeviceManager, this);
1277ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        addProfile(mMapProfile, MapProfile.NAME,
1287ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
1297ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1307ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk       //Create PBAP server profile, but do not add it to list of profiles
1317ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk       // as we do not need to monitor the profile as part of profile list
1327ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mPbapProfile = new PbapServerProfile(context);
1337ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1347ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if (DEBUG) Log.d(TAG, "LocalBluetoothProfileManager construction complete");
1357ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
1367ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1377ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    /**
1387ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     * Initialize or update the local profile objects. If a UUID was previously
1397ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     * present but has been removed, we print a warning but don't remove the
1407ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     * profile object as it might be referenced elsewhere, or the UUID might
1417ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     * come back and we don't want multiple copies of the profile objects.
1427ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     * @param uuids
1437ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     */
1447ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    void updateLocalProfiles(ParcelUuid[] uuids) {
1457ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        // A2DP
1467ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSource)) {
1477ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            if (mA2dpProfile == null) {
1487ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                if(DEBUG) Log.d(TAG, "Adding local A2DP profile");
1497ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                mA2dpProfile = new A2dpProfile(mContext, mLocalAdapter, mDeviceManager, this);
1507ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                addProfile(mA2dpProfile, A2dpProfile.NAME,
1517ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                        BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
1527ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
1537ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        } else if (mA2dpProfile != null) {
1547ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            Log.w(TAG, "Warning: A2DP profile was previously added but the UUID is now missing.");
1557ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
1567ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1577ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        // Headset / Handsfree
1587ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) ||
1597ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP_AG)) {
1607ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            if (mHeadsetProfile == null) {
1617ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                if (DEBUG) Log.d(TAG, "Adding local HEADSET profile");
1627ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                mHeadsetProfile = new HeadsetProfile(mContext, mLocalAdapter,
1637ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                        mDeviceManager, this);
1647ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                addProfile(mHeadsetProfile, HeadsetProfile.NAME,
1657ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                        BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
1667ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
1677ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        } else if (mHeadsetProfile != null) {
1687ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            Log.w(TAG, "Warning: HEADSET profile was previously added but the UUID is now missing.");
1697ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
1707ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1717ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        // OPP
1727ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) {
1737ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            if (mOppProfile == null) {
1747ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                if(DEBUG) Log.d(TAG, "Adding local OPP profile");
1757ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                mOppProfile = new OppProfile();
1767ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                // Note: no event handler for OPP, only name map.
1777ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                mProfileNameMap.put(OppProfile.NAME, mOppProfile);
1787ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
1797ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        } else if (mOppProfile != null) {
1807ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing.");
1817ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
1827ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mEventManager.registerProfileIntentReceiver();
1837ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1847ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        // There is no local SDP record for HID and Settings app doesn't control PBAP
1857ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
1867ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1877ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private final Collection<ServiceListener> mServiceListeners =
1887ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            new ArrayList<ServiceListener>();
1897ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1907ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private void addProfile(LocalBluetoothProfile profile,
1917ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            String profileName, String stateChangedAction) {
1927ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mEventManager.addProfileHandler(stateChangedAction, new StateChangedHandler(profile));
1937ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mProfileNameMap.put(profileName, profile);
1947ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
1957ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
1967ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private void addPanProfile(LocalBluetoothProfile profile,
1977ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            String profileName, String stateChangedAction) {
1987ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mEventManager.addProfileHandler(stateChangedAction,
1997ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                new PanStateChangedHandler(profile));
2007ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mProfileNameMap.put(profileName, profile);
2017ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
2027ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2037ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    public LocalBluetoothProfile getProfileByName(String name) {
2047ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        return mProfileNameMap.get(name);
2057ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
2067ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2077ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    // Called from LocalBluetoothAdapter when state changes to ON
2087ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    void setBluetoothStateOn() {
2097ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        ParcelUuid[] uuids = mLocalAdapter.getUuids();
2107ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if (uuids != null) {
2117ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            updateLocalProfiles(uuids);
2127ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
2137ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mEventManager.readPairedDevices();
2147ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
2157ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2167ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    /**
2177ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     * Generic handler for connection state change events for the specified profile.
2187ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     */
2197ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private class StateChangedHandler implements BluetoothEventManager.Handler {
2207ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        final LocalBluetoothProfile mProfile;
2217ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2227ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        StateChangedHandler(LocalBluetoothProfile profile) {
2237ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            mProfile = profile;
2247ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
2257ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2267ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
2277ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
2287ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            if (cachedDevice == null) {
2297ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                Log.w(TAG, "StateChangedHandler found new device: " + device);
2307ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                cachedDevice = mDeviceManager.addDevice(mLocalAdapter,
2317ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                        LocalBluetoothProfileManager.this, device);
2327ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
2337ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
2347ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
2357ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            if (newState == BluetoothProfile.STATE_DISCONNECTED &&
2367ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                    oldState == BluetoothProfile.STATE_CONNECTING) {
2377ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                Log.i(TAG, "Failed to connect " + mProfile + " device");
2387ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
2397ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2407ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            cachedDevice.onProfileStateChanged(mProfile, newState);
2417ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            cachedDevice.refresh();
2427ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
2437ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
2447ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2457ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    /** State change handler for NAP and PANU profiles. */
2467ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    private class PanStateChangedHandler extends StateChangedHandler {
2477ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2487ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        PanStateChangedHandler(LocalBluetoothProfile profile) {
2497ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            super(profile);
2507ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
2517ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2527ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        @Override
2537ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
2547ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            PanProfile panProfile = (PanProfile) mProfile;
2557ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            int role = intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, 0);
2567ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            panProfile.setLocalRole(device, role);
2577ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            super.onReceive(context, intent, device);
2587ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
2597ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
2607ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2617ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    // called from DockService
2627ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    public void addServiceListener(ServiceListener l) {
2637ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mServiceListeners.add(l);
2647ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
2657ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2667ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    // called from DockService
2677ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    public void removeServiceListener(ServiceListener l) {
2687ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        mServiceListeners.remove(l);
2697ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
2707ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2717ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    // not synchronized: use only from UI thread! (TODO: verify)
2727ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    void callServiceConnectedListeners() {
2737ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        for (ServiceListener l : mServiceListeners) {
2747ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            l.onServiceConnected();
2757ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
2767ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
2777ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2787ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    // not synchronized: use only from UI thread! (TODO: verify)
2797ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    void callServiceDisconnectedListeners() {
2807ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        for (ServiceListener listener : mServiceListeners) {
2817ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            listener.onServiceDisconnected();
2827ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
2837ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
2847ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
2857ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    // This is called by DockService, so check Headset and A2DP.
2867ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    public synchronized boolean isManagerReady() {
2877ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        // Getting just the headset profile is fine for now. Will need to deal with A2DP
2887ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        // and others if they aren't always in a ready state.
2897ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        LocalBluetoothProfile profile = mHeadsetProfile;
2907ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if (profile != null) {
2917ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            return profile.isProfileReady();
2927ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
2937ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        profile = mA2dpProfile;
2947ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if (profile != null) {
2957ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            return profile.isProfileReady();
2967ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
2977ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        return false;
2987ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
2997ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3007ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    public A2dpProfile getA2dpProfile() {
3017ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        return mA2dpProfile;
3027ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
3037ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3047ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    public HeadsetProfile getHeadsetProfile() {
3057ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        return mHeadsetProfile;
3067ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
3077ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3087ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    public PbapServerProfile getPbapProfile(){
3097ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        return mPbapProfile;
3107ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
3117ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3127ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    public MapProfile getMapProfile(){
3137ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        return mMapProfile;
3147ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
3157ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3167ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    /**
3177ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     * Fill in a list of LocalBluetoothProfile objects that are supported by
3187ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     * the local device and the remote device.
3197ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     *
3207ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     * @param uuids of the remote device
3217ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     * @param localUuids UUIDs of the local device
3227ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     * @param profiles The list of profiles to fill
3237ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     * @param removedProfiles list of profiles that were removed
3247ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk     */
3257ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    synchronized void updateProfiles(ParcelUuid[] uuids, ParcelUuid[] localUuids,
3267ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            Collection<LocalBluetoothProfile> profiles,
3277ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            Collection<LocalBluetoothProfile> removedProfiles,
3287ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            boolean isPanNapConnected, BluetoothDevice device) {
3297ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        // Copy previous profile list into removedProfiles
3307ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        removedProfiles.clear();
3317ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        removedProfiles.addAll(profiles);
3327ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        profiles.clear();
3337ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3347ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if (uuids == null) {
3357ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            return;
3367ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
3377ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3387ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if (mHeadsetProfile != null) {
3397ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            if ((BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG) &&
3407ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                    BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP)) ||
3417ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                    (BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) &&
3427ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                            BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) {
3437ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                profiles.add(mHeadsetProfile);
3447ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk                removedProfiles.remove(mHeadsetProfile);
3457ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            }
3467ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
3477ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3487ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) &&
3497ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            mA2dpProfile != null) {
3507ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            profiles.add(mA2dpProfile);
3517ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            removedProfiles.remove(mA2dpProfile);
3527ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
3537ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3547ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) &&
3557ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            mOppProfile != null) {
3567ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            profiles.add(mOppProfile);
3577ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            removedProfiles.remove(mOppProfile);
3587ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
3597ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3607ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hid) ||
3617ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk             BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hogp)) &&
3627ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            mHidProfile != null) {
3637ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            profiles.add(mHidProfile);
3647ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            removedProfiles.remove(mHidProfile);
3657ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
3667ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3677ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if(isPanNapConnected)
3687ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            if(DEBUG) Log.d(TAG, "Valid PAN-NAP connection exists.");
3697ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP) &&
3707ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            mPanProfile != null) || isPanNapConnected) {
3717ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            profiles.add(mPanProfile);
3727ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            removedProfiles.remove(mPanProfile);
3737ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
3747ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3757ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        if ((mMapProfile != null) &&
3767ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            (mMapProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)) {
3777ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            profiles.add(mMapProfile);
3787ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            removedProfiles.remove(mMapProfile);
3797ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk            mMapProfile.setPreferred(device, true);
3807ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk        }
3817ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk    }
3827ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk
3837ce96b9e610de2782ec5f2af806e7bc0f90c8578Jason Monk}
384