From 5858a6ece2d8368f6074cd05759490ed008bd4e9 Mon Sep 17 00:00:00 2001 From: Ang Li Date: Mon, 1 May 2017 21:05:41 -0700 Subject: Add Bluetooth Rpcs needed to support making the device discoverable. (#41) * Add Bluetooth Rpcs needed to support making the device discoverable. * Fix a bug in serializer; fix a typo in an Rpc name. Related to #8 --- .../snippet/bundled/BluetoothAdapterSnippet.java | 70 +++++++++++++++++++++- .../snippet/bundled/utils/JsonSerializer.java | 32 ++++++++-- 2 files changed, 97 insertions(+), 5 deletions(-) (limited to 'src/main/java/com/google/android') diff --git a/src/main/java/com/google/android/mobly/snippet/bundled/BluetoothAdapterSnippet.java b/src/main/java/com/google/android/mobly/snippet/bundled/BluetoothAdapterSnippet.java index a6e6dbb..7a0a15e 100644 --- a/src/main/java/com/google/android/mobly/snippet/bundled/BluetoothAdapterSnippet.java +++ b/src/main/java/com/google/android/mobly/snippet/bundled/BluetoothAdapterSnippet.java @@ -75,6 +75,11 @@ public class BluetoothAdapterSnippet implements Snippet { } } + @Rpc(description = "Return true if Bluetooth is enabled, false otherwise.") + public boolean btIsEnabled() { + return mBluetoothAdapter.isEnabled(); + } + @Rpc( description = "Get bluetooth discovery results, which is a list of serialized BluetoothDevice objects." @@ -87,12 +92,29 @@ public class BluetoothAdapterSnippet implements Snippet { return results; } + @Rpc(description = "Set the friendly Bluetooth name of the local Bluetooth adapter.") + public void btSetName(String name) throws BluetoothAdapterSnippetException { + if (!btIsEnabled()) { + throw new BluetoothAdapterSnippetException( + "Bluetooth is not enabled, cannot set Bluetooth name."); + } + if (!mBluetoothAdapter.setName(name)) { + throw new BluetoothAdapterSnippetException( + "Failed to set local Bluetooth name to " + name); + } + } + + @Rpc(description = "Get the friendly Bluetooth name of the local Bluetooth adapter.") + public String btGetName() { + return mBluetoothAdapter.getName(); + } + @Rpc( description = "Start discovery, wait for discovery to complete, and return results, which is a list of " + "serialized BluetoothDevice objects." ) - public JSONArray btDiscoveryAndGetResults() + public JSONArray btDiscoverAndGetResults() throws InterruptedException, JSONException, BluetoothAdapterSnippetException { IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); @@ -118,6 +140,52 @@ public class BluetoothAdapterSnippet implements Snippet { return btGetCachedScanResults(); } + @Rpc(description = "Become discoverable in Bluetooth.") + public void btBecomeDiscoverable(Integer duration) throws Throwable { + if (!btIsEnabled()) { + throw new BluetoothAdapterSnippetException( + "Bluetooth is not enabled, cannot become discoverable."); + } + boolean success; + try { + success = + (boolean) + mBluetoothAdapter + .getClass() + .getDeclaredMethod("setScanMode", int.class, int.class) + .invoke( + mBluetoothAdapter, + BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, + duration); + } catch (InvocationTargetException e) { + throw e.getCause(); + } + if (!success) { + throw new BluetoothAdapterSnippetException("Failed to become discoverable."); + } + } + + @Rpc(description = "Stop being discoverable in Bluetooth.") + public void btStopBeingDiscoverable() throws Throwable { + boolean success; + try { + success = + (boolean) + mBluetoothAdapter + .getClass() + .getDeclaredMethod("setScanMode", int.class, int.class) + .invoke( + mBluetoothAdapter, + BluetoothAdapter.SCAN_MODE_NONE, + 0 /* duration is not used for this */); + } catch (InvocationTargetException e) { + throw e.getCause(); + } + if (!success) { + throw new BluetoothAdapterSnippetException("Failed to stop being discoverable."); + } + } + @Rpc(description = "Get the list of paired bluetooth devices.") public JSONArray btGetPairedDevices() throws BluetoothAdapterSnippetException, InterruptedException, JSONException { diff --git a/src/main/java/com/google/android/mobly/snippet/bundled/utils/JsonSerializer.java b/src/main/java/com/google/android/mobly/snippet/bundled/utils/JsonSerializer.java index fc7d17b..bd00f45 100644 --- a/src/main/java/com/google/android/mobly/snippet/bundled/utils/JsonSerializer.java +++ b/src/main/java/com/google/android/mobly/snippet/bundled/utils/JsonSerializer.java @@ -109,13 +109,13 @@ public class JsonSerializer { private JSONObject serializeWifiConfiguration(WifiConfiguration data) throws JSONException { JSONObject result = new JSONObject(mGson.toJson(data)); result.put("Status", WifiConfiguration.Status.strings[data.status]); - result.put("SSID", trimQuotationMarks(data.SSID)); + guaranteedPut(result, "SSID", trimQuotationMarks(data.SSID)); return result; } private JSONObject serializeWifiInfo(WifiInfo data) throws JSONException { JSONObject result = new JSONObject(mGson.toJson(data)); - result.put("SSID", trimQuotationMarks(data.getSSID())); + guaranteedPut(result, "SSID", trimQuotationMarks(data.getSSID())); for (SupplicantState state : SupplicantState.values()) { if (data.getSupplicantState().equals(state)) { result.put("SupplicantState", state.name()); @@ -126,7 +126,7 @@ public class JsonSerializer { private JSONObject serializeBluetoothDevice(BluetoothDevice data) throws JSONException { JSONObject result = new JSONObject(); - result.put("Address", data.getAddress()); + guaranteedPut(result, "Address", data.getAddress()); final String bondStateFieldName = "BondState"; switch (data.getBondState()) { case BluetoothDevice.BOND_NONE: @@ -139,7 +139,7 @@ public class JsonSerializer { result.put(bondStateFieldName, "BOND_BONDED"); break; } - result.put("Name", data.getName()); + guaranteedPut(result, "Name", data.getName()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { final String deviceTypeFieldName = "DeviceType"; switch (data.getType()) { @@ -167,4 +167,28 @@ public class JsonSerializer { } return result; } + + /** + * Guarantees a field is put into a JSONObject even if it's null. + * + *

By default, if the object of {@link JSONObject#put(String, Object)} is null, the `put` + * method would either remove the field or do nothing, causing serialized objects to have + * inconsistent fields. + * + *

Use this method to put objects that may be null into the serialized JSONObject so the + * serialized objects have a consistent set of critical fields, like the SSID field in + * serialized WifiConfiguration objects. + * + * @param data + * @param name + * @param object + * @throws JSONException + */ + private void guaranteedPut(JSONObject data, String name, Object object) throws JSONException { + if (object == null) { + data.put(name, JSONObject.NULL); + } else { + data.put(name, object); + } + } } -- cgit v1.2.3