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