From 6f092344f5bebfdc1fc6a67761e7db1f93ccb4ab Mon Sep 17 00:00:00 2001 From: Alexandros Schillings Date: Wed, 31 Aug 2016 19:56:09 +0100 Subject: [PATCH] Fixed CSV sharing --- .../containers/BluetoothLeDeviceStore.java | 128 -------------- .../alt236/btlescan/ui/common/Navigation.java | 16 ++ .../{util => ui/main}/CsvWriterHelper.java | 4 +- .../alt236/btlescan/ui/main/MainActivity.java | 2 +- .../uk/co/alt236/btlescan/ui/main/Sharer.java | 161 ++++++++++++++++++ sample_app/src/main/res/values/strings.xml | 1 + 6 files changed, 181 insertions(+), 131 deletions(-) rename sample_app/src/main/java/uk/co/alt236/btlescan/{util => ui/main}/CsvWriterHelper.java (88%) create mode 100644 sample_app/src/main/java/uk/co/alt236/btlescan/ui/main/Sharer.java diff --git a/sample_app/src/main/java/uk/co/alt236/btlescan/containers/BluetoothLeDeviceStore.java b/sample_app/src/main/java/uk/co/alt236/btlescan/containers/BluetoothLeDeviceStore.java index 8b99033..acc0820 100644 --- a/sample_app/src/main/java/uk/co/alt236/btlescan/containers/BluetoothLeDeviceStore.java +++ b/sample_app/src/main/java/uk/co/alt236/btlescan/containers/BluetoothLeDeviceStore.java @@ -1,28 +1,13 @@ package uk.co.alt236.btlescan.containers; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice; -import uk.co.alt236.bluetoothlelib.device.beacon.BeaconType; -import uk.co.alt236.bluetoothlelib.device.beacon.BeaconUtils; -import uk.co.alt236.bluetoothlelib.device.beacon.ibeacon.IBeaconDevice; -import uk.co.alt236.bluetoothlelib.util.ByteUtils; -import uk.co.alt236.btlescan.R; -import uk.co.alt236.btlescan.util.CsvWriterHelper; -import uk.co.alt236.btlescan.util.TimeFormatter; import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor; public class BluetoothLeDeviceStore { @@ -65,117 +50,4 @@ public class BluetoothLeDeviceStore { return methodResult; } - - private String getListAsCsv() { - final List list = getDeviceList(); - final StringBuilder sb = new StringBuilder(); - sb.append(CsvWriterHelper.addStuff("mac")); - sb.append(CsvWriterHelper.addStuff("name")); - sb.append(CsvWriterHelper.addStuff("firstTimestamp")); - sb.append(CsvWriterHelper.addStuff("firstRssi")); - sb.append(CsvWriterHelper.addStuff("currentTimestamp")); - sb.append(CsvWriterHelper.addStuff("currentRssi")); - sb.append(CsvWriterHelper.addStuff("adRecord")); - sb.append(CsvWriterHelper.addStuff("iBeacon")); - sb.append(CsvWriterHelper.addStuff("uuid")); - sb.append(CsvWriterHelper.addStuff("major")); - sb.append(CsvWriterHelper.addStuff("minor")); - sb.append(CsvWriterHelper.addStuff("txPower")); - sb.append(CsvWriterHelper.addStuff("distance")); - sb.append(CsvWriterHelper.addStuff("accuracy")); - sb.append('\n'); - - for (final BluetoothLeDevice device : list) { - sb.append(CsvWriterHelper.addStuff(device.getAddress())); - sb.append(CsvWriterHelper.addStuff(device.getName())); - sb.append(CsvWriterHelper.addStuff(TimeFormatter.getIsoDateTime(device.getFirstTimestamp()))); - sb.append(CsvWriterHelper.addStuff(device.getFirstRssi())); - sb.append(CsvWriterHelper.addStuff(TimeFormatter.getIsoDateTime(device.getTimestamp()))); - sb.append(CsvWriterHelper.addStuff(device.getRssi())); - sb.append(CsvWriterHelper.addStuff(ByteUtils.byteArrayToHexString(device.getScanRecord()))); - final boolean isIBeacon = BeaconUtils.getBeaconType(device) == BeaconType.IBEACON; - final String uuid; - final String minor; - final String major; - final String txPower; - final String distance; - final String accuracy; - - if (isIBeacon) { - final IBeaconDevice beacon = new IBeaconDevice(device); - uuid = String.valueOf(beacon.getUUID()); - minor = String.valueOf(beacon.getMinor()); - major = String.valueOf(beacon.getMajor()); - txPower = String.valueOf(beacon.getCalibratedTxPower()); - distance = beacon.getDistanceDescriptor().toString().toLowerCase(Locale.US); - accuracy = String.valueOf(beacon.getAccuracy()); - } else { - uuid = ""; - minor = ""; - major = ""; - txPower = ""; - distance = ""; - accuracy = ""; - } - - sb.append(CsvWriterHelper.addStuff(isIBeacon)); - sb.append(CsvWriterHelper.addStuff(uuid)); - sb.append(CsvWriterHelper.addStuff(minor)); - sb.append(CsvWriterHelper.addStuff(major)); - sb.append(CsvWriterHelper.addStuff(txPower)); - sb.append(CsvWriterHelper.addStuff(distance)); - sb.append(CsvWriterHelper.addStuff(accuracy)); - - sb.append('\n'); - } - - return sb.toString(); - } - - public void shareDataAsEmail(final Context context) { - final long timeInMillis = System.currentTimeMillis(); - - final String to = null; - final String subject = context.getString( - R.string.exporter_email_device_list_subject, - TimeFormatter.getIsoDateTime(timeInMillis)); - - final String message = context.getString(R.string.exporter_email_device_list_body); - - final Intent i = new Intent(Intent.ACTION_SEND); - i.setType("plain/text"); - try { - final File outputDir = context.getCacheDir(); - final File outputFile = File.createTempFile("bluetooth_le_" + timeInMillis, ".csv", outputDir); - outputFile.setReadable(true, false); - generateFile(outputFile, getListAsCsv()); - i.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(outputFile)); - i.putExtra(Intent.EXTRA_EMAIL, new String[]{to}); - i.putExtra(Intent.EXTRA_SUBJECT, subject); - i.putExtra(Intent.EXTRA_TEXT, message); - context.startActivity(Intent.createChooser(i, context.getString(R.string.exporter_email_device_list_picker_text))); - - } catch (final IOException e) { - e.printStackTrace(); - } - } - - private static FileWriter generateFile(final File file, final String contents) { - FileWriter writer = null; - try { - writer = new FileWriter(file); - writer.append(contents); - writer.flush(); - - } catch (final IOException e) { - e.printStackTrace(); - } finally { - try { - writer.close(); - } catch (final IOException e) { - e.printStackTrace(); - } - } - return writer; - } } diff --git a/sample_app/src/main/java/uk/co/alt236/btlescan/ui/common/Navigation.java b/sample_app/src/main/java/uk/co/alt236/btlescan/ui/common/Navigation.java index bae79c3..95846d6 100644 --- a/sample_app/src/main/java/uk/co/alt236/btlescan/ui/common/Navigation.java +++ b/sample_app/src/main/java/uk/co/alt236/btlescan/ui/common/Navigation.java @@ -2,9 +2,11 @@ package uk.co.alt236.btlescan.ui.common; import android.app.Activity; import android.content.Intent; +import android.net.Uri; import android.support.v4.app.ActivityCompat; import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice; +import uk.co.alt236.btlescan.R; import uk.co.alt236.btlescan.ui.control.DeviceControlActivity; import uk.co.alt236.btlescan.ui.details.DeviceDetailsActivity; @@ -28,6 +30,20 @@ public class Navigation { startActivity(intent); } + public void shareFileViaEmail(final Uri fileUri, final String[] recipient, final String subject, final String message) { + final Intent intent = new Intent(Intent.ACTION_SEND); + + intent.setType("plain/text"); + intent.putExtra(Intent.EXTRA_STREAM, fileUri); + intent.putExtra(Intent.EXTRA_EMAIL, recipient); + intent.putExtra(Intent.EXTRA_SUBJECT, subject); + intent.putExtra(Intent.EXTRA_TEXT, message); + + startActivity(Intent.createChooser(intent, + mActivity.getString(R.string.exporter_email_device_list_picker_text))); + } + + private void startActivity(final Intent intent) { ActivityCompat.startActivity(mActivity, intent, null); } diff --git a/sample_app/src/main/java/uk/co/alt236/btlescan/util/CsvWriterHelper.java b/sample_app/src/main/java/uk/co/alt236/btlescan/ui/main/CsvWriterHelper.java similarity index 88% rename from sample_app/src/main/java/uk/co/alt236/btlescan/util/CsvWriterHelper.java rename to sample_app/src/main/java/uk/co/alt236/btlescan/ui/main/CsvWriterHelper.java index f8bff7d..c73b4c7 100644 --- a/sample_app/src/main/java/uk/co/alt236/btlescan/util/CsvWriterHelper.java +++ b/sample_app/src/main/java/uk/co/alt236/btlescan/ui/main/CsvWriterHelper.java @@ -1,6 +1,6 @@ -package uk.co.alt236.btlescan.util; +package uk.co.alt236.btlescan.ui.main; -public class CsvWriterHelper { +/*package*/ class CsvWriterHelper { private static final String QUOTE = "\""; public static String addStuff(final Integer text) { diff --git a/sample_app/src/main/java/uk/co/alt236/btlescan/ui/main/MainActivity.java b/sample_app/src/main/java/uk/co/alt236/btlescan/ui/main/MainActivity.java index b6b4668..9b34960 100644 --- a/sample_app/src/main/java/uk/co/alt236/btlescan/ui/main/MainActivity.java +++ b/sample_app/src/main/java/uk/co/alt236/btlescan/ui/main/MainActivity.java @@ -132,7 +132,7 @@ public class MainActivity extends AppCompatActivity implements AdapterView.OnIte DialogFactory.createAboutDialog(this).show(); break; case R.id.menu_share: - mDeviceStore.shareDataAsEmail(this); + new Sharer().shareDataAsEmail(this, mDeviceStore); } return true; } diff --git a/sample_app/src/main/java/uk/co/alt236/btlescan/ui/main/Sharer.java b/sample_app/src/main/java/uk/co/alt236/btlescan/ui/main/Sharer.java new file mode 100644 index 0000000..0062c29 --- /dev/null +++ b/sample_app/src/main/java/uk/co/alt236/btlescan/ui/main/Sharer.java @@ -0,0 +1,161 @@ +package uk.co.alt236.btlescan.ui.main; + +import android.app.Activity; +import android.content.Context; +import android.net.Uri; +import android.support.v4.content.ContextCompat; +import android.widget.Toast; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; +import java.util.Locale; + +import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice; +import uk.co.alt236.bluetoothlelib.device.beacon.BeaconType; +import uk.co.alt236.bluetoothlelib.device.beacon.BeaconUtils; +import uk.co.alt236.bluetoothlelib.device.beacon.ibeacon.IBeaconDevice; +import uk.co.alt236.bluetoothlelib.util.ByteUtils; +import uk.co.alt236.btlescan.R; +import uk.co.alt236.btlescan.containers.BluetoothLeDeviceStore; +import uk.co.alt236.btlescan.ui.common.Navigation; +import uk.co.alt236.btlescan.util.TimeFormatter; + +/*package*/ class Sharer { + private static final String CSV_FILENAME_PREFIX = "bluetooth_le_%d"; + private static final String CSV_FILENAME_SUFFIX = ".csv"; + + private static File getExternalCacheDir(final Context context) { + final File[] files = ContextCompat.getExternalCacheDirs(context); + final File retVal; + + if (files == null || files.length == 0 || files[0] == null) { + retVal = null; + } else { + retVal = files[0]; + } + + return retVal; + } + + private static String getListAsCsv(List deviceList) { + + final StringBuilder sb = new StringBuilder(); + sb.append(CsvWriterHelper.addStuff("mac")); + sb.append(CsvWriterHelper.addStuff("name")); + sb.append(CsvWriterHelper.addStuff("firstTimestamp")); + sb.append(CsvWriterHelper.addStuff("firstRssi")); + sb.append(CsvWriterHelper.addStuff("currentTimestamp")); + sb.append(CsvWriterHelper.addStuff("currentRssi")); + sb.append(CsvWriterHelper.addStuff("adRecord")); + sb.append(CsvWriterHelper.addStuff("iBeacon")); + sb.append(CsvWriterHelper.addStuff("uuid")); + sb.append(CsvWriterHelper.addStuff("major")); + sb.append(CsvWriterHelper.addStuff("minor")); + sb.append(CsvWriterHelper.addStuff("txPower")); + sb.append(CsvWriterHelper.addStuff("distance")); + sb.append(CsvWriterHelper.addStuff("accuracy")); + sb.append('\n'); + + for (final BluetoothLeDevice device : deviceList) { + sb.append(CsvWriterHelper.addStuff(device.getAddress())); + sb.append(CsvWriterHelper.addStuff(device.getName())); + sb.append(CsvWriterHelper.addStuff(TimeFormatter.getIsoDateTime(device.getFirstTimestamp()))); + sb.append(CsvWriterHelper.addStuff(device.getFirstRssi())); + sb.append(CsvWriterHelper.addStuff(TimeFormatter.getIsoDateTime(device.getTimestamp()))); + sb.append(CsvWriterHelper.addStuff(device.getRssi())); + sb.append(CsvWriterHelper.addStuff(ByteUtils.byteArrayToHexString(device.getScanRecord()))); + final boolean isIBeacon = BeaconUtils.getBeaconType(device) == BeaconType.IBEACON; + final String uuid; + final String minor; + final String major; + final String txPower; + final String distance; + final String accuracy; + + if (isIBeacon) { + final IBeaconDevice beacon = new IBeaconDevice(device); + uuid = String.valueOf(beacon.getUUID()); + minor = String.valueOf(beacon.getMinor()); + major = String.valueOf(beacon.getMajor()); + txPower = String.valueOf(beacon.getCalibratedTxPower()); + distance = beacon.getDistanceDescriptor().toString().toLowerCase(Locale.US); + accuracy = String.valueOf(beacon.getAccuracy()); + } else { + uuid = ""; + minor = ""; + major = ""; + txPower = ""; + distance = ""; + accuracy = ""; + } + + sb.append(CsvWriterHelper.addStuff(isIBeacon)); + sb.append(CsvWriterHelper.addStuff(uuid)); + sb.append(CsvWriterHelper.addStuff(minor)); + sb.append(CsvWriterHelper.addStuff(major)); + sb.append(CsvWriterHelper.addStuff(txPower)); + sb.append(CsvWriterHelper.addStuff(distance)); + sb.append(CsvWriterHelper.addStuff(accuracy)); + + sb.append('\n'); + } + + return sb.toString(); + } + + private static FileWriter saveToFile(final File file, final String contents) { + FileWriter writer = null; + try { + writer = new FileWriter(file); + writer.append(contents); + writer.flush(); + + } catch (final IOException e) { + e.printStackTrace(); + } finally { + try { + if (writer != null) { + writer.close(); + } + } catch (final IOException e) { + e.printStackTrace(); + } + } + return writer; + } + + public void shareDataAsEmail(final Activity activity, + final BluetoothLeDeviceStore store) { + final long timeInMillis = System.currentTimeMillis(); + final String filename = String.format(Locale.US, CSV_FILENAME_PREFIX, timeInMillis); + + final String to = null; + final String subject = activity.getString( + R.string.exporter_email_device_list_subject, + TimeFormatter.getIsoDateTime(timeInMillis)); + + final String message = activity.getString(R.string.exporter_email_device_list_body); + + final String contents = getListAsCsv(store.getDeviceList()); + final File outputDir = getExternalCacheDir(activity); + + if (outputDir == null) { + Toast.makeText(activity, R.string.error_unable_to_access_external_storage, Toast.LENGTH_SHORT).show(); + } else { + try { + + final File outputFile = File.createTempFile(filename, CSV_FILENAME_SUFFIX, outputDir); + saveToFile(outputFile, contents); + + final Uri uri = Uri.fromFile(outputFile); + new Navigation(activity) + .shareFileViaEmail(uri, new String[]{to}, subject, message); + + } catch (final IOException e) { + e.printStackTrace(); + } + } + } +} diff --git a/sample_app/src/main/res/values/strings.xml b/sample_app/src/main/res/values/strings.xml index 17d8515..a6b422f 100644 --- a/sample_app/src/main/res/values/strings.xml +++ b/sample_app/src/main/res/values/strings.xml @@ -75,5 +75,6 @@ Updated: Descriptor: + "Could not access external storage!" The ACCESS_COARSE_LOCATION permission is needed to receive bluetooth scan results \ No newline at end of file