1e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignol/* 2e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignol * Copyright (C) 2017 The Android Open Source Project 3e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignol * 4e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignol * Licensed under the Apache License, Version 2.0 (the "License"); 5e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignol * you may not use this file except in compliance with the License. 6e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignol * You may obtain a copy of the License at 7e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignol * 8e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignol * http://www.apache.org/licenses/LICENSE-2.0 9e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignol * 10e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignol * Unless required by applicable law or agreed to in writing, software 11e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignol * distributed under the License is distributed on an "AS IS" BASIS, 12e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignol * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignol * See the License for the specific language governing permissions and 14e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignol * limitations under the License. 15e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignol */ 16e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignol 17a16406ba1a734f21f36a4b0f64b23b062644b6e2Andrew Rossignolpackage com.googlecode.android_scripting.facade.bluetooth; 18e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignol 19e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignolimport android.app.Service; 203884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chungimport android.bluetooth.BluetoothAdapter; 21a16406ba1a734f21f36a4b0f64b23b062644b6e2Andrew Rossignolimport android.bluetooth.BluetoothDevice; 2227d4adedb8c7d1f4b41388efb04a30a9038f33e1Andrew Rossignolimport android.bluetooth.BluetoothMap; 23a16406ba1a734f21f36a4b0f64b23b062644b6e2Andrew Rossignolimport android.bluetooth.BluetoothProfile; 24a16406ba1a734f21f36a4b0f64b23b062644b6e2Andrew Rossignolimport android.bluetooth.BluetoothUuid; 25a16406ba1a734f21f36a4b0f64b23b062644b6e2Andrew Rossignolimport android.os.ParcelUuid; 26e969b9be8eca27ffc875167879ab0ec093b3e313Andrew Rossignol 27e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignolimport com.googlecode.android_scripting.Log; 28e969b9be8eca27ffc875167879ab0ec093b3e313Andrew Rossignolimport com.googlecode.android_scripting.facade.FacadeManager; 29e969b9be8eca27ffc875167879ab0ec093b3e313Andrew Rossignolimport com.googlecode.android_scripting.jsonrpc.RpcReceiver; 30e47c28ffe449ca6b91ad0604be2bf164cdd490a3Andrew Rossignolimport com.googlecode.android_scripting.rpc.Rpc; 313e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chungimport com.googlecode.android_scripting.rpc.RpcParameter; 323e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung 333e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chungimport java.util.List; 343e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung 353e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chungpublic class BluetoothMapFacade extends RpcReceiver { 363884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung static final ParcelUuid[] MAP_UUIDS = { 373e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung BluetoothUuid.MAP, 3827d4adedb8c7d1f4b41388efb04a30a9038f33e1Andrew Rossignol BluetoothUuid.MNS, 3927d4adedb8c7d1f4b41388efb04a30a9038f33e1Andrew Rossignol BluetoothUuid.MAS, 4027d4adedb8c7d1f4b41388efb04a30a9038f33e1Andrew Rossignol }; 4127d4adedb8c7d1f4b41388efb04a30a9038f33e1Andrew Rossignol private final Service mService; 423e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung private final BluetoothAdapter mBluetoothAdapter; 433e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung 443884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung private static boolean sIsMapReady = false; 453884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung private static BluetoothMap sMapProfile = null; 463884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung 473884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung public BluetoothMapFacade(FacadeManager manager) { 483884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung super(manager); 493884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung mService = manager.getService(); 503884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 513884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung mBluetoothAdapter.getProfileProxy(mService, new MapServiceListener(), 523e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung BluetoothProfile.MAP); 533884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung } 543e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung 553e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung class MapServiceListener implements BluetoothProfile.ServiceListener { 563e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung @Override 573e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung public void onServiceConnected(int profile, BluetoothProfile proxy) { 583884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung sMapProfile = (BluetoothMap) proxy; 593e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung sIsMapReady = true; 603e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung } 613884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung 623884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung @Override 633e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung public void onServiceDisconnected(int profile) { 643e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung sIsMapReady = false; 653884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung } 663884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung } 673e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung 683884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung /** 693884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung * Disconnect Map Profile. 703884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung * @param device - the BluetoothDevice object to connect to. 713884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung * @return if the disconnection was successfull or not. 723884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung */ 733884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung public Boolean mapDisconnect(BluetoothDevice device) { 743884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung if (sMapProfile.getPriority(device) > BluetoothProfile.PRIORITY_ON) { 753884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung sMapProfile.setPriority(device, BluetoothProfile.PRIORITY_ON); 763884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung } 773884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung return sMapProfile.disconnect(device); 783884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung } 793884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung 803884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung /** 813884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung * Is Map profile ready. 823884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung * @return if Map profile is ready or not. 833884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung */ 843884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung @Rpc(description = "Is Map profile ready.") 853884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung public Boolean bluetoothMapIsReady() { 863884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung return sIsMapReady; 873884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung } 883884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung 893e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung /** 903e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung * Disconnect an MAP device. 913e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung * @param deviceID - Name or MAC address of a bluetooth device. 923e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung * @return True if the disconnection was successful; otherwise False. 933e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung */ 943e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung @Rpc(description = "Disconnect an MAP device.") 953e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung public Boolean bluetoothMapDisconnect( 963e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung @RpcParameter(name = "deviceID", 973e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung description = "Name or MAC address of a device.") 983e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung String deviceID) throws Exception { 993e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung if (sMapProfile == null) return false; 1003e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung List<BluetoothDevice> connectedMapDevices = 1013e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung sMapProfile.getConnectedDevices(); 1023e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung Log.d("Connected map devices: " + connectedMapDevices); 1033e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung BluetoothDevice mDevice = BluetoothFacade.getDevice(connectedMapDevices, deviceID); 1043e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung if (!connectedMapDevices.isEmpty() 1053e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung && connectedMapDevices.get(0).equals(mDevice)) { 1063e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung if (sMapProfile.getPriority(mDevice) 1073e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung > BluetoothProfile.PRIORITY_ON) { 1083e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung sMapProfile.setPriority(mDevice, BluetoothProfile.PRIORITY_ON); 1093e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung } 1103e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung return sMapProfile.disconnect(mDevice); 1113e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung } else { 1123e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung return false; 1133e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung } 1143e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung } 1153e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung 1163884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung /** 1173e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung * Get all the devices connected through MAP. 1183884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung * @return List of all the devices connected through MAP. 1193884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung */ 1203884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung @Rpc(description = "Get all the devices connected through MAP.") 1213e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung public List<BluetoothDevice> bluetoothMapGetConnectedDevices() { 1223e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung if (!sIsMapReady) return null; 1233e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung return sMapProfile.getDevicesMatchingConnectionStates( 1243e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung new int[] {BluetoothProfile.STATE_CONNECTED, 1253e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung BluetoothProfile.STATE_CONNECTING, 1263e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung BluetoothProfile.STATE_DISCONNECTING}); 1273e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung } 1283e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung 1293e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung /** 1303e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung * Get the currently connected remote Bluetooth device (PCE). 1313e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung * @return remote Bluetooth device which is currently conencted. 1323e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung */ 1333e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung @Rpc(description = 1343e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung "Get the currently connected remote Bluetooth device (PCE).") 1353e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung public BluetoothDevice bluetoothMapGetClient() { 1363e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung if (sMapProfile == null) return null; 1373e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung return sMapProfile.getClient(); 1383e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung } 1393e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung 1403e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung @Override 1413e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung public void shutdown() { 1423e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung } 1433e1c98d9c4d08a47c439d4a60923edd2a23891b3Meng-hsuan Chung} 1443884ae8a863be35992abc3c172a29f84ba8a4b83Meng-hsuan Chung