diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml index 6901075a358d1da14b42e48c0276d8ce70e0eb9a..11abd3b49720c095d50859940b037cafa9dc29e6 100644 --- a/briar-android/AndroidManifest.xml +++ b/briar-android/AndroidManifest.xml @@ -45,7 +45,7 @@ </service> <activity - android:name=".android.DevReportActivity" + android:name=".android.report.DevReportActivity" android:excludeFromRecents="true" android:exported="false" android:finishOnTaskLaunch="true" diff --git a/briar-android/src/org/briarproject/android/AndroidComponent.java b/briar-android/src/org/briarproject/android/AndroidComponent.java index 6f5454a05abbe36e7407926a5c1a345fa46ddc2b..92a4e8ccb64341964e0d66c0db33b26b0b0c7a78 100644 --- a/briar-android/src/org/briarproject/android/AndroidComponent.java +++ b/briar-android/src/org/briarproject/android/AndroidComponent.java @@ -5,7 +5,7 @@ import org.briarproject.CoreModule; import org.briarproject.android.api.AndroidExecutor; import org.briarproject.android.api.AndroidNotificationManager; import org.briarproject.android.api.ReferenceManager; -import org.briarproject.android.util.BriarReportSender; +import org.briarproject.android.report.BriarReportSender; import org.briarproject.api.contact.ContactExchangeTask; import org.briarproject.api.contact.ContactManager; import org.briarproject.api.crypto.CryptoComponent; @@ -112,12 +112,10 @@ public interface AndroidComponent extends CoreEagerSingletons { @IoExecutor Executor ioExecutor(); - void inject(DevReportActivity devReportActivity); - void inject(BriarService activity); + void inject(BriarReportSender briarReportSender); + // Eager singleton load void inject(AppModule.EagerSingletons init); - - void inject(BriarReportSender briarReportSender); } diff --git a/briar-android/src/org/briarproject/android/BriarApplicationImpl.java b/briar-android/src/org/briarproject/android/BriarApplicationImpl.java index 080fffdcabf57ade9bee5159d65a4460172cfb92..4d88c6536708fc5700b475147ffea0a0e5ae0b73 100644 --- a/briar-android/src/org/briarproject/android/BriarApplicationImpl.java +++ b/briar-android/src/org/briarproject/android/BriarApplicationImpl.java @@ -8,8 +8,9 @@ import org.acra.ReportingInteractionMode; import org.acra.annotation.ReportsCrashes; import org.briarproject.CoreModule; import org.briarproject.R; -import org.briarproject.android.util.BriarReportPrimer; -import org.briarproject.android.util.BriarReportSenderFactory; +import org.briarproject.android.report.BriarReportPrimer; +import org.briarproject.android.report.BriarReportSenderFactory; +import org.briarproject.android.report.DevReportActivity; import java.util.logging.Logger; diff --git a/briar-android/src/org/briarproject/android/report/BriarReportPrimer.java b/briar-android/src/org/briarproject/android/report/BriarReportPrimer.java new file mode 100644 index 0000000000000000000000000000000000000000..df2ac74306ae0e2c35ee923c443ff5db3a424b1f --- /dev/null +++ b/briar-android/src/org/briarproject/android/report/BriarReportPrimer.java @@ -0,0 +1,240 @@ +package org.briarproject.android.report; + +import android.app.ActivityManager; +import android.bluetooth.BluetoothAdapter; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.Build; +import android.os.Environment; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; +import android.support.annotation.NonNull; + +import org.acra.builder.ReportBuilder; +import org.acra.builder.ReportPrimer; +import org.briarproject.util.StringUtils; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; + +import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE; +import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; +import static android.content.Context.ACTIVITY_SERVICE; +import static android.content.Context.CONNECTIVITY_SERVICE; +import static android.content.Context.WIFI_SERVICE; +import static android.net.ConnectivityManager.TYPE_MOBILE; +import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; + +public class BriarReportPrimer implements ReportPrimer { + + @Override + public void primeReport(@NonNull Context ctx, + @NonNull ReportBuilder builder) { + CustomDataTask task = new CustomDataTask(ctx); + FutureTask<Map<String, String>> futureTask = new FutureTask<>(task); + // Use a new thread as the Android executor thread may have died + new SingleShotAndroidExecutor(futureTask).start(); + try { + builder.customData(futureTask.get()); + } catch (InterruptedException | ExecutionException e) { + builder.customData("Custom data exception", e.toString()); + } + } + + private static class CustomDataTask + implements Callable<Map<String, String>> { + + private final Context ctx; + + private CustomDataTask(Context ctx) { + this.ctx = ctx; + } + + @Override + public Map<String, String> call() { + Map<String, String> customData = new LinkedHashMap<>(); + + // System memory + Object o = ctx.getSystemService(ACTIVITY_SERVICE); + ActivityManager am = (ActivityManager) o; + ActivityManager.MemoryInfo mem = new ActivityManager.MemoryInfo(); + am.getMemoryInfo(mem); + String systemMemory; + if (Build.VERSION.SDK_INT >= 16) { + systemMemory = (mem.totalMem / 1024 / 1024) + " MiB total, " + + (mem.availMem / 1024 / 1204) + " MiB free, " + + (mem.threshold / 1024 / 1024) + " MiB threshold"; + } else { + systemMemory = (mem.availMem / 1024 / 1204) + " MiB free, " + + (mem.threshold / 1024 / 1024) + " MiB threshold"; + } + customData.put("System memory", systemMemory); + + // Virtual machine memory + Runtime runtime = Runtime.getRuntime(); + long heap = runtime.totalMemory(); + long heapFree = runtime.freeMemory(); + long heapMax = runtime.maxMemory(); + String vmMemory = (heap / 1024 / 1024) + " MiB allocated, " + + (heapFree / 1024 / 1024) + " MiB free, " + + (heapMax / 1024 / 1024) + " MiB maximum"; + customData.put("Virtual machine memory", vmMemory); + + // Internal storage + File root = Environment.getRootDirectory(); + long rootTotal = root.getTotalSpace(); + long rootFree = root.getFreeSpace(); + String internal = (rootTotal / 1024 / 1024) + " MiB total, " + + (rootFree / 1024 / 1024) + " MiB free"; + customData.put("Internal storage", internal); + + // External storage (SD card) + File sd = Environment.getExternalStorageDirectory(); + long sdTotal = sd.getTotalSpace(); + long sdFree = sd.getFreeSpace(); + String external = (sdTotal / 1024 / 1024) + " MiB total, " + + (sdFree / 1024 / 1024) + " MiB free"; + customData.put("External storage", external); + + // Is mobile data available? + o = ctx.getSystemService(CONNECTIVITY_SERVICE); + ConnectivityManager cm = (ConnectivityManager) o; + NetworkInfo mobile = cm.getNetworkInfo(TYPE_MOBILE); + boolean mobileAvailable = mobile != null && mobile.isAvailable(); + // Is mobile data enabled? + boolean mobileEnabled = false; + try { + Class<?> clazz = Class.forName(cm.getClass().getName()); + Method method = clazz.getDeclaredMethod("getMobileDataEnabled"); + method.setAccessible(true); + mobileEnabled = (Boolean) method.invoke(cm); + } catch (ClassNotFoundException + | NoSuchMethodException + | IllegalArgumentException + | InvocationTargetException + | IllegalAccessException e) { + customData.put("Mobile data reflection exception", + e.toString()); + } + // Is mobile data connected ? + boolean mobileConnected = mobile != null && mobile.isConnected(); + + String mobileStatus; + if (mobileAvailable) mobileStatus = "Available, "; + else mobileStatus = "Not available, "; + if (mobileEnabled) mobileStatus += "enabled, "; + else mobileStatus += "not enabled, "; + if (mobileConnected) mobileStatus += "connected"; + else mobileStatus += "not connected"; + customData.put("Mobile data status", mobileStatus); + + // Is wifi available? + NetworkInfo wifi = cm.getNetworkInfo(TYPE_WIFI); + boolean wifiAvailable = wifi != null && wifi.isAvailable(); + // Is wifi enabled? + o = ctx.getSystemService(WIFI_SERVICE); + WifiManager wm = (WifiManager) o; + boolean wifiEnabled = wm != null && + wm.getWifiState() == WIFI_STATE_ENABLED; + // Is wifi connected? + boolean wifiConnected = wifi != null && wifi.isConnected(); + + String wifiStatus; + if (wifiAvailable) wifiStatus = "Available, "; + else wifiStatus = "Not available, "; + if (wifiEnabled) wifiStatus += "enabled, "; + else wifiStatus += "not enabled, "; + if (wifiConnected) wifiStatus += "connected"; + else wifiStatus += "not connected"; + customData.put("Wi-Fi status", wifiStatus); + + if (wm != null) { + WifiInfo wifiInfo = wm.getConnectionInfo(); + if (wifiInfo != null) { + int ip = wifiInfo.getIpAddress(); // Nice API, Google + int ip1 = ip & 0xFF; + int ip2 = (ip >> 8) & 0xFF; + int ip3 = (ip >> 16) & 0xFF; + int ip4 = (ip >> 24) & 0xFF; + String address = ip1 + "." + ip2 + "." + ip3 + "." + ip4; + customData.put("Wi-Fi address", address); + } + } + + // Is Bluetooth available? + BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter(); + boolean btAvailable = bt != null; + // Is Bluetooth enabled? + boolean btEnabled = bt != null && bt.isEnabled() && + !StringUtils.isNullOrEmpty(bt.getAddress()); + // Is Bluetooth connectable? + boolean btConnectable = bt != null && + (bt.getScanMode() == SCAN_MODE_CONNECTABLE || + bt.getScanMode() == + SCAN_MODE_CONNECTABLE_DISCOVERABLE); + // Is Bluetooth discoverable? + boolean btDiscoverable = bt != null && + bt.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE; + + String btStatus; + if (btAvailable) btStatus = "Available, "; + else btStatus = "Not available, "; + if (btEnabled) btStatus += "enabled, "; + else btStatus += "not enabled, "; + if (btConnectable) btStatus += "connectable, "; + else btStatus += "not connectable, "; + if (btDiscoverable) btStatus += "discoverable"; + else btStatus += "not discoverable"; + customData.put("Bluetooth status", btStatus); + + if (bt != null) + customData.put("Bluetooth address", bt.getAddress()); + String btSettingsAddr; + try { + btSettingsAddr = Settings.Secure.getString( + ctx.getContentResolver(), "bluetooth_address"); + } catch (SecurityException e) { + btSettingsAddr = "Could not get address from settings"; + } + customData.put("Bluetooth address from settings", btSettingsAddr); + + return Collections.unmodifiableMap(customData); + } + } + + private static class SingleShotAndroidExecutor extends Thread { + + private final Runnable runnable; + + private SingleShotAndroidExecutor(Runnable runnable) { + this.runnable = runnable; + } + + @Override + public void run() { + Looper.prepare(); + Handler handler = new Handler(); + handler.post(runnable); + handler.post(new Runnable() { + @Override + public void run() { + Looper looper = Looper.myLooper(); + if (looper != null) looper.quit(); + } + }); + Looper.loop(); + } + } +} diff --git a/briar-android/src/org/briarproject/android/util/BriarReportSender.java b/briar-android/src/org/briarproject/android/report/BriarReportSender.java similarity index 74% rename from briar-android/src/org/briarproject/android/util/BriarReportSender.java rename to briar-android/src/org/briarproject/android/report/BriarReportSender.java index 50b6fa2c54d4a1745989d8495ba4f2263f996567..9594cf5842b637dc5de138532d3b2fce4e3b8bac 100644 --- a/briar-android/src/org/briarproject/android/util/BriarReportSender.java +++ b/briar-android/src/org/briarproject/android/report/BriarReportSender.java @@ -1,20 +1,23 @@ -package org.briarproject.android.util; +package org.briarproject.android.report; import android.content.Context; import android.support.annotation.NonNull; -import org.acra.ReportField; import org.acra.collector.CrashReportData; import org.acra.sender.ReportSender; import org.acra.sender.ReportSenderException; import org.acra.util.JSONReportBuilder; import org.briarproject.android.AndroidComponent; +import org.briarproject.android.util.AndroidUtils; import org.briarproject.api.reporting.DevReporter; +import java.io.File; import java.io.FileNotFoundException; import javax.inject.Inject; +import static org.acra.ReportField.REPORT_ID; + public class BriarReportSender implements ReportSender { private final AndroidComponent component; @@ -27,11 +30,10 @@ public class BriarReportSender implements ReportSender { } @Override - public void send(@NonNull Context context, + public void send(@NonNull Context ctx, @NonNull CrashReportData errorContent) throws ReportSenderException { component.inject(this); - String crashReport; try { crashReport = errorContent.toJSON().toString(); @@ -39,10 +41,9 @@ public class BriarReportSender implements ReportSender { throw new ReportSenderException("Couldn't create JSON", e); } try { - reporter.encryptReportToFile( - AndroidUtils.getReportDir(context), - errorContent.getProperty(ReportField.REPORT_ID), - crashReport); + File reportDir = AndroidUtils.getReportDir(ctx); + String reportId = errorContent.getProperty(REPORT_ID); + reporter.encryptReportToFile(reportDir, reportId, crashReport); } catch (FileNotFoundException e) { throw new ReportSenderException("Failed to encrypt report", e); } diff --git a/briar-android/src/org/briarproject/android/util/BriarReportSenderFactory.java b/briar-android/src/org/briarproject/android/report/BriarReportSenderFactory.java similarity index 68% rename from briar-android/src/org/briarproject/android/util/BriarReportSenderFactory.java rename to briar-android/src/org/briarproject/android/report/BriarReportSenderFactory.java index 6dc106f743e9b7d6309d144964bd208b0c6e9fd1..6c413781fe9790ea6243e9e18cd0fdbbd24c2a4a 100644 --- a/briar-android/src/org/briarproject/android/util/BriarReportSenderFactory.java +++ b/briar-android/src/org/briarproject/android/report/BriarReportSenderFactory.java @@ -1,4 +1,4 @@ -package org.briarproject.android.util; +package org.briarproject.android.report; import android.content.Context; import android.support.annotation.NonNull; @@ -9,12 +9,13 @@ import org.acra.sender.ReportSenderFactory; import org.briarproject.android.BriarApplication; public class BriarReportSenderFactory implements ReportSenderFactory { + @NonNull @Override - public ReportSender create(@NonNull Context context, + public ReportSender create(@NonNull Context ctx, @NonNull ACRAConfiguration config) { // ACRA passes in the Application as context - return new BriarReportSender( - ((BriarApplication) context).getApplicationComponent()); + BriarApplication app = (BriarApplication) ctx; + return new BriarReportSender(app.getApplicationComponent()); } } diff --git a/briar-android/src/org/briarproject/android/DevReportActivity.java b/briar-android/src/org/briarproject/android/report/DevReportActivity.java similarity index 96% rename from briar-android/src/org/briarproject/android/DevReportActivity.java rename to briar-android/src/org/briarproject/android/report/DevReportActivity.java index a55ffd26c5eddb1d8ba09ddf969659a48166c3ee..6eb535a9205123cddc259c8e6c12c07f814cf1ab 100644 --- a/briar-android/src/org/briarproject/android/DevReportActivity.java +++ b/briar-android/src/org/briarproject/android/report/DevReportActivity.java @@ -1,4 +1,4 @@ -package org.briarproject.android; +package org.briarproject.android.report; import android.content.DialogInterface; import android.content.SharedPreferences; @@ -79,15 +79,13 @@ public class DevReportActivity extends BaseCrashReportDialog @Override public void onCreate(Bundle state) { super.onCreate(state); - setContentView(R.layout.activity_dev_report); - BriarApplication app = (BriarApplication) getApplication(); - app.getApplicationComponent().inject(this); + setContentView(R.layout.activity_dev_report); sharedPreferencesFactory = new SharedPreferencesFactory( getApplicationContext(), getConfig()); - final SharedPreferences prefs = sharedPreferencesFactory.create(); + SharedPreferences prefs = sharedPreferencesFactory.create(); excludedFields = new HashSet<>(); if (Build.VERSION.SDK_INT >= 11) { for (String name : prefs.getStringSet(PREF_EXCLUDED_FIELDS, @@ -121,13 +119,12 @@ public class DevReportActivity extends BaseCrashReportDialog report.setVisibility(GONE); } }); - share.setOnClickListener( - new OnClickListener() { - @Override - public void onClick(View v) { - processReport(); - } - }); + share.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + processReport(); + } + }); String userEmail = prefs.getString(ACRA.PREF_USER_EMAIL_ADDRESS, ""); userEmailView.setText(userEmail); diff --git a/briar-android/src/org/briarproject/android/util/BriarReportPrimer.java b/briar-android/src/org/briarproject/android/util/BriarReportPrimer.java deleted file mode 100644 index 67e96b3ca4a86e325e58dfe0be3b74e0fc422e48..0000000000000000000000000000000000000000 --- a/briar-android/src/org/briarproject/android/util/BriarReportPrimer.java +++ /dev/null @@ -1,184 +0,0 @@ -package org.briarproject.android.util; - -import android.app.ActivityManager; -import android.bluetooth.BluetoothAdapter; -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; -import android.os.Build; -import android.os.Environment; -import android.provider.Settings; - -import org.acra.builder.ReportBuilder; -import org.acra.builder.ReportPrimer; -import org.briarproject.util.StringUtils; - -import java.io.File; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.logging.Logger; - -import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE; -import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; -import static android.content.Context.ACTIVITY_SERVICE; -import static android.content.Context.CONNECTIVITY_SERVICE; -import static android.content.Context.WIFI_SERVICE; -import static android.net.ConnectivityManager.TYPE_MOBILE; -import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; -import static java.util.logging.Level.WARNING; - -public class BriarReportPrimer implements ReportPrimer { - - private static final Logger LOG = - Logger.getLogger(BriarReportPrimer.class.getName()); - - @Override - public void primeReport(Context context, ReportBuilder builder) { - // System memory - Object o = context.getSystemService(ACTIVITY_SERVICE); - ActivityManager am = (ActivityManager) o; - ActivityManager.MemoryInfo mem = new ActivityManager.MemoryInfo(); - am.getMemoryInfo(mem); - String systemMemory; - if (Build.VERSION.SDK_INT >= 16) { - systemMemory = (mem.totalMem / 1024 / 1024) + " MiB total, " - + (mem.availMem / 1024 / 1204) + " MiB free, " - + (mem.threshold / 1024 / 1024) + " MiB threshold"; - } else { - systemMemory = (mem.availMem / 1024 / 1204) + " MiB free, " - + (mem.threshold / 1024 / 1024) + " MiB threshold"; - } - builder.customData("System memory", systemMemory); - - // Virtual machine memory - Runtime runtime = Runtime.getRuntime(); - long heap = runtime.totalMemory(); - long heapFree = runtime.freeMemory(); - long heapMax = runtime.maxMemory(); - String vmMemory = (heap / 1024 / 1024) + " MiB allocated, " - + (heapFree / 1024 / 1024) + " MiB free, " - + (heapMax / 1024 / 1024) + " MiB maximum"; - builder.customData("Virtual machine memory", vmMemory); - - // Internal storage - File root = Environment.getRootDirectory(); - long rootTotal = root.getTotalSpace(); - long rootFree = root.getFreeSpace(); - String internal = (rootTotal / 1024 / 1024) + " MiB total, " - + (rootFree / 1024 / 1024) + " MiB free"; - builder.customData("Internal storage", internal); - - // External storage (SD card) - File sd = Environment.getExternalStorageDirectory(); - long sdTotal = sd.getTotalSpace(); - long sdFree = sd.getFreeSpace(); - String external = (sdTotal / 1024 / 1024) + " MiB total, " - + (sdFree / 1024 / 1024) + " MiB free"; - builder.customData("External storage", external); - - // Is mobile data available? - o = context.getSystemService(CONNECTIVITY_SERVICE); - ConnectivityManager cm = (ConnectivityManager) o; - NetworkInfo mobile = cm.getNetworkInfo(TYPE_MOBILE); - boolean mobileAvailable = mobile != null && mobile.isAvailable(); - // Is mobile data enabled? - boolean mobileEnabled = false; - try { - Class<?> clazz = Class.forName(cm.getClass().getName()); - Method method = clazz.getDeclaredMethod("getMobileDataEnabled"); - method.setAccessible(true); - mobileEnabled = (Boolean) method.invoke(cm); - } catch (ClassNotFoundException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - } catch (NoSuchMethodException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - } catch (IllegalAccessException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - } catch (IllegalArgumentException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - } catch (InvocationTargetException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - } - // Is mobile data connected ? - boolean mobileConnected = mobile != null && mobile.isConnected(); - - String mobileStatus; - if (mobileAvailable) mobileStatus = "Available, "; - else mobileStatus = "Not available, "; - if (mobileEnabled) mobileStatus += "enabled, "; - else mobileStatus += "not enabled, "; - if (mobileConnected) mobileStatus += "connected"; - else mobileStatus += "not connected"; - builder.customData("Mobile data status", mobileStatus); - - // Is wifi available? - NetworkInfo wifi = cm.getNetworkInfo(TYPE_WIFI); - boolean wifiAvailable = wifi != null && wifi.isAvailable(); - // Is wifi enabled? - WifiManager wm = (WifiManager) context.getSystemService(WIFI_SERVICE); - boolean wifiEnabled = wm != null && - wm.getWifiState() == WIFI_STATE_ENABLED; - // Is wifi connected? - boolean wifiConnected = wifi != null && wifi.isConnected(); - - String wifiStatus; - if (wifiAvailable) wifiStatus = "Available, "; - else wifiStatus = "Not available, "; - if (wifiEnabled) wifiStatus += "enabled, "; - else wifiStatus += "not enabled, "; - if (wifiConnected) wifiStatus += "connected"; - else wifiStatus += "not connected"; - builder.customData("Wi-Fi status", wifiStatus); - - if (wm != null) { - WifiInfo wifiInfo = wm.getConnectionInfo(); - if (wifiInfo != null) { - int ip = wifiInfo.getIpAddress(); // Nice API, Google - int ip1 = ip & 0xFF; - int ip2 = (ip >> 8) & 0xFF; - int ip3 = (ip >> 16) & 0xFF; - int ip4 = (ip >> 24) & 0xFF; - String address = ip1 + "." + ip2 + "." + ip3 + "." + ip4; - builder.customData("Wi-Fi address", address); - } - } - - // Is Bluetooth available? - BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter(); - boolean btAvailable = bt != null; - // Is Bluetooth enabled? - boolean btEnabled = bt != null && bt.isEnabled() && - !StringUtils.isNullOrEmpty(bt.getAddress()); - // Is Bluetooth connectable? - boolean btConnectable = bt != null && - (bt.getScanMode() == SCAN_MODE_CONNECTABLE || - bt.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE); - // Is Bluetooth discoverable? - boolean btDiscoverable = bt != null && - bt.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE; - - String btStatus; - if (btAvailable) btStatus = "Available, "; - else btStatus = "Not available, "; - if (btEnabled) btStatus += "enabled, "; - else btStatus += "not enabled, "; - if (btConnectable) btStatus += "connectable, "; - else btStatus += "not connectable, "; - if (btDiscoverable) btStatus += "discoverable"; - else btStatus += "not discoverable"; - builder.customData("Bluetooth status", btStatus); - - if (bt != null) builder.customData("Bluetooth address", bt.getAddress()); - String btSettingsAddr; - try { - btSettingsAddr = Settings.Secure.getString(context.getContentResolver(), - "bluetooth_address"); - } catch (SecurityException e) { - btSettingsAddr = "Could not get address from settings"; - } - builder.customData("Bluetooth address from settings", btSettingsAddr); - } -}