OSDN Git Service

Merge "Fix SystemUI crash on devices with WiFi only" into klp-dev
[android-x86/frameworks-base.git] / core / java / android / bluetooth / BluetoothMap.java
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package android.bluetooth;
18
19 import java.util.List;
20 import java.util.ArrayList;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.ServiceConnection;
25 import android.os.RemoteException;
26 import android.os.IBinder;
27 import android.os.ServiceManager;
28 import android.util.Log;
29
30 /**
31  * This class provides the APIs to control the Bluetooth MAP
32  * Profile.
33  *@hide
34  */
35 public final class BluetoothMap implements BluetoothProfile {
36
37     private static final String TAG = "BluetoothMap";
38     private static final boolean DBG = true;
39     private static final boolean VDBG = false;
40
41     public static final String ACTION_CONNECTION_STATE_CHANGED =
42         "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
43
44     private IBluetoothMap mService;
45     private final Context mContext;
46     private ServiceListener mServiceListener;
47     private BluetoothAdapter mAdapter;
48
49     /** There was an error trying to obtain the state */
50     public static final int STATE_ERROR        = -1;
51
52     public static final int RESULT_FAILURE = 0;
53     public static final int RESULT_SUCCESS = 1;
54     /** Connection canceled before completion. */
55     public static final int RESULT_CANCELED = 2;
56
57     final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
58             new IBluetoothStateChangeCallback.Stub() {
59                 public void onBluetoothStateChange(boolean up) {
60                     if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
61                     if (!up) {
62                         if (VDBG) Log.d(TAG,"Unbinding service...");
63                         synchronized (mConnection) {
64                             try {
65                                 mService = null;
66                                 mContext.unbindService(mConnection);
67                             } catch (Exception re) {
68                                 Log.e(TAG,"",re);
69                             }
70                         }
71                     } else {
72                         synchronized (mConnection) {
73                             try {
74                                 if (mService == null) {
75                                     if (VDBG) Log.d(TAG,"Binding service...");
76                                     doBind();
77                                 }
78                             } catch (Exception re) {
79                                 Log.e(TAG,"",re);
80                             }
81                         }
82                     }
83                 }
84         };
85
86     /**
87      * Create a BluetoothMap proxy object.
88      */
89     /*package*/ BluetoothMap(Context context, ServiceListener l) {
90         if (DBG) Log.d(TAG, "Create BluetoothMap proxy object");
91         mContext = context;
92         mServiceListener = l;
93         mAdapter = BluetoothAdapter.getDefaultAdapter();
94         IBluetoothManager mgr = mAdapter.getBluetoothManager();
95         if (mgr != null) {
96             try {
97                 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
98             } catch (RemoteException e) {
99                 Log.e(TAG,"",e);
100             }
101         }
102         doBind();
103     }
104
105     boolean doBind() {
106         Intent intent = new Intent(IBluetoothMap.class.getName());
107         ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
108         intent.setComponent(comp);
109         if (comp == null || !mContext.bindService(intent, mConnection, 0)) {
110             Log.e(TAG, "Could not bind to Bluetooth MAP Service with " + intent);
111             return false;
112         }
113         return true;
114     }
115
116     protected void finalize() throws Throwable {
117         try {
118             close();
119         } finally {
120             super.finalize();
121         }
122     }
123
124     /**
125      * Close the connection to the backing service.
126      * Other public functions of BluetoothMap will return default error
127      * results once close() has been called. Multiple invocations of close()
128      * are ok.
129      */
130     public synchronized void close() {
131         IBluetoothManager mgr = mAdapter.getBluetoothManager();
132         if (mgr != null) {
133             try {
134                 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
135             } catch (Exception e) {
136                 Log.e(TAG,"",e);
137             }
138         }
139
140         synchronized (mConnection) {
141             if (mService != null) {
142                 try {
143                     mService = null;
144                     mContext.unbindService(mConnection);
145                 } catch (Exception re) {
146                     Log.e(TAG,"",re);
147                 }
148             }
149         }
150         mServiceListener = null;
151     }
152
153     /**
154      * Get the current state of the BluetoothMap service.
155      * @return One of the STATE_ return codes, or STATE_ERROR if this proxy
156      *         object is currently not connected to the Map service.
157      */
158     public int getState() {
159         if (VDBG) log("getState()");
160         if (mService != null) {
161             try {
162                 return mService.getState();
163             } catch (RemoteException e) {Log.e(TAG, e.toString());}
164         } else {
165             Log.w(TAG, "Proxy not attached to service");
166             if (DBG) log(Log.getStackTraceString(new Throwable()));
167         }
168         return BluetoothMap.STATE_ERROR;
169     }
170
171     /**
172      * Get the currently connected remote Bluetooth device (PCE).
173      * @return The remote Bluetooth device, or null if not in connected or
174      *         connecting state, or if this proxy object is not connected to
175      *         the Map service.
176      */
177     public BluetoothDevice getClient() {
178         if (VDBG) log("getClient()");
179         if (mService != null) {
180             try {
181                 return mService.getClient();
182             } catch (RemoteException e) {Log.e(TAG, e.toString());}
183         } else {
184             Log.w(TAG, "Proxy not attached to service");
185             if (DBG) log(Log.getStackTraceString(new Throwable()));
186         }
187         return null;
188     }
189
190     /**
191      * Returns true if the specified Bluetooth device is connected.
192      * Returns false if not connected, or if this proxy object is not
193      * currently connected to the Map service.
194      */
195     public boolean isConnected(BluetoothDevice device) {
196         if (VDBG) log("isConnected(" + device + ")");
197         if (mService != null) {
198             try {
199                 return mService.isConnected(device);
200             } catch (RemoteException e) {Log.e(TAG, e.toString());}
201         } else {
202             Log.w(TAG, "Proxy not attached to service");
203             if (DBG) log(Log.getStackTraceString(new Throwable()));
204         }
205         return false;
206     }
207
208     /**
209      * Initiate connection. Initiation of outgoing connections is not
210      * supported for MAP server.
211      */
212     public boolean connect(BluetoothDevice device) {
213         if (DBG) log("connect(" + device + ")" + "not supported for MAPS");
214         return false;
215     }
216
217     /**
218      * Initiate disconnect.
219      *
220      * @param device Remote Bluetooth Device
221      * @return false on error,
222      *               true otherwise
223      */
224     public boolean disconnect(BluetoothDevice device) {
225         if (DBG) log("disconnect(" + device + ")");
226         if (mService != null && isEnabled() &&
227             isValidDevice(device)) {
228             try {
229                 return mService.disconnect(device);
230             } catch (RemoteException e) {
231               Log.e(TAG, Log.getStackTraceString(new Throwable()));
232               return false;
233             }
234         }
235         if (mService == null) Log.w(TAG, "Proxy not attached to service");
236         return false;
237     }
238
239     /**
240      * Check class bits for possible Map support.
241      * This is a simple heuristic that tries to guess if a device with the
242      * given class bits might support Map. It is not accurate for all
243      * devices. It tries to err on the side of false positives.
244      * @return True if this device might support Map.
245      */
246     public static boolean doesClassMatchSink(BluetoothClass btClass) {
247         // TODO optimize the rule
248         switch (btClass.getDeviceClass()) {
249         case BluetoothClass.Device.COMPUTER_DESKTOP:
250         case BluetoothClass.Device.COMPUTER_LAPTOP:
251         case BluetoothClass.Device.COMPUTER_SERVER:
252         case BluetoothClass.Device.COMPUTER_UNCATEGORIZED:
253             return true;
254         default:
255             return false;
256         }
257     }
258
259     /**
260      * Get the list of connected devices. Currently at most one.
261      *
262      * @return list of connected devices
263      */
264     public List<BluetoothDevice> getConnectedDevices() {
265         if (DBG) log("getConnectedDevices()");
266         if (mService != null && isEnabled()) {
267             try {
268                 return mService.getConnectedDevices();
269             } catch (RemoteException e) {
270                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
271                 return new ArrayList<BluetoothDevice>();
272             }
273         }
274         if (mService == null) Log.w(TAG, "Proxy not attached to service");
275         return new ArrayList<BluetoothDevice>();
276     }
277
278     /**
279      * Get the list of devices matching specified states. Currently at most one.
280      *
281      * @return list of matching devices
282      */
283     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
284         if (DBG) log("getDevicesMatchingStates()");
285         if (mService != null && isEnabled()) {
286             try {
287                 return mService.getDevicesMatchingConnectionStates(states);
288             } catch (RemoteException e) {
289                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
290                 return new ArrayList<BluetoothDevice>();
291             }
292         }
293         if (mService == null) Log.w(TAG, "Proxy not attached to service");
294         return new ArrayList<BluetoothDevice>();
295     }
296
297     /**
298      * Get connection state of device
299      *
300      * @return device connection state
301      */
302     public int getConnectionState(BluetoothDevice device) {
303         if (DBG) log("getConnectionState(" + device + ")");
304         if (mService != null && isEnabled() &&
305             isValidDevice(device)) {
306             try {
307                 return mService.getConnectionState(device);
308             } catch (RemoteException e) {
309                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
310                 return BluetoothProfile.STATE_DISCONNECTED;
311             }
312         }
313         if (mService == null) Log.w(TAG, "Proxy not attached to service");
314         return BluetoothProfile.STATE_DISCONNECTED;
315     }
316
317     /**
318      * Set priority of the profile
319      *
320      * <p> The device should already be paired.
321      *  Priority can be one of {@link #PRIORITY_ON} or
322      * {@link #PRIORITY_OFF},
323      *
324      * @param device Paired bluetooth device
325      * @param priority
326      * @return true if priority is set, false on error
327      */
328     public boolean setPriority(BluetoothDevice device, int priority) {
329         if (DBG) log("setPriority(" + device + ", " + priority + ")");
330         if (mService != null && isEnabled() &&
331             isValidDevice(device)) {
332             if (priority != BluetoothProfile.PRIORITY_OFF &&
333                 priority != BluetoothProfile.PRIORITY_ON) {
334               return false;
335             }
336             try {
337                 return mService.setPriority(device, priority);
338             } catch (RemoteException e) {
339                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
340                 return false;
341             }
342         }
343         if (mService == null) Log.w(TAG, "Proxy not attached to service");
344         return false;
345     }
346
347     /**
348      * Get the priority of the profile.
349      *
350      * <p> The priority can be any of:
351      * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
352      * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
353      *
354      * @param device Bluetooth device
355      * @return priority of the device
356      */
357     public int getPriority(BluetoothDevice device) {
358         if (VDBG) log("getPriority(" + device + ")");
359         if (mService != null && isEnabled() &&
360             isValidDevice(device)) {
361             try {
362                 return mService.getPriority(device);
363             } catch (RemoteException e) {
364                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
365                 return PRIORITY_OFF;
366             }
367         }
368         if (mService == null) Log.w(TAG, "Proxy not attached to service");
369         return PRIORITY_OFF;
370     }
371
372     private final ServiceConnection mConnection = new ServiceConnection() {
373         public void onServiceConnected(ComponentName className, IBinder service) {
374             if (DBG) log("Proxy object connected");
375             mService = IBluetoothMap.Stub.asInterface(service);
376             if (mServiceListener != null) {
377                 mServiceListener.onServiceConnected(BluetoothProfile.MAP, BluetoothMap.this);
378             }
379         }
380         public void onServiceDisconnected(ComponentName className) {
381             if (DBG) log("Proxy object disconnected");
382             mService = null;
383             if (mServiceListener != null) {
384                 mServiceListener.onServiceDisconnected(BluetoothProfile.MAP);
385             }
386         }
387     };
388
389     private static void log(String msg) {
390         Log.d(TAG, msg);
391     }
392
393    private boolean isEnabled() {
394         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
395         if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
396         log("Bluetooth is Not enabled");
397         return false;
398     }
399     private boolean isValidDevice(BluetoothDevice device) {
400        if (device == null) return false;
401
402        if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
403        return false;
404     }
405
406
407 }