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