Fixed CSV sharing
This commit is contained in:
-128
@@ -1,28 +1,13 @@
|
|||||||
package uk.co.alt236.btlescan.containers;
|
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.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
|
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;
|
import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor;
|
||||||
|
|
||||||
public class BluetoothLeDeviceStore {
|
public class BluetoothLeDeviceStore {
|
||||||
@@ -65,117 +50,4 @@ public class BluetoothLeDeviceStore {
|
|||||||
|
|
||||||
return methodResult;
|
return methodResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getListAsCsv() {
|
|
||||||
final List<BluetoothLeDevice> 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ package uk.co.alt236.btlescan.ui.common;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
|
|
||||||
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
|
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.control.DeviceControlActivity;
|
||||||
import uk.co.alt236.btlescan.ui.details.DeviceDetailsActivity;
|
import uk.co.alt236.btlescan.ui.details.DeviceDetailsActivity;
|
||||||
|
|
||||||
@@ -28,6 +30,20 @@ public class Navigation {
|
|||||||
startActivity(intent);
|
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) {
|
private void startActivity(final Intent intent) {
|
||||||
ActivityCompat.startActivity(mActivity, intent, null);
|
ActivityCompat.startActivity(mActivity, intent, null);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -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 = "\"";
|
private static final String QUOTE = "\"";
|
||||||
|
|
||||||
public static String addStuff(final Integer text) {
|
public static String addStuff(final Integer text) {
|
||||||
@@ -132,7 +132,7 @@ public class MainActivity extends AppCompatActivity implements AdapterView.OnIte
|
|||||||
DialogFactory.createAboutDialog(this).show();
|
DialogFactory.createAboutDialog(this).show();
|
||||||
break;
|
break;
|
||||||
case R.id.menu_share:
|
case R.id.menu_share:
|
||||||
mDeviceStore.shareDataAsEmail(this);
|
new Sharer().shareDataAsEmail(this, mDeviceStore);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<BluetoothLeDevice> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -75,5 +75,6 @@
|
|||||||
<string name="label_updated">Updated:</string>
|
<string name="label_updated">Updated:</string>
|
||||||
<string name="label_decriptor">Descriptor:</string>
|
<string name="label_decriptor">Descriptor:</string>
|
||||||
|
|
||||||
|
<string name="error_unable_to_access_external_storage">"Could not access external storage!"</string>
|
||||||
<string name="permission_not_granted_coarse_location">The ACCESS_COARSE_LOCATION permission is needed to receive bluetooth scan results</string>
|
<string name="permission_not_granted_coarse_location">The ACCESS_COARSE_LOCATION permission is needed to receive bluetooth scan results</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user