Fix bugs in sl4a bluetooth connection APIs.
Restructure receivers in connection facade.
Fix a name in media player facade.
Merging kwd commit 9c02e91c1fed90f743eda49dff5c7263a76c1a49
Change-Id: Ibd00c2df6311efd075a2e38fd71e2ad4a18b90cf
diff --git a/Common/src/com/googlecode/android_scripting/bluetooth/BluetoothA2dpFacade.java b/Common/src/com/googlecode/android_scripting/bluetooth/BluetoothA2dpFacade.java
index c3a2e6d..805c78f 100644
--- a/Common/src/com/googlecode/android_scripting/bluetooth/BluetoothA2dpFacade.java
+++ b/Common/src/com/googlecode/android_scripting/bluetooth/BluetoothA2dpFacade.java
@@ -16,85 +16,88 @@
import com.googlecode.android_scripting.rpc.Rpc;
import com.googlecode.android_scripting.rpc.RpcParameter;
-
public class BluetoothA2dpFacade extends RpcReceiver {
- static final ParcelUuid[] SINK_UUIDS = {
- BluetoothUuid.AudioSink,
- BluetoothUuid.AdvAudioDist,
- };
+ static final ParcelUuid[] SINK_UUIDS = { BluetoothUuid.AudioSink,
+ BluetoothUuid.AdvAudioDist, };
private final Service mService;
private final BluetoothAdapter mBluetoothAdapter;
- private boolean mIsA2dpReady = false;
- private BluetoothA2dp mA2dpProfile = null;
+ private static boolean sIsA2dpReady = false;
+ private static BluetoothA2dp sA2dpProfile = null;
public BluetoothA2dpFacade(FacadeManager manager) {
super(manager);
mService = manager.getService();
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- mBluetoothAdapter.getProfileProxy(mService, new A2dpServiceListener(), BluetoothProfile.A2DP);
+ mBluetoothAdapter.getProfileProxy(mService, new A2dpServiceListener(),
+ BluetoothProfile.A2DP);
}
class A2dpServiceListener implements BluetoothProfile.ServiceListener {
@Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- mA2dpProfile = (BluetoothA2dp) proxy;
- mIsA2dpReady = true;
+ sA2dpProfile = (BluetoothA2dp) proxy;
+ sIsA2dpReady = true;
}
+
@Override
public void onServiceDisconnected(int profile) {
- mIsA2dpReady = false;
+ sIsA2dpReady = false;
}
}
public Boolean a2dpConnect(BluetoothDevice device) {
- List<BluetoothDevice> sinks = mA2dpProfile.getConnectedDevices();
+ List<BluetoothDevice> sinks = sA2dpProfile.getConnectedDevices();
if (sinks != null) {
- for (BluetoothDevice sink : sinks) {
- mA2dpProfile.disconnect(sink);
- }
+ for (BluetoothDevice sink : sinks) {
+ sA2dpProfile.disconnect(sink);
+ }
}
- return mA2dpProfile.connect(device);
+ return sA2dpProfile.connect(device);
}
public Boolean a2dpDisconnect(BluetoothDevice device) {
- if (mA2dpProfile.getPriority(device) > BluetoothProfile.PRIORITY_ON){
- mA2dpProfile.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ if (sA2dpProfile.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
+ sA2dpProfile.setPriority(device, BluetoothProfile.PRIORITY_ON);
}
- return mA2dpProfile.disconnect(device);
+ return sA2dpProfile.disconnect(device);
}
- @Rpc(description="Is A2dp profile ready.")
+ @Rpc(description = "Is A2dp profile ready.")
public Boolean bluetoothA2dpIsReady() {
- return mIsA2dpReady;
+ return sIsA2dpReady;
}
- @Rpc(description="Connect to an A2DP device.")
+
+ @Rpc(description = "Connect to an A2DP device.")
public Boolean bluetoothA2dpConnect(
- @RpcParameter(
- name = "device",
- description = "Name or MAC address of a bluetooth device.")
- String device) throws Exception {
- if (mA2dpProfile == null) return false;
- BluetoothDevice mDevice = BluetoothFacade.getDevice(BluetoothFacade.DiscoveredDevices, device);
+ @RpcParameter(name = "device", description = "Name or MAC address of a bluetooth device.") String device)
+ throws Exception {
+ if (sA2dpProfile == null)
+ return false;
+ BluetoothDevice mDevice = BluetoothFacade.getDevice(
+ BluetoothFacade.DiscoveredDevices, device);
Log.d("Connecting to device " + mDevice.getAliasName());
return a2dpConnect(mDevice);
}
- @Rpc(description="Disconnect an A2DP device.")
+ @Rpc(description = "Disconnect an A2DP device.")
public Boolean bluetoothA2dpDisconnect(
- @RpcParameter(
- name = "device",
- description = "Name or MAC address of a device.")
- String device) throws Exception {
- if (mA2dpProfile == null) return false;
- BluetoothDevice mDevice = BluetoothFacade.getDevice(mA2dpProfile.getConnectedDevices(), device);
+ @RpcParameter(name = "device", description = "Name or MAC address of a device.") String device)
+ throws Exception {
+ if (sA2dpProfile == null)
+ return false;
+ Log.d("Connected devices: " + sA2dpProfile.getConnectedDevices());
+ BluetoothDevice mDevice = BluetoothFacade.getDevice(
+ sA2dpProfile.getConnectedDevices(), device);
return a2dpDisconnect(mDevice);
}
- @Rpc(description="Get all the devices connected through A2DP.")
+ @Rpc(description = "Get all the devices connected through A2DP.")
public List<BluetoothDevice> bluetoothA2dpGetConnectedDevices() {
- return mA2dpProfile.getConnectedDevices();
+ while (!sIsA2dpReady)
+ ;
+ return sA2dpProfile.getConnectedDevices();
}
@Override
diff --git a/Common/src/com/googlecode/android_scripting/bluetooth/BluetoothConnectionFacade.java b/Common/src/com/googlecode/android_scripting/bluetooth/BluetoothConnectionFacade.java
index 16b7713..9fb98b4 100644
--- a/Common/src/com/googlecode/android_scripting/bluetooth/BluetoothConnectionFacade.java
+++ b/Common/src/com/googlecode/android_scripting/bluetooth/BluetoothConnectionFacade.java
@@ -1,10 +1,17 @@
+
package com.googlecode.android_scripting.bluetooth;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
import android.app.Service;
+import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothUuid;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -21,181 +28,260 @@
import com.googlecode.android_scripting.rpc.RpcParameter;
public class BluetoothConnectionFacade extends RpcReceiver {
- static final ParcelUuid[] SINK_UUIDS = {
- BluetoothUuid.AudioSink,
- BluetoothUuid.AdvAudioDist,
- };
- static final ParcelUuid[] HSP_UUIDS = {
- BluetoothUuid.HSP,
- BluetoothUuid.Handsfree,
- };
+ static final ParcelUuid[] SINK_UUIDS = {
+ BluetoothUuid.AudioSink, BluetoothUuid.AdvAudioDist,
+ };
+ static final ParcelUuid[] HSP_UUIDS = {
+ BluetoothUuid.HSP, BluetoothUuid.Handsfree,
+ };
- private final Service mService;
- private final BluetoothAdapter mBluetoothAdapter;
- private final BluetoothPairingHelper mPairingHelper;
- private final ConcurrentHashMap<String, BroadcastReceiver> listeningDevices;
+ private final Service mService;
+ private final BluetoothAdapter mBluetoothAdapter;
+ private final BluetoothPairingHelper mPairingHelper;
+ private final Map<String, BroadcastReceiver> listeningDevices;
- private final EventFacade mEventFacade;
- private BluetoothHspFacade mHspProfile;
- private BluetoothA2dpFacade mA2dpProfile;
+ private final EventFacade mEventFacade;
+ private BluetoothHspFacade mHspProfile;
+ private BluetoothA2dpFacade mA2dpProfile;
- private final IntentFilter mDiscoverConnectFilter;
- private final IntentFilter mPairingFilter;
+ private final IntentFilter mDiscoverConnectFilter;
+ private final IntentFilter mPairingFilter;
+ private final IntentFilter mBondStateChangeFilter;
+ private final IntentFilter mA2dpStateChangeFilter;
+ private final IntentFilter mHspStateChangeFilter;
- public BluetoothConnectionFacade(FacadeManager manager) {
- super(manager);
- mService = manager.getService();
- mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- mPairingHelper = new BluetoothPairingHelper();
- listeningDevices = new ConcurrentHashMap<String, BroadcastReceiver>();
+ public BluetoothConnectionFacade(FacadeManager manager) {
+ super(manager);
+ mService = manager.getService();
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ mPairingHelper = new BluetoothPairingHelper();
+ // Use a synchronized map to avoid running problems
+ listeningDevices = Collections.synchronizedMap(new HashMap<String, BroadcastReceiver>());
- mEventFacade = manager.getReceiver(EventFacade.class);
- mA2dpProfile = manager.getReceiver(BluetoothA2dpFacade.class);
- mHspProfile = manager.getReceiver(BluetoothHspFacade.class);
+ mEventFacade = manager.getReceiver(EventFacade.class);
+ mA2dpProfile = manager.getReceiver(BluetoothA2dpFacade.class);
+ mHspProfile = manager.getReceiver(BluetoothHspFacade.class);
- mDiscoverConnectFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
- mDiscoverConnectFilter.addAction(BluetoothDevice.ACTION_UUID);
- mDiscoverConnectFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
+ mDiscoverConnectFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
+ mDiscoverConnectFilter.addAction(BluetoothDevice.ACTION_UUID);
+ mDiscoverConnectFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
- mPairingFilter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
- }
+ mPairingFilter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
- /**
- * Connect to a specific device upon its discovery
- * @author angli
- *
- */
- public class DiscoverConnectReceiver extends BroadcastReceiver {
- private final String mDeviceID;
- private final Boolean mBond;
- private BluetoothDevice mDevice;
+ mBondStateChangeFilter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+ mA2dpStateChangeFilter = new IntentFilter(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
+ mHspStateChangeFilter = new IntentFilter(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
+ }
+
/**
- * Constructor
- * @param deviceID Either the device alias name or mac address.
- * @param bond If true, create bond to the device only.
+ * Connect to a specific device upon its discovery
*/
- public DiscoverConnectReceiver(String deviceID, Boolean bond) {
- super();
- mDeviceID = deviceID;
- mBond = bond;
+ public class DiscoverConnectReceiver extends BroadcastReceiver {
+ private final String mDeviceID;
+ private final Boolean mBond;
+ private BluetoothDevice mDevice;
+
+ /**
+ * Constructor
+ *
+ * @param deviceID Either the device alias name or mac address.
+ * @param bond If true, bond the device only.
+ */
+ public DiscoverConnectReceiver(String deviceID, Boolean bond) {
+ super();
+ mDeviceID = deviceID;
+ mBond = bond;
+ }
+
+ public DiscoverConnectReceiver(String deviceID) {
+ this(deviceID, false);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ // The specified device is found.
+ if (action.equals(BluetoothDevice.ACTION_FOUND)) {
+ BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ if (BluetoothFacade.deviceMatch(device, mDeviceID)) {
+ Log.d("Found device " + device.getAliasName() + " for connection.");
+ mBluetoothAdapter.cancelDiscovery();
+ mDevice = device;
+ }
+ // After discovery stops.
+ } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
+ if (mDevice == null) {
+ Log.d("Device " + mDeviceID + " was not discovered.");
+ return;
+ }
+ // Attempt to initiate bonding if this is a bond request.
+ if (mBond) {
+ Log.d("Bond with " + mDevice.getAliasName());
+ StateChangeReceiver receiver = new StateChangeReceiver(mDeviceID);
+ listeningDevices.put("Bonding" + mDeviceID, receiver);
+ mService.registerReceiver(receiver, mBondStateChangeFilter);
+ if (mDevice.createBond()) {
+ Log.d("Bonding started.");
+ } else {
+ Log.e("Failed to bond with " + mDevice.getAliasName());
+ mService.unregisterReceiver(listeningDevices.remove("Bonding" + mDeviceID));
+ }
+ mService.unregisterReceiver(listeningDevices.remove("Bond" + mDeviceID));
+ // Otherwise fetch the device's UUID.
+ } else {
+ Log.d("Discovery finished, start fetching UUIDs.");
+ boolean status = mDevice.fetchUuidsWithSdp();
+ Log.d("Initiated ACL connection: " + status);
+ }
+ // Initiate connection based on the UUIDs retrieved.
+ } else if (action.equals(BluetoothDevice.ACTION_UUID)) {
+ BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ if (BluetoothFacade.deviceMatch(device, mDeviceID)) {
+ Log.d("Initiating connections.");
+ connectProfile(device, mDeviceID);
+ mService.unregisterReceiver(listeningDevices.remove(mDeviceID));
+ }
+ }
+ }
}
- public DiscoverConnectReceiver(String deviceID) {
- this(deviceID, false);
+
+ public class StateChangeReceiver extends BroadcastReceiver {
+ private final String mDeviceID;
+
+ public StateChangeReceiver(String deviceID) {
+ mDeviceID = deviceID;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
+ int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
+ if (state == BluetoothDevice.BOND_BONDED) {
+ mEventFacade.postEvent("Bonded" + mDeviceID, new Bundle());
+ mService.unregisterReceiver(listeningDevices.remove("Bonding" + mDeviceID));
+ }
+ } else if (action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
+ int state = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, -1);
+ if (state == BluetoothA2dp.STATE_CONNECTED) {
+ mEventFacade.postEvent("A2dpConnected" + mDeviceID, new Bundle());
+ mService.unregisterReceiver(listeningDevices.remove("A2dpConnecting"
+ + mDeviceID));
+ }
+ } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
+ int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, -1);
+ if (state == BluetoothHeadset.STATE_CONNECTED) {
+ mEventFacade.postEvent("HspConnected" + mDeviceID, new Bundle());
+ mService.unregisterReceiver(listeningDevices
+ .remove("HspConnecting" + mDeviceID));
+ }
+ }
+ }
}
+
+ private void connectProfile(BluetoothDevice device, String deviceID) {
+ ParcelUuid[] deviceUuids = device.getUuids();
+ Log.d("Device uuid is " + deviceUuids);
+ mService.registerReceiver(mPairingHelper, mPairingFilter);
+ if (BluetoothUuid.containsAnyUuid(SINK_UUIDS, deviceUuids)) {
+ Log.d("Connecting to " + device.getAliasName());
+ boolean status = mA2dpProfile.a2dpConnect(device);
+ if (status) {
+ Log.d("Connecting A2dp...");
+ StateChangeReceiver receiver = new StateChangeReceiver(deviceID);
+ mService.registerReceiver(receiver, mA2dpStateChangeFilter);
+ listeningDevices.put("A2dpConnecting" + deviceID, receiver);
+ } else {
+ Log.d("Failed starting A2dp connection.");
+ }
+ }
+ if (BluetoothUuid.containsAnyUuid(HSP_UUIDS, deviceUuids)) {
+ boolean status = mHspProfile.hspConnect(device);
+ if (status) {
+ Log.d("Posting event.");
+ StateChangeReceiver receiver = new StateChangeReceiver(deviceID);
+ mService.registerReceiver(receiver, mHspStateChangeFilter);
+ listeningDevices.put("HspConnecting" + deviceID, receiver);
+ } else {
+ Log.d("Failed starting Hsp connection.");
+ }
+ }
+ mService.unregisterReceiver(mPairingHelper);
+ }
+
+ private Set<BluetoothDevice> getConnectedDevices() {
+ Set<BluetoothDevice> a2dp = new HashSet<BluetoothDevice>(
+ mA2dpProfile.bluetoothA2dpGetConnectedDevices());
+ Set<BluetoothDevice> hsp = new HashSet<BluetoothDevice>(
+ mHspProfile.bluetoothHspGetConnectedDevices());
+ a2dp.addAll(hsp);
+ return a2dp;
+ }
+
+ @Rpc(description = "Connect to a specified device once it's discovered.",
+ returns = "Whether discovery started successfully.")
+ public Boolean bluetoothDiscoverAndConnect(
+ @RpcParameter(name = "deviceID",
+ description = "Name or MAC address of a bluetooth device.")
+ String deviceID) {
+ mBluetoothAdapter.cancelDiscovery();
+ if (listeningDevices.containsKey(deviceID)) {
+ Log.d("This device is already in the process of discovery and connecting.");
+ return false;
+ }
+ if (BluetoothFacade.deviceExists(getConnectedDevices(), deviceID)) {
+ Log.d("Device " + deviceID + " is already connected through A2DP.");
+ return false;
+ }
+ DiscoverConnectReceiver receiver = new DiscoverConnectReceiver(deviceID);
+ listeningDevices.put(deviceID, receiver);
+ mService.registerReceiver(receiver, mDiscoverConnectFilter);
+ return mBluetoothAdapter.startDiscovery();
+ }
+
+ @Rpc(description = "Bond to a specified device once it's discovered.",
+ returns = "Whether discovery started successfully. ")
+ public Boolean bluetoothDiscoverAndBond(
+ @RpcParameter(name = "device",
+ description = "Name or MAC address of a bluetooth device.")
+ String deviceID) {
+ mBluetoothAdapter.cancelDiscovery();
+ if (listeningDevices.containsKey(deviceID)) {
+ Log.d("This device is already in the process of discovery and bonding.");
+ return false;
+ }
+ if (BluetoothFacade.deviceExists(mBluetoothAdapter.getBondedDevices(), deviceID)) {
+ Log.d("Device " + deviceID + " is already bonded.");
+ return false;
+ }
+ DiscoverConnectReceiver receiver = new DiscoverConnectReceiver(deviceID, true);
+ listeningDevices.put("Bond" + deviceID, receiver);
+ mService.registerReceiver(receiver, mDiscoverConnectFilter);
+ return mBluetoothAdapter.startDiscovery();
+ }
+
+ @Rpc(description = "Remove bond to a device.",
+ returns = "Whether the device was successfully unbonded.")
+ public Boolean bluetoothUnbond(
+ @RpcParameter(name = "device",
+ description = "Name or MAC address of a bluetooth device.")
+ String device) throws Exception {
+ BluetoothDevice mDevice = BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(),
+ device);
+ return mDevice.removeBond();
+ }
+
+ @Rpc(description = "Connect to a device that is already bonded.")
+ public void bluetoothConnectBonded(
+ @RpcParameter(name = "device",
+ description = "Name or MAC address of a bluetooth device.")
+ String device) throws Exception {
+ BluetoothDevice mDevice = BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(),
+ device);
+ connectProfile(mDevice, device);
+ }
+
@Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(BluetoothDevice.ACTION_FOUND)) {
- BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- if(mDeviceID.equals(device.getAliasName()) || mDeviceID.equals(device.getAddress())) {
- Log.d("Found device " + device.getAliasName() + " for connection.");
- mBluetoothAdapter.cancelDiscovery();
- mDevice = device;
- }
- }else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
- if(mBond) {
- Log.d("Bond with " + mDevice.getAliasName());
- if (!mDevice.createBond()) {
- Log.e("Failed to bond with " + mDevice.getAliasName());
- }
- mService.unregisterReceiver(this);
- }else{
- Log.d("Discovery finished, start fetching UUIDs.");
- mDevice.fetchUuidsWithSdp();
- }
- }else if (action.equals(BluetoothDevice.ACTION_UUID)) {
- BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- if(mDeviceID.equals(device.getAliasName()) || mDeviceID.equals(device.getAddress())) {
- connectProfile(device, mDeviceID);
- }
- }
+ public void shutdown() {
}
- }
-
- private void connectProfile(BluetoothDevice device, String deviceID) {
- ParcelUuid[] deviceUuids = device.getUuids();
- Log.d("Device uuid is " + deviceUuids);
- mService.registerReceiver(mPairingHelper, mPairingFilter);
- if (BluetoothUuid.containsAnyUuid(SINK_UUIDS, deviceUuids)) {
- Log.d("Connecting to " + device.getAliasName());
- boolean status = mA2dpProfile.a2dpConnect(device);
- Log.d("Status " + status);
- if(status) {
- Log.d("Posting event.");
- Bundle mResults = new Bundle();
- mEventFacade.postEvent("A2dpConnected" + deviceID, mResults);
- }
- }
- if (BluetoothUuid.containsAnyUuid(HSP_UUIDS, deviceUuids)) {
- boolean status = mHspProfile.hspConnect(device);
- if(status) {
- Log.d("Posting event.");
- Bundle mResults = new Bundle();
- mEventFacade.postEvent("HspConnected" + deviceID, mResults);
- }
- }
- mService.unregisterReceiver(listeningDevices.remove(deviceID));
- mService.unregisterReceiver(mPairingHelper);
- }
-
- @Rpc(description = "Connect to a specified device once it's discovered.",
- returns = "Whether discovery started successfully.")
- public Boolean bluetoothDiscoverAndConnect(
- @RpcParameter(
- name = "device",
- description = "Name or MAC address of a bluetooth device.")
- String device) {
- if (listeningDevices.containsKey(device)) {
- Log.d("This device is already in the process of discovery and connecting.");
- return false;
- }
- DiscoverConnectReceiver receiver = new DiscoverConnectReceiver(device);
- listeningDevices.put(device, receiver);
- mService.registerReceiver(receiver, mDiscoverConnectFilter);
- return mBluetoothAdapter.startDiscovery();
- }
-
- @Rpc(description = "Bond to a specified device once it's discovered.",
- returns = "Whether discovery started successfully. ")
- public Boolean bluetoothDiscoverAndBond(
- @RpcParameter(
- name = "device",
- description = "Name or MAC address of a bluetooth device.")
- String device) {
- if (listeningDevices.containsKey(device)) {
- Log.d("This device is already in the process of discovery and bonding.");
- return false;
- }
- DiscoverConnectReceiver receiver = new DiscoverConnectReceiver(device, true);
- listeningDevices.put(device, receiver);
- mService.registerReceiver(receiver, mDiscoverConnectFilter);
- return mBluetoothAdapter.startDiscovery();
- }
-
- @Rpc(description = "Remove bond to a device.",
- returns = "Whether the device was successfully unbonded.")
- public Boolean bluetoothUnbond(
- @RpcParameter(
- name = "device",
- description = "Name or MAC address of a bluetooth device.")
- String device) throws Exception {
- BluetoothDevice mDevice =
- BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(), device);
- return mDevice.removeBond();
- }
-
- @Rpc(description = "Connect to a device that is already bonded.")
- public void bluetoothConnectBonded(
- @RpcParameter(
- name = "device",
- description = "Name or MAC address of a bluetooth device.")
- String device) throws Exception {
- BluetoothDevice mDevice =
- BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(), device);
- connectProfile(mDevice, device);
- }
-
- @Override
- public void shutdown() {
- }
}
diff --git a/Common/src/com/googlecode/android_scripting/bluetooth/BluetoothFacade.java b/Common/src/com/googlecode/android_scripting/bluetooth/BluetoothFacade.java
index 1f2293e..1d6edf5 100644
--- a/Common/src/com/googlecode/android_scripting/bluetooth/BluetoothFacade.java
+++ b/Common/src/com/googlecode/android_scripting/bluetooth/BluetoothFacade.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Google Inc.
+ * Copyright (C) 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -23,10 +23,12 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.Bundle;
import android.os.ParcelUuid;
import com.googlecode.android_scripting.Log;
import com.googlecode.android_scripting.MainThread;
+import com.googlecode.android_scripting.facade.EventFacade;
import com.googlecode.android_scripting.facade.FacadeManager;
import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
import com.googlecode.android_scripting.rpc.Rpc;
@@ -44,207 +46,232 @@
/**
* Basic Bluetooth functions.
- *
*/
@RpcMinSdk(5)
public class BluetoothFacade extends RpcReceiver {
- private final Service mService;
- private final BroadcastReceiver mDiscoveryReceiver;
- private final IntentFilter discoveryFilter;
- private Map<String, BluetoothConnection>
- connections = new HashMap<String, BluetoothConnection>();
- private BluetoothAdapter mBluetoothAdapter;
+ private final Service mService;
+ private final BroadcastReceiver mDiscoveryReceiver;
+ private final IntentFilter discoveryFilter;
+ private final EventFacade mEventFacade;
+ private Map<String, BluetoothConnection> connections =
+ new HashMap<String, BluetoothConnection>();
+ private BluetoothAdapter mBluetoothAdapter;
- public static ConcurrentHashMap<String, BluetoothDevice> DiscoveredDevices;
+ public static ConcurrentHashMap<String, BluetoothDevice> DiscoveredDevices;
- public BluetoothFacade(FacadeManager manager) {
- super(manager);
- mBluetoothAdapter = MainThread.run(manager.getService(), new Callable<BluetoothAdapter>() {
- @Override
- public BluetoothAdapter call() throws Exception {
- return BluetoothAdapter.getDefaultAdapter();
- }
- });
- mService = manager.getService();
+ public BluetoothFacade(FacadeManager manager) {
+ super(manager);
+ mBluetoothAdapter = MainThread.run(manager.getService(), new Callable<BluetoothAdapter>() {
+ @Override
+ public BluetoothAdapter call() throws Exception {
+ return BluetoothAdapter.getDefaultAdapter();
+ }
+ });
+ mEventFacade = manager.getReceiver(EventFacade.class);
+ mService = manager.getService();
- DiscoveredDevices = new ConcurrentHashMap<String, BluetoothDevice>();
- discoveryFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
- mDiscoveryReceiver = new DiscoveryCacheReceiver();
- }
+ DiscoveredDevices = new ConcurrentHashMap<String, BluetoothDevice>();
+ discoveryFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
+ discoveryFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
+ mDiscoveryReceiver = new DiscoveryCacheReceiver();
+ }
- class DiscoveryCacheReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(BluetoothDevice.ACTION_FOUND)) {
- BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- Log.d("Found device " + device.getAliasName());
- if (!DiscoveredDevices.containsKey(device.getAddress())) {
- String name = device.getAliasName();
- if(name != null) {
- DiscoveredDevices.put(device.getAliasName(), device);
- }
- DiscoveredDevices.put(device.getAddress(), device);
+ class DiscoveryCacheReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(BluetoothDevice.ACTION_FOUND)) {
+ BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ Log.d("Found device " + device.getAliasName());
+ if (!DiscoveredDevices.containsKey(device.getAddress())) {
+ String name = device.getAliasName();
+ if (name != null) {
+ DiscoveredDevices.put(device.getAliasName(), device);
+ }
+ DiscoveredDevices.put(device.getAddress(), device);
+ }
+ } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
+ mEventFacade.postEvent("BluetoothDiscoveryFinished", new Bundle());
+ mService.unregisterReceiver(mDiscoveryReceiver);
+ }
}
- }
}
- }
- public static <T> BluetoothDevice getDevice(ConcurrentHashMap<String, T> devices,
- String device)throws Exception {
- if(devices.containsKey(device)) {
- return (BluetoothDevice) devices.get(device);
- }else{
- throw new Exception("Can't find device " + device);
+ public static boolean deviceMatch(BluetoothDevice device, String deviceID) {
+ return deviceID.equals(device.getAliasName()) || deviceID.equals(device.getAddress());
}
- }
- public static BluetoothDevice getDevice(Collection<BluetoothDevice> devices,
- String deviceID) throws Exception {
- for(BluetoothDevice bd : devices) {
- if (deviceID.equals(bd.getAliasName()) || deviceID.equals(bd.getAddress())) {
- Log.d("Found match " + bd.getAliasName() + " " + bd.getAddress());
- return bd;
- }
+ public static <T> BluetoothDevice getDevice(ConcurrentHashMap<String, T> devices, String device)
+ throws Exception {
+ if (devices.containsKey(device)) {
+ return (BluetoothDevice) devices.get(device);
+ } else {
+ throw new Exception("Can't find device " + device);
+ }
}
- throw new Exception("Can't find device " + deviceID);
- }
- @Rpc(description = "Requests that the device be discoverable for Bluetooth connections.")
- public void bluetoothMakeDiscoverable(
- @RpcParameter(name = "duration",
- description = "period of time, in seconds, during which the device should be discoverable")
- @RpcDefault("300")
- Integer duration) {
- Log.d("Making discoverable for "+duration+" seconds.\n");
- mBluetoothAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, duration);
- }
-
- @Rpc(description = "Requests that the device be not discoverable.")
- public void bluetoothMakeUndiscoverable() {
- Log.d("Making undiscoverable\n");
- mBluetoothAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_NONE);
- }
-
- @Rpc(description = "Queries a remote device for it's name or null if it can't be resolved")
- public String bluetoothGetRemoteDeviceName(
- @RpcParameter(name = "address", description = "Bluetooth Address For Target Device")
- String address) {
- try {
- BluetoothDevice mDevice;
- mDevice = mBluetoothAdapter.getRemoteDevice(address);
- return mDevice.getName();
- } catch (Exception e) {
- return null;
+ public static BluetoothDevice getDevice(Collection<BluetoothDevice> devices, String deviceID)
+ throws Exception {
+ Log.d("Looking for " + deviceID);
+ for (BluetoothDevice bd : devices) {
+ Log.d(bd.getAliasName() + " " + bd.getAddress());
+ if (deviceMatch(bd, deviceID)) {
+ Log.d("Found match " + bd.getAliasName() + " " + bd.getAddress());
+ return bd;
+ }
+ }
+ throw new Exception("Can't find device " + deviceID);
}
- }
- @Rpc(description = "Get local Bluetooth device name")
- public String bluetoothGetLocalName() {
- return mBluetoothAdapter.getName();
- }
-
- @Rpc(description = "Returns the hardware address of the local Bluetooth adapter. ")
- public String bluetoothGetLocalAddress() {
- return mBluetoothAdapter.getAddress();
- }
-
- @Rpc(description = "Returns the UUIDs supported by local Bluetooth adapter.")
- public ParcelUuid[] bluetoothGetLocalUuids() {
- return mBluetoothAdapter.getUuids();
- }
-
- @Rpc(description = "Gets the scan mode for the local dongle.\r\n" + "Return values:\r\n"
- + "\t-1 when Bluetooth is disabled.\r\n" + "\t0 if non discoverable and non connectable.\r\n"
- + "\r1 connectable non discoverable." + "\r3 connectable and discoverable.")
- public int bluetoothGetScanMode() {
- if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF
- || mBluetoothAdapter.getState() == BluetoothAdapter.STATE_TURNING_OFF) {
- return -1;
+ public static boolean deviceExists(Collection<BluetoothDevice> devices, String deviceID) {
+ for (BluetoothDevice bd : devices) {
+ if (deviceMatch(bd, deviceID)) {
+ Log.d("Found match " + bd.getAliasName() + " " + bd.getAddress());
+ return true;
+ }
+ }
+ return false;
}
- switch (mBluetoothAdapter.getScanMode()) {
- case BluetoothAdapter.SCAN_MODE_NONE:
- return 0;
- case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
- return 1;
- case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
- return 3;
- default:
- return mBluetoothAdapter.getScanMode() - 20;
+
+ @Rpc(description = "Requests that the device be discoverable for Bluetooth connections.")
+ public void bluetoothMakeDiscoverable(
+ @RpcParameter(name = "duration",
+ description = "period of time, in seconds,"
+ + "during which the device should be discoverable")
+ @RpcDefault("300")
+ Integer duration) {
+ Log.d("Making discoverable for " + duration + " seconds.\n");
+ mBluetoothAdapter
+ .setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, duration);
}
- }
- @Rpc(description = "Return the set of BluetoothDevice that are paired to the local adapter.")
- public Set<BluetoothDevice> bluetoothGetBondedDevices() {
- return mBluetoothAdapter.getBondedDevices();
- }
-
- @Rpc(description = "Checks Bluetooth state.", returns = "True if Bluetooth is enabled.")
- public Boolean bluetoothCheckState() {
- return mBluetoothAdapter.isEnabled();
- }
-
- @Rpc(description = "Sets the Bluetooth visible device name", returns = "true on success")
- public boolean bluetoothSetLocalName(
- @RpcParameter(name = "name", description = "New local name") String name) {
- return mBluetoothAdapter.setName(name);
- }
-
- @Rpc(description = "Toggle Bluetooth on and off.", returns = "True if Bluetooth is enabled.")
- public Boolean bluetoothToggleState(
- @RpcParameter(name = "enabled") @RpcOptional
- Boolean enabled,
- @RpcParameter(name = "prompt",
- description = "Prompt the user to confirm changing the Bluetooth state.")
- @RpcDefault("false")
- Boolean prompt
- ) {
- if (enabled == null) {
- enabled = !bluetoothCheckState();
+ @Rpc(description = "Requests that the device be not discoverable.")
+ public void bluetoothMakeUndiscoverable() {
+ Log.d("Making undiscoverable\n");
+ mBluetoothAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_NONE);
}
- if (enabled) {
- // TODO(damonkohler): Make this synchronous as well.
- mBluetoothAdapter.enable();
- } else {
- // TODO(damonkohler): Add support for prompting on disable.
- // TODO(damonkohler): Make this synchronous as well.
- shutdown();
- mBluetoothAdapter.disable();
+
+ @Rpc(description = "Queries a remote device for it's name or null if it can't be resolved")
+ public String bluetoothGetRemoteDeviceName(
+ @RpcParameter(name = "address", description = "Bluetooth Address For Target Device")
+ String address) {
+ try {
+ BluetoothDevice mDevice;
+ mDevice = mBluetoothAdapter.getRemoteDevice(address);
+ return mDevice.getName();
+ } catch (Exception e) {
+ return null;
+ }
}
- return enabled;
- }
- @Rpc(description = "Start the remote device discovery process. ",
- returns = "true on success, false on error")
- public Boolean bluetoothStartDiscovery() {
- mService.registerReceiver(mDiscoveryReceiver, discoveryFilter);
- return mBluetoothAdapter.startDiscovery();
- }
-
- @Rpc(description = "Cancel the current device discovery process.",
- returns = "true on success, false on error")
- public Boolean bluetoothCancelDiscovery() {
- mService.unregisterReceiver(mDiscoveryReceiver);
- return mBluetoothAdapter.cancelDiscovery();
- }
-
- @Rpc(description =
- "If the local Bluetooth adapter is currently in the device discovery process.")
- public Boolean bluetoothIsDiscovering() {
- return mBluetoothAdapter.isDiscovering();
- }
-
- @Rpc(description = "Get all the discovered bluetooth devices.")
- public Collection<BluetoothDevice> bluetoothGetDiscoveredDevices() {
- while(bluetoothIsDiscovering());
- return DiscoveredDevices.values();
- }
-
- @Override
- public void shutdown() {
- for (Map.Entry<String, BluetoothConnection> entry : connections.entrySet()) {
- entry.getValue().stop();
+ @Rpc(description = "Get local Bluetooth device name")
+ public String bluetoothGetLocalName() {
+ return mBluetoothAdapter.getName();
}
- connections.clear();
- }
+
+ @Rpc(description = "Returns the hardware address of the local Bluetooth adapter. ")
+ public String bluetoothGetLocalAddress() {
+ return mBluetoothAdapter.getAddress();
+ }
+
+ @Rpc(description = "Returns the UUIDs supported by local Bluetooth adapter.")
+ public ParcelUuid[] bluetoothGetLocalUuids() {
+ return mBluetoothAdapter.getUuids();
+ }
+
+ @Rpc(description = "Gets the scan mode for the local dongle.\r\n" + "Return values:\r\n"
+ + "\t-1 when Bluetooth is disabled.\r\n"
+ + "\t0 if non discoverable and non connectable.\r\n"
+ + "\r1 connectable non discoverable." + "\r3 connectable and discoverable.")
+ public int bluetoothGetScanMode() {
+ if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF
+ || mBluetoothAdapter.getState() == BluetoothAdapter.STATE_TURNING_OFF) {
+ return -1;
+ }
+ switch (mBluetoothAdapter.getScanMode()) {
+ case BluetoothAdapter.SCAN_MODE_NONE:
+ return 0;
+ case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
+ return 1;
+ case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
+ return 3;
+ default:
+ return mBluetoothAdapter.getScanMode() - 20;
+ }
+ }
+
+ @Rpc(description = "Return the set of BluetoothDevice that are paired to the local adapter.")
+ public Set<BluetoothDevice> bluetoothGetBondedDevices() {
+ return mBluetoothAdapter.getBondedDevices();
+ }
+
+ @Rpc(description = "Checks Bluetooth state.", returns = "True if Bluetooth is enabled.")
+ public Boolean bluetoothCheckState() {
+ return mBluetoothAdapter.isEnabled();
+ }
+
+ @Rpc(description = "Sets the Bluetooth visible device name", returns = "true on success")
+ public boolean bluetoothSetLocalName(@RpcParameter(name = "name",
+ description = "New local name")
+ String name) {
+ return mBluetoothAdapter.setName(name);
+ }
+
+ @Rpc(description = "Toggle Bluetooth on and off.", returns = "True if Bluetooth is enabled.")
+ public Boolean bluetoothToggleState(@RpcParameter(name = "enabled")
+ @RpcOptional
+ Boolean enabled,
+ @RpcParameter(name = "prompt",
+ description = "Prompt the user to confirm changing the Bluetooth state.")
+ @RpcDefault("false")
+ Boolean prompt) {
+ if (enabled == null) {
+ enabled = !bluetoothCheckState();
+ }
+ if (enabled) {
+ // TODO(damonkohler): Make this synchronous as well.
+ mBluetoothAdapter.enable();
+ } else {
+ // TODO(damonkohler): Add support for prompting on disable.
+ // TODO(damonkohler): Make this synchronous as well.
+ shutdown();
+ mBluetoothAdapter.disable();
+ }
+ return enabled;
+ }
+
+ @Rpc(description = "Start the remote device discovery process. ",
+ returns = "true on success, false on error")
+ public Boolean bluetoothStartDiscovery() {
+ mService.registerReceiver(mDiscoveryReceiver, discoveryFilter);
+ return mBluetoothAdapter.startDiscovery();
+ }
+
+ @Rpc(description = "Cancel the current device discovery process.",
+ returns = "true on success, false on error")
+ public Boolean bluetoothCancelDiscovery() {
+ mService.unregisterReceiver(mDiscoveryReceiver);
+ return mBluetoothAdapter.cancelDiscovery();
+ }
+
+ @Rpc(description = "If the local Bluetooth adapter is currently"
+ + "in the device discovery process.")
+ public Boolean bluetoothIsDiscovering() {
+ return mBluetoothAdapter.isDiscovering();
+ }
+
+ @Rpc(description = "Get all the discovered bluetooth devices.")
+ public Collection<BluetoothDevice> bluetoothGetDiscoveredDevices() {
+ while (bluetoothIsDiscovering())
+ ;
+ return DiscoveredDevices.values();
+ }
+
+ @Override
+ public void shutdown() {
+ for (Map.Entry<String, BluetoothConnection> entry : connections.entrySet()) {
+ entry.getValue().stop();
+ }
+ connections.clear();
+ }
}
diff --git a/Common/src/com/googlecode/android_scripting/bluetooth/BluetoothHspFacade.java b/Common/src/com/googlecode/android_scripting/bluetooth/BluetoothHspFacade.java
index 2e87b09..2b35e90 100644
--- a/Common/src/com/googlecode/android_scripting/bluetooth/BluetoothHspFacade.java
+++ b/Common/src/com/googlecode/android_scripting/bluetooth/BluetoothHspFacade.java
@@ -1,5 +1,7 @@
package com.googlecode.android_scripting.bluetooth;
+import java.util.List;
+
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
@@ -14,12 +16,9 @@
import com.googlecode.android_scripting.rpc.Rpc;
import com.googlecode.android_scripting.rpc.RpcParameter;
-
public class BluetoothHspFacade extends RpcReceiver {
- static final ParcelUuid[] HSP_UUIDS = {
- BluetoothUuid.HSP,
- BluetoothUuid.Handsfree,
- };
+ static final ParcelUuid[] HSP_UUIDS = { BluetoothUuid.HSP,
+ BluetoothUuid.Handsfree, };
private final Service mService;
private final BluetoothAdapter mBluetoothAdapter;
@@ -31,7 +30,8 @@
super(manager);
mService = manager.getService();
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- mBluetoothAdapter.getProfileProxy(mService, new HspServiceListener(), BluetoothProfile.HEADSET);
+ mBluetoothAdapter.getProfileProxy(mService, new HspServiceListener(),
+ BluetoothProfile.HEADSET);
}
class HspServiceListener implements BluetoothProfile.ServiceListener {
@@ -40,6 +40,7 @@
mHspProfile = (BluetoothHeadset) proxy;
mIsHspReady = true;
}
+
@Override
public void onServiceDisconnected(int profile) {
mIsHspReady = false;
@@ -57,34 +58,41 @@
return mHspProfile.disconnect(device);
}
- @Rpc(description="Is Hsp profile ready.")
+ @Rpc(description = "Is Hsp profile ready.")
public Boolean bluetoothHspIsReady() {
return mIsHspReady;
}
- @Rpc(description="Connect to HSP device.")
+ @Rpc(description = "Connect to HSP device.")
public Boolean bluetoothHspConnect(
- @RpcParameter(
- name = "device",
- description = "Name or MAC address of a bluetooth device.")
- String device) throws Exception {
- if (mHspProfile == null) return false;
- BluetoothDevice mDevice = BluetoothFacade.getDevice(BluetoothFacade.DiscoveredDevices, device);
+ @RpcParameter(name = "device", description = "Name or MAC address of a bluetooth device.")
+ String device)
+ throws Exception {
+ if (mHspProfile == null)
+ return false;
+ BluetoothDevice mDevice = BluetoothFacade.getDevice(
+ BluetoothFacade.DiscoveredDevices, device);
Log.d("Connecting to device " + mDevice.getAliasName());
return hspConnect(mDevice);
}
- @Rpc(description="Disconnect an HSP device.")
+ @Rpc(description = "Disconnect an HSP device.")
public Boolean bluetoothHspDisconnect(
- @RpcParameter(
- name = "device",
- description = "Name or MAC address of a bluetooth device.")
- String device) throws Exception {
- if (mHspProfile == null) return false;
- BluetoothDevice mDevice = BluetoothFacade.getDevice(mHspProfile.getConnectedDevices(), device);
+ @RpcParameter(name = "device", description = "Name or MAC address of a bluetooth device.")
+ String device)
+ throws Exception {
+ if (mHspProfile == null)
+ return false;
+ BluetoothDevice mDevice = BluetoothFacade.getDevice(
+ mHspProfile.getConnectedDevices(), device);
return hspDisconnect(mDevice);
}
+ @Rpc(description = "Return the list of devices connected through Hsp.")
+ public List<BluetoothDevice> bluetoothHspGetConnectedDevices() {
+ return mHspProfile.getConnectedDevices();
+ }
+
@Override
public void shutdown() {
}
diff --git a/Common/src/com/googlecode/android_scripting/facade/MediaPlayerFacade.java b/Common/src/com/googlecode/android_scripting/facade/MediaPlayerFacade.java
index 6468925..2fbebb1 100644
--- a/Common/src/com/googlecode/android_scripting/facade/MediaPlayerFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/MediaPlayerFacade.java
@@ -108,7 +108,7 @@
}
@Rpc(description = "Open a media file", returns = "true if play successful")
- public synchronized boolean mediaPlay(
+ public synchronized boolean mediaPlayOpen(
@RpcParameter(name = "url", description = "url of media resource") String url,
@RpcParameter(name = "tag", description = "string identifying resource") @RpcDefault(value = "default") String tag,
@RpcParameter(name = "play", description = "start playing immediately") @RpcDefault(value = "true") Boolean play) {