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
190d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulzimport java.util.List;
200d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulzimport java.util.ArrayList;
21fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xieimport android.content.ComponentName;
22fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xieimport android.content.Context;
23fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xieimport android.content.Intent;
24fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xieimport android.content.ServiceConnection;
25466ce96da8ca7ea8c97e716b02a7d55007179aa1Dianne Hackbornimport android.os.*;
26fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xieimport android.util.Log;
27fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
28fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie/**
29fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie * This class provides the APIs to control the Bluetooth MAP
30fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie * Profile.
31fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie *@hide
32fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie */
330d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulzpublic final class BluetoothMap implements BluetoothProfile {
34fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
35fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    private static final String TAG = "BluetoothMap";
36fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    private static final boolean DBG = true;
37fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    private static final boolean VDBG = false;
38fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
390d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    public static final String ACTION_CONNECTION_STATE_CHANGED =
400d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
41fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
42fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    private IBluetoothMap mService;
43fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    private final Context mContext;
44fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    private ServiceListener mServiceListener;
45fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    private BluetoothAdapter mAdapter;
46fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
47fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /** There was an error trying to obtain the state */
48fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public static final int STATE_ERROR        = -1;
49fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
50fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public static final int RESULT_FAILURE = 0;
51fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public static final int RESULT_SUCCESS = 1;
52fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /** Connection canceled before completion. */
53fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public static final int RESULT_CANCELED = 2;
54fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
55fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
56fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            new IBluetoothStateChangeCallback.Stub() {
57fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                public void onBluetoothStateChange(boolean up) {
58fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
59fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    if (!up) {
60fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                        if (VDBG) Log.d(TAG,"Unbinding service...");
61fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                        synchronized (mConnection) {
62fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                            try {
63fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                                mService = null;
64fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                                mContext.unbindService(mConnection);
65fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                            } catch (Exception re) {
66fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                                Log.e(TAG,"",re);
67fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                            }
68fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                        }
69fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    } else {
70fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                        synchronized (mConnection) {
71fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                            try {
72fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                                if (mService == null) {
73fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                                    if (VDBG) Log.d(TAG,"Binding service...");
740d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                                    doBind();
75fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                                }
76fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                            } catch (Exception re) {
77fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                                Log.e(TAG,"",re);
78fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                            }
79fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                        }
80fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    }
81fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                }
82fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        };
83fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
84fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /**
85fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * Create a BluetoothMap proxy object.
86fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     */
870d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    /*package*/ BluetoothMap(Context context, ServiceListener l) {
880d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (DBG) Log.d(TAG, "Create BluetoothMap proxy object");
89fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        mContext = context;
90fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        mServiceListener = l;
91fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        mAdapter = BluetoothAdapter.getDefaultAdapter();
92fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        IBluetoothManager mgr = mAdapter.getBluetoothManager();
93fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        if (mgr != null) {
94fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            try {
95fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
96fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            } catch (RemoteException e) {
97fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                Log.e(TAG,"",e);
98fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            }
99fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
1000d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        doBind();
1010d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
1020d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
1030d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    boolean doBind() {
1040d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        Intent intent = new Intent(IBluetoothMap.class.getName());
1050d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
1060d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        intent.setComponent(comp);
107466ce96da8ca7ea8c97e716b02a7d55007179aa1Dianne Hackborn        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
108466ce96da8ca7ea8c97e716b02a7d55007179aa1Dianne Hackborn                android.os.Process.myUserHandle())) {
1090d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            Log.e(TAG, "Could not bind to Bluetooth MAP Service with " + intent);
1100d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            return false;
111fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
1120d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        return true;
113fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
114fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
115fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    protected void finalize() throws Throwable {
116fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        try {
117fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            close();
118fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        } finally {
119fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            super.finalize();
120fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
121fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
122fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
123fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /**
124fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * Close the connection to the backing service.
125fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * Other public functions of BluetoothMap will return default error
126fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * results once close() has been called. Multiple invocations of close()
127fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * are ok.
128fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     */
129fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public synchronized void close() {
130fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        IBluetoothManager mgr = mAdapter.getBluetoothManager();
131fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        if (mgr != null) {
132fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            try {
133fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
134fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            } catch (Exception e) {
135fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                Log.e(TAG,"",e);
136fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            }
137fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
138fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
139fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        synchronized (mConnection) {
140fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            if (mService != null) {
141fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                try {
142fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    mService = null;
143fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    mContext.unbindService(mConnection);
144fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                } catch (Exception re) {
145fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    Log.e(TAG,"",re);
146fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                }
147fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            }
148fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
149fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        mServiceListener = null;
150fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
151fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
152fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /**
153fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * Get the current state of the BluetoothMap service.
154fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * @return One of the STATE_ return codes, or STATE_ERROR if this proxy
155fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     *         object is currently not connected to the Map service.
156fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     */
157fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public int getState() {
158fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        if (VDBG) log("getState()");
159fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        if (mService != null) {
160fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            try {
161fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                return mService.getState();
162fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            } catch (RemoteException e) {Log.e(TAG, e.toString());}
163fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        } else {
164fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            Log.w(TAG, "Proxy not attached to service");
165fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            if (DBG) log(Log.getStackTraceString(new Throwable()));
166fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
167fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        return BluetoothMap.STATE_ERROR;
168fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
169fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
170fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /**
171fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * Get the currently connected remote Bluetooth device (PCE).
172fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * @return The remote Bluetooth device, or null if not in connected or
173fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     *         connecting state, or if this proxy object is not connected to
174fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     *         the Map service.
175fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     */
176fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public BluetoothDevice getClient() {
177fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        if (VDBG) log("getClient()");
178fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        if (mService != null) {
179fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            try {
180fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                return mService.getClient();
181fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            } catch (RemoteException e) {Log.e(TAG, e.toString());}
182fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        } else {
183fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            Log.w(TAG, "Proxy not attached to service");
184fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            if (DBG) log(Log.getStackTraceString(new Throwable()));
185fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
186fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        return null;
187fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
188fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
189fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /**
1900d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Returns true if the specified Bluetooth device is connected.
1910d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Returns false if not connected, or if this proxy object is not
1920d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * currently connected to the Map service.
193fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     */
194fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public boolean isConnected(BluetoothDevice device) {
195fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        if (VDBG) log("isConnected(" + device + ")");
196fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        if (mService != null) {
197fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            try {
198fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                return mService.isConnected(device);
199fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            } catch (RemoteException e) {Log.e(TAG, e.toString());}
200fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        } else {
201fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            Log.w(TAG, "Proxy not attached to service");
202fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            if (DBG) log(Log.getStackTraceString(new Throwable()));
203fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
204fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        return false;
205fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
206fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
207fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /**
2080d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Initiate connection. Initiation of outgoing connections is not
2090d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * supported for MAP server.
210fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     */
2110d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    public boolean connect(BluetoothDevice device) {
2120d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (DBG) log("connect(" + device + ")" + "not supported for MAPS");
2130d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        return false;
2140d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
2150d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
2160d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    /**
2170d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Initiate disconnect.
2180d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *
2190d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @param device Remote Bluetooth Device
2200d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @return false on error,
2210d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *               true otherwise
2220d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     */
2230d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    public boolean disconnect(BluetoothDevice device) {
2240d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (DBG) log("disconnect(" + device + ")");
2250d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (mService != null && isEnabled() &&
2260d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            isValidDevice(device)) {
227fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            try {
2280d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                return mService.disconnect(device);
2290d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            } catch (RemoteException e) {
2300d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz              Log.e(TAG, Log.getStackTraceString(new Throwable()));
2310d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz              return false;
2320d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            }
233fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
2340d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (mService == null) Log.w(TAG, "Proxy not attached to service");
235fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        return false;
236fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
237fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
238fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    /**
239fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * Check class bits for possible Map support.
240fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * This is a simple heuristic that tries to guess if a device with the
241fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * given class bits might support Map. It is not accurate for all
242fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * devices. It tries to err on the side of false positives.
243fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     * @return True if this device might support Map.
244fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie     */
245fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public static boolean doesClassMatchSink(BluetoothClass btClass) {
246fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        // TODO optimize the rule
247fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        switch (btClass.getDeviceClass()) {
248fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        case BluetoothClass.Device.COMPUTER_DESKTOP:
249fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        case BluetoothClass.Device.COMPUTER_LAPTOP:
250fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        case BluetoothClass.Device.COMPUTER_SERVER:
251fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        case BluetoothClass.Device.COMPUTER_UNCATEGORIZED:
252fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            return true;
253fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        default:
254fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            return false;
255fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
256fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
257fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
2580d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    /**
2590d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Get the list of connected devices. Currently at most one.
2600d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *
2610d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @return list of connected devices
2620d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     */
2630d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    public List<BluetoothDevice> getConnectedDevices() {
2640d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (DBG) log("getConnectedDevices()");
2650d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (mService != null && isEnabled()) {
2660d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            try {
2670d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                return mService.getConnectedDevices();
2680d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            } catch (RemoteException e) {
2690d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                Log.e(TAG, Log.getStackTraceString(new Throwable()));
2700d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                return new ArrayList<BluetoothDevice>();
2710d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            }
2720d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        }
2730d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (mService == null) Log.w(TAG, "Proxy not attached to service");
2740d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        return new ArrayList<BluetoothDevice>();
2750d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
2760d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
2770d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    /**
2780d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Get the list of devices matching specified states. Currently at most one.
2790d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *
2800d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @return list of matching devices
2810d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     */
2820d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
2830d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (DBG) log("getDevicesMatchingStates()");
2840d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (mService != null && isEnabled()) {
2850d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            try {
2860d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                return mService.getDevicesMatchingConnectionStates(states);
2870d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            } catch (RemoteException e) {
2880d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                Log.e(TAG, Log.getStackTraceString(new Throwable()));
2890d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                return new ArrayList<BluetoothDevice>();
2900d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            }
2910d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        }
2920d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (mService == null) Log.w(TAG, "Proxy not attached to service");
2930d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        return new ArrayList<BluetoothDevice>();
2940d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
2950d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
2960d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    /**
2970d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Get connection state of device
2980d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *
2990d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @return device connection state
3000d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     */
3010d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    public int getConnectionState(BluetoothDevice device) {
3020d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (DBG) log("getConnectionState(" + device + ")");
3030d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (mService != null && isEnabled() &&
3040d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            isValidDevice(device)) {
3050d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            try {
3060d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                return mService.getConnectionState(device);
3070d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            } catch (RemoteException e) {
3080d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                Log.e(TAG, Log.getStackTraceString(new Throwable()));
3090d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                return BluetoothProfile.STATE_DISCONNECTED;
3100d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            }
3110d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        }
3120d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (mService == null) Log.w(TAG, "Proxy not attached to service");
3130d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        return BluetoothProfile.STATE_DISCONNECTED;
3140d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
3150d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
3160d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    /**
3170d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Set priority of the profile
3180d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *
3190d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * <p> The device should already be paired.
3200d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *  Priority can be one of {@link #PRIORITY_ON} or
3210d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * {@link #PRIORITY_OFF},
3220d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *
3230d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @param device Paired bluetooth device
3240d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @param priority
3250d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @return true if priority is set, false on error
3260d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     */
3270d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    public boolean setPriority(BluetoothDevice device, int priority) {
3280d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (DBG) log("setPriority(" + device + ", " + priority + ")");
3290d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (mService != null && isEnabled() &&
3300d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            isValidDevice(device)) {
3310d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            if (priority != BluetoothProfile.PRIORITY_OFF &&
3320d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                priority != BluetoothProfile.PRIORITY_ON) {
3330d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz              return false;
3340d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            }
3350d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            try {
3360d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                return mService.setPriority(device, priority);
3370d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            } catch (RemoteException e) {
3380d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                Log.e(TAG, Log.getStackTraceString(new Throwable()));
3390d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                return false;
3400d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            }
3410d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        }
3420d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (mService == null) Log.w(TAG, "Proxy not attached to service");
3430d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        return false;
3440d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
3450d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
3460d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    /**
3470d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * Get the priority of the profile.
3480d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *
3490d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * <p> The priority can be any of:
3500d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
3510d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
3520d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     *
3530d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @param device Bluetooth device
3540d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     * @return priority of the device
3550d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz     */
3560d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    public int getPriority(BluetoothDevice device) {
3570d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (VDBG) log("getPriority(" + device + ")");
3580d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (mService != null && isEnabled() &&
3590d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            isValidDevice(device)) {
3600d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            try {
3610d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                return mService.getPriority(device);
3620d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            } catch (RemoteException e) {
3630d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                Log.e(TAG, Log.getStackTraceString(new Throwable()));
3640d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                return PRIORITY_OFF;
3650d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            }
3660d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        }
3670d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (mService == null) Log.w(TAG, "Proxy not attached to service");
3680d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        return PRIORITY_OFF;
3690d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
3700d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
3719b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie    private final ServiceConnection mConnection = new ServiceConnection() {
372fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        public void onServiceConnected(ComponentName className, IBinder service) {
373fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            if (DBG) log("Proxy object connected");
3740a17db1cc5942ea000ca87bb72853de57a15ec64Jeff Sharkey            mService = IBluetoothMap.Stub.asInterface(Binder.allowBlocking(service));
375fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            if (mServiceListener != null) {
3760d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                mServiceListener.onServiceConnected(BluetoothProfile.MAP, BluetoothMap.this);
377fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            }
378fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
379fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        public void onServiceDisconnected(ComponentName className) {
380fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            if (DBG) log("Proxy object disconnected");
381fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            mService = null;
382fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            if (mServiceListener != null) {
3830d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz                mServiceListener.onServiceDisconnected(BluetoothProfile.MAP);
384fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            }
385fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        }
386fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    };
387fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
388fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    private static void log(String msg) {
389fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        Log.d(TAG, msg);
390fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
3910d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
3920d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz   private boolean isEnabled() {
3930d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
3940d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
3950d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        log("Bluetooth is Not enabled");
3960d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        return false;
3970d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
3980d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    private boolean isValidDevice(BluetoothDevice device) {
3990d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz       if (device == null) return false;
4000d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
4010d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz       if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
4020d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz       return false;
4030d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz    }
4040d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
4050d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz
406fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie}
407