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