1fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie/*
2fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie * Copyright (C) 2008 The Android Open Source Project
3fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie *
4fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie * Licensed under the Apache License, Version 2.0 (the "License");
5fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie * you may not use this file except in compliance with the License.
6fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie * You may obtain a copy of the License at
7fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie *
8fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie *      http://www.apache.org/licenses/LICENSE-2.0
9fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie *
10fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie * Unless required by applicable law or agreed to in writing, software
11fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie * distributed under the License is distributed on an "AS IS" BASIS,
12fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie * See the License for the specific language governing permissions and
14fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie * limitations under the License.
15fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie */
16fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
17fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xiepackage android.bluetooth;
18fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
19fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xieimport android.content.ComponentName;
20fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xieimport android.content.Context;
21fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xieimport android.content.Intent;
22fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xieimport android.content.ServiceConnection;
230146463d70355592da85c3605aaaef4cf0b7335eJack Heimport android.os.Binder;
240146463d70355592da85c3605aaaef4cf0b7335eJack Heimport android.os.IBinder;
250146463d70355592da85c3605aaaef4cf0b7335eJack Heimport android.os.RemoteException;
26fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xieimport android.util.Log;
27fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
280146463d70355592da85c3605aaaef4cf0b7335eJack Heimport java.util.ArrayList;
290146463d70355592da85c3605aaaef4cf0b7335eJack Heimport java.util.List;
300146463d70355592da85c3605aaaef4cf0b7335eJack He
31fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie/**
32fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie * This class provides the APIs to control the Bluetooth MAP
33fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie * Profile.
34fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie *@hide
35fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie */
360d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulzpublic final class BluetoothMap implements BluetoothProfile {
37fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
38fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    private static final String TAG = "BluetoothMap";
39fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    private static final boolean DBG = true;
40fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    private static final boolean VDBG = false;
41fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
420d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    public static final String ACTION_CONNECTION_STATE_CHANGED =
430d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
44fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
450146463d70355592da85c3605aaaef4cf0b7335eJack He    private volatile IBluetoothMap mService;
46fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    private final Context mContext;
47fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    private ServiceListener mServiceListener;
48fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    private BluetoothAdapter mAdapter;
49fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
50fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /** There was an error trying to obtain the state */
51fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public static final int STATE_ERROR        = -1;
52fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
53fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public static final int RESULT_FAILURE = 0;
54fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public static final int RESULT_SUCCESS = 1;
55fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /** Connection canceled before completion. */
56fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public static final int RESULT_CANCELED = 2;
57fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
58fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
59fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            new IBluetoothStateChangeCallback.Stub() {
60fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                public void onBluetoothStateChange(boolean up) {
61fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
62fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    if (!up) {
63fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                        if (VDBG) Log.d(TAG,"Unbinding service...");
64fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                        synchronized (mConnection) {
65fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                            try {
66fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                                mService = null;
67fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                                mContext.unbindService(mConnection);
68fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                            } catch (Exception re) {
69fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                                Log.e(TAG,"",re);
70fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                            }
71fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                        }
72fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    } else {
73fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                        synchronized (mConnection) {
74fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                            try {
75fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                                if (mService == null) {
76fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                                    if (VDBG) Log.d(TAG,"Binding service...");
770d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                                    doBind();
78fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                                }
79fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                            } catch (Exception re) {
80fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                                Log.e(TAG,"",re);
81fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                            }
82fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                        }
83fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    }
84fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                }
85fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        };
86fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
87fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /**
88fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * Create a BluetoothMap proxy object.
89fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     */
900d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    /*package*/ BluetoothMap(Context context, ServiceListener l) {
910d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (DBG) Log.d(TAG, "Create BluetoothMap proxy object");
92fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        mContext = context;
93fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        mServiceListener = l;
94fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        mAdapter = BluetoothAdapter.getDefaultAdapter();
95fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        IBluetoothManager mgr = mAdapter.getBluetoothManager();
96fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        if (mgr != null) {
97fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            try {
98fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
99fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            } catch (RemoteException e) {
100fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                Log.e(TAG,"",e);
101fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            }
102fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
1030d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        doBind();
1040d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
1050d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
1060d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    boolean doBind() {
1070d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        Intent intent = new Intent(IBluetoothMap.class.getName());
1080d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
1090d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        intent.setComponent(comp);
110466ce96da8ca7ea8c97e716b02a7d55007179aa1Dianne Hackborn        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
111466ce96da8ca7ea8c97e716b02a7d55007179aa1Dianne Hackborn                android.os.Process.myUserHandle())) {
1120d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            Log.e(TAG, "Could not bind to Bluetooth MAP Service with " + intent);
1130d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            return false;
114fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
1150d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        return true;
116fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
117fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
118fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    protected void finalize() throws Throwable {
119fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        try {
120fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            close();
121fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        } finally {
122fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            super.finalize();
123fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
124fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
125fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
126fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /**
127fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * Close the connection to the backing service.
128fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * Other public functions of BluetoothMap will return default error
129fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * results once close() has been called. Multiple invocations of close()
130fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * are ok.
131fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     */
132fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public synchronized void close() {
133fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        IBluetoothManager mgr = mAdapter.getBluetoothManager();
134fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        if (mgr != null) {
135fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            try {
136fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
137fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            } catch (Exception e) {
138fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                Log.e(TAG,"",e);
139fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            }
140fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
141fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
142fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        synchronized (mConnection) {
143fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            if (mService != null) {
144fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                try {
145fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    mService = null;
146fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    mContext.unbindService(mConnection);
147fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                } catch (Exception re) {
148fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    Log.e(TAG,"",re);
149fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                }
150fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            }
151fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
152fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        mServiceListener = null;
153fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
154fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
155fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /**
156fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * Get the current state of the BluetoothMap service.
157fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * @return One of the STATE_ return codes, or STATE_ERROR if this proxy
158fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     *         object is currently not connected to the Map service.
159fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     */
160fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public int getState() {
161fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        if (VDBG) log("getState()");
1620146463d70355592da85c3605aaaef4cf0b7335eJack He        final IBluetoothMap service = mService;
1630146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service != null) {
164fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            try {
1650146463d70355592da85c3605aaaef4cf0b7335eJack He                return service.getState();
1660146463d70355592da85c3605aaaef4cf0b7335eJack He            } catch (RemoteException e) {
1670146463d70355592da85c3605aaaef4cf0b7335eJack He                Log.e(TAG, e.toString());
1680146463d70355592da85c3605aaaef4cf0b7335eJack He            }
169fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        } else {
170fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            Log.w(TAG, "Proxy not attached to service");
171fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            if (DBG) log(Log.getStackTraceString(new Throwable()));
172fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
173fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        return BluetoothMap.STATE_ERROR;
174fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
175fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
176fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /**
177fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * Get the currently connected remote Bluetooth device (PCE).
178fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * @return The remote Bluetooth device, or null if not in connected or
179fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     *         connecting state, or if this proxy object is not connected to
180fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     *         the Map service.
181fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     */
182fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public BluetoothDevice getClient() {
183fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        if (VDBG) log("getClient()");
1840146463d70355592da85c3605aaaef4cf0b7335eJack He        final IBluetoothMap service = mService;
1850146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service != null) {
186fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            try {
1870146463d70355592da85c3605aaaef4cf0b7335eJack He                return service.getClient();
1880146463d70355592da85c3605aaaef4cf0b7335eJack He            } catch (RemoteException e) {
1890146463d70355592da85c3605aaaef4cf0b7335eJack He                Log.e(TAG, e.toString());
1900146463d70355592da85c3605aaaef4cf0b7335eJack He            }
191fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        } else {
192fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            Log.w(TAG, "Proxy not attached to service");
193fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            if (DBG) log(Log.getStackTraceString(new Throwable()));
194fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
195fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        return null;
196fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
197fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
198fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /**
1990d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Returns true if the specified Bluetooth device is connected.
2000d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Returns false if not connected, or if this proxy object is not
2010d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * currently connected to the Map service.
202fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     */
203fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public boolean isConnected(BluetoothDevice device) {
204fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        if (VDBG) log("isConnected(" + device + ")");
2050146463d70355592da85c3605aaaef4cf0b7335eJack He        final IBluetoothMap service = mService;
2060146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service != null) {
207fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            try {
2080146463d70355592da85c3605aaaef4cf0b7335eJack He                return service.isConnected(device);
2090146463d70355592da85c3605aaaef4cf0b7335eJack He            } catch (RemoteException e) {
2100146463d70355592da85c3605aaaef4cf0b7335eJack He                Log.e(TAG, e.toString());
2110146463d70355592da85c3605aaaef4cf0b7335eJack He            }
212fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        } else {
213fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            Log.w(TAG, "Proxy not attached to service");
214fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            if (DBG) log(Log.getStackTraceString(new Throwable()));
215fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
216fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        return false;
217fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
218fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
219fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /**
2200d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Initiate connection. Initiation of outgoing connections is not
2210d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * supported for MAP server.
222fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     */
2230d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    public boolean connect(BluetoothDevice device) {
2240d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (DBG) log("connect(" + device + ")" + "not supported for MAPS");
2250d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        return false;
2260d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
2270d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
2280d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    /**
2290d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Initiate disconnect.
2300d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *
2310d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @param device Remote Bluetooth Device
2320d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @return false on error,
2330d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *               true otherwise
2340d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     */
2350d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    public boolean disconnect(BluetoothDevice device) {
2360d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (DBG) log("disconnect(" + device + ")");
2370146463d70355592da85c3605aaaef4cf0b7335eJack He        final IBluetoothMap service = mService;
2380146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service != null && isEnabled() && isValidDevice(device)) {
239fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            try {
2400146463d70355592da85c3605aaaef4cf0b7335eJack He                return service.disconnect(device);
2410d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            } catch (RemoteException e) {
2420d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz              Log.e(TAG, Log.getStackTraceString(new Throwable()));
2430d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz              return false;
2440d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            }
245fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
2460146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service == null) Log.w(TAG, "Proxy not attached to service");
247fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        return false;
248fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
249fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
250fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /**
251fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * Check class bits for possible Map support.
252fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * This is a simple heuristic that tries to guess if a device with the
253fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * given class bits might support Map. It is not accurate for all
254fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * devices. It tries to err on the side of false positives.
255fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * @return True if this device might support Map.
256fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     */
257fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public static boolean doesClassMatchSink(BluetoothClass btClass) {
258fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        // TODO optimize the rule
259fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        switch (btClass.getDeviceClass()) {
260fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        case BluetoothClass.Device.COMPUTER_DESKTOP:
261fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        case BluetoothClass.Device.COMPUTER_LAPTOP:
262fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        case BluetoothClass.Device.COMPUTER_SERVER:
263fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        case BluetoothClass.Device.COMPUTER_UNCATEGORIZED:
264fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            return true;
265fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        default:
266fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            return false;
267fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
268fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
269fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
2700d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    /**
2710d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Get the list of connected devices. Currently at most one.
2720d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *
2730d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @return list of connected devices
2740d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     */
2750d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    public List<BluetoothDevice> getConnectedDevices() {
2760d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (DBG) log("getConnectedDevices()");
2770146463d70355592da85c3605aaaef4cf0b7335eJack He        final IBluetoothMap service = mService;
2780146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service != null && isEnabled()) {
2790d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            try {
2800146463d70355592da85c3605aaaef4cf0b7335eJack He                return service.getConnectedDevices();
2810d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            } catch (RemoteException e) {
2820d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                Log.e(TAG, Log.getStackTraceString(new Throwable()));
2830d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                return new ArrayList<BluetoothDevice>();
2840d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            }
2850d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        }
2860146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service == null) Log.w(TAG, "Proxy not attached to service");
2870d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        return new ArrayList<BluetoothDevice>();
2880d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
2890d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
2900d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    /**
2910d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Get the list of devices matching specified states. Currently at most one.
2920d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *
2930d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @return list of matching devices
2940d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     */
2950d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
2960d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (DBG) log("getDevicesMatchingStates()");
2970146463d70355592da85c3605aaaef4cf0b7335eJack He        final IBluetoothMap service = mService;
2980146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service != null && isEnabled()) {
2990d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            try {
3000146463d70355592da85c3605aaaef4cf0b7335eJack He                return service.getDevicesMatchingConnectionStates(states);
3010d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            } catch (RemoteException e) {
3020d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                Log.e(TAG, Log.getStackTraceString(new Throwable()));
3030d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                return new ArrayList<BluetoothDevice>();
3040d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            }
3050d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        }
3060146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service == null) Log.w(TAG, "Proxy not attached to service");
3070d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        return new ArrayList<BluetoothDevice>();
3080d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
3090d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
3100d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    /**
3110d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Get connection state of device
3120d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *
3130d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @return device connection state
3140d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     */
3150d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    public int getConnectionState(BluetoothDevice device) {
3160d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (DBG) log("getConnectionState(" + device + ")");
3170146463d70355592da85c3605aaaef4cf0b7335eJack He        final IBluetoothMap service = mService;
3180146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service != null && isEnabled() && isValidDevice(device)) {
3190d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            try {
3200146463d70355592da85c3605aaaef4cf0b7335eJack He                return service.getConnectionState(device);
3210d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            } catch (RemoteException e) {
3220d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                Log.e(TAG, Log.getStackTraceString(new Throwable()));
3230d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                return BluetoothProfile.STATE_DISCONNECTED;
3240d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            }
3250d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        }
3260146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service == null) Log.w(TAG, "Proxy not attached to service");
3270d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        return BluetoothProfile.STATE_DISCONNECTED;
3280d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
3290d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
3300d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    /**
3310d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Set priority of the profile
3320d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *
3330d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * <p> The device should already be paired.
3340d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *  Priority can be one of {@link #PRIORITY_ON} or
3350d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * {@link #PRIORITY_OFF},
3360d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *
3370d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @param device Paired bluetooth device
3380d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @param priority
3390d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @return true if priority is set, false on error
3400d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     */
3410d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    public boolean setPriority(BluetoothDevice device, int priority) {
3420d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (DBG) log("setPriority(" + device + ", " + priority + ")");
3430146463d70355592da85c3605aaaef4cf0b7335eJack He        final IBluetoothMap service = mService;
3440146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service != null && isEnabled() && isValidDevice(device)) {
3450146463d70355592da85c3605aaaef4cf0b7335eJack He            if (priority != BluetoothProfile.PRIORITY_OFF
3460146463d70355592da85c3605aaaef4cf0b7335eJack He                    && priority != BluetoothProfile.PRIORITY_ON) {
3470146463d70355592da85c3605aaaef4cf0b7335eJack He                return false;
3480d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            }
3490d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            try {
3500146463d70355592da85c3605aaaef4cf0b7335eJack He                return service.setPriority(device, priority);
3510d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            } catch (RemoteException e) {
3520d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                Log.e(TAG, Log.getStackTraceString(new Throwable()));
3530d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                return false;
3540d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            }
3550d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        }
3560146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service == null) Log.w(TAG, "Proxy not attached to service");
3570d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        return false;
3580d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
3590d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
3600d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    /**
3610d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Get the priority of the profile.
3620d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *
3630d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * <p> The priority can be any of:
3640d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
3650d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
3660d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *
3670d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @param device Bluetooth device
3680d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @return priority of the device
3690d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     */
3700d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    public int getPriority(BluetoothDevice device) {
3710d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (VDBG) log("getPriority(" + device + ")");
3720146463d70355592da85c3605aaaef4cf0b7335eJack He        final IBluetoothMap service = mService;
3730146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service != null && isEnabled() && isValidDevice(device)) {
3740d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            try {
3750146463d70355592da85c3605aaaef4cf0b7335eJack He                return service.getPriority(device);
3760d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            } catch (RemoteException e) {
3770d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                Log.e(TAG, Log.getStackTraceString(new Throwable()));
3780d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                return PRIORITY_OFF;
3790d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            }
3800d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        }
3810146463d70355592da85c3605aaaef4cf0b7335eJack He        if (service == null) Log.w(TAG, "Proxy not attached to service");
3820d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        return PRIORITY_OFF;
3830d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
3840d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
3859b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie    private final ServiceConnection mConnection = new ServiceConnection() {
386fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        public void onServiceConnected(ComponentName className, IBinder service) {
387fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            if (DBG) log("Proxy object connected");
3880a17db1cc5942ea000ca87bb72853de57a15ec64Jeff Sharkey            mService = IBluetoothMap.Stub.asInterface(Binder.allowBlocking(service));
389fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            if (mServiceListener != null) {
3900d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                mServiceListener.onServiceConnected(BluetoothProfile.MAP, BluetoothMap.this);
391fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            }
392fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
393fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        public void onServiceDisconnected(ComponentName className) {
394fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            if (DBG) log("Proxy object disconnected");
395fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            mService = null;
396fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            if (mServiceListener != null) {
3970d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                mServiceListener.onServiceDisconnected(BluetoothProfile.MAP);
398fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            }
399fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
400fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    };
401fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
402fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    private static void log(String msg) {
403fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        Log.d(TAG, msg);
404fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
4050d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
4060d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz   private boolean isEnabled() {
4070d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
4080d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
4090d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        log("Bluetooth is Not enabled");
4100d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        return false;
4110d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
4120146463d70355592da85c3605aaaef4cf0b7335eJack He    private static boolean isValidDevice(BluetoothDevice device) {
4130146463d70355592da85c3605aaaef4cf0b7335eJack He        return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
4140d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
4150d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
416fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie}
417