From 5cc371dc1539e3fc7ad336c536b254126b170793 Mon Sep 17 00:00:00 2001 From: ostrya Date: Wed, 9 Sep 2020 21:18:21 +0200 Subject: [PATCH] #25 use wrapper object and copy all relevant fields --- .../ostrya/presencepublisher/Application.java | 4 +- .../beacon/PresenceBeacon.java | 56 +++++++++++++++++++ ...anager.java => PresenceBeaconManager.java} | 22 ++++---- .../ui/dialog/BeaconListAdapter.java | 41 +++++++------- .../ui/dialog/BeaconScanDialogFragment.java | 21 ++----- .../AddBeaconChoicePreferenceDummy.java | 8 +-- .../condition/BeaconPreference.java | 4 +- .../ui/util/BeaconIdHelper.java | 18 ------ 8 files changed, 100 insertions(+), 74 deletions(-) create mode 100644 app/src/main/java/org/ostrya/presencepublisher/beacon/PresenceBeacon.java rename app/src/main/java/org/ostrya/presencepublisher/beacon/{BeaconManager.java => PresenceBeaconManager.java} (85%) delete mode 100644 app/src/main/java/org/ostrya/presencepublisher/ui/util/BeaconIdHelper.java diff --git a/app/src/main/java/org/ostrya/presencepublisher/Application.java b/app/src/main/java/org/ostrya/presencepublisher/Application.java index fc31de2..f2ad271 100644 --- a/app/src/main/java/org/ostrya/presencepublisher/Application.java +++ b/app/src/main/java/org/ostrya/presencepublisher/Application.java @@ -13,8 +13,8 @@ import org.altbeacon.beacon.distance.ModelSpecificDistanceCalculator; import org.altbeacon.beacon.logging.LogManager; import org.altbeacon.beacon.powersave.BackgroundPowerSaver; -import org.ostrya.presencepublisher.beacon.BeaconManager; import org.ostrya.presencepublisher.beacon.HyperlogLogger; +import org.ostrya.presencepublisher.beacon.PresenceBeaconManager; import org.ostrya.presencepublisher.log.CustomLogFormat; import org.ostrya.presencepublisher.log.LogUncaughtExceptionHandler; import org.ostrya.presencepublisher.receiver.SystemBroadcastReceiver; @@ -85,7 +85,7 @@ private void initBeaconReceiver() { Set beacons = sharedPreferences.getStringSet(BEACON_LIST, Collections.emptySet()); if (!beacons.isEmpty()) { HyperLog.i(TAG, "Enabling beacon scanning for " + beacons); - BeaconManager.getInstance().initialize(this); + PresenceBeaconManager.getInstance().initialize(this); } else { HyperLog.i(TAG, "No beacons configured, not enabling background beacon scanning"); return; diff --git a/app/src/main/java/org/ostrya/presencepublisher/beacon/PresenceBeacon.java b/app/src/main/java/org/ostrya/presencepublisher/beacon/PresenceBeacon.java new file mode 100644 index 0000000..b2e7876 --- /dev/null +++ b/app/src/main/java/org/ostrya/presencepublisher/beacon/PresenceBeacon.java @@ -0,0 +1,56 @@ +package org.ostrya.presencepublisher.beacon; + +import org.altbeacon.beacon.Beacon; + +import java.util.Objects; + +public class PresenceBeacon { + private static final String BEACON_FORMAT = "%s (%s)%n%s"; + + private final String address; + private final String name; + private final String type; + private final int rssi; + private final double distance; + + public PresenceBeacon(Beacon beacon) { + Objects.requireNonNull(beacon); + address = Objects.requireNonNull(beacon.getBluetoothAddress()); + if (beacon.getBluetoothName() != null) { + name = beacon.getBluetoothName(); + } else { + name = address; + } + type = Objects.requireNonNull(beacon.getParserIdentifier()); + rssi = beacon.getRssi(); + distance = beacon.getDistance(); + } + + public static String beaconIdToAddress(String beaconId) { + return beaconId.substring(beaconId.lastIndexOf('\n') + 1); + } + + public String getAddress() { + return address; + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } + + public int getRssi() { + return rssi; + } + + public double getDistance() { + return distance; + } + + public String toBeaconId() { + return String.format(BEACON_FORMAT, name, type, address); + } +} diff --git a/app/src/main/java/org/ostrya/presencepublisher/beacon/BeaconManager.java b/app/src/main/java/org/ostrya/presencepublisher/beacon/PresenceBeaconManager.java similarity index 85% rename from app/src/main/java/org/ostrya/presencepublisher/beacon/BeaconManager.java rename to app/src/main/java/org/ostrya/presencepublisher/beacon/PresenceBeaconManager.java index 4f2ae5b..a0548c9 100644 --- a/app/src/main/java/org/ostrya/presencepublisher/beacon/BeaconManager.java +++ b/app/src/main/java/org/ostrya/presencepublisher/beacon/PresenceBeaconManager.java @@ -8,10 +8,8 @@ import androidx.annotation.RequiresApi; import androidx.preference.PreferenceManager; import com.hypertrack.hyperlog.HyperLog; -import org.altbeacon.beacon.Beacon; import org.altbeacon.beacon.Region; import org.altbeacon.beacon.startup.RegionBootstrap; -import org.ostrya.presencepublisher.ui.util.BeaconIdHelper; import java.util.ArrayList; import java.util.Collections; @@ -23,18 +21,18 @@ import static org.ostrya.presencepublisher.ui.preference.condition.AddBeaconChoicePreferenceDummy.BEACON_LIST; @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) -public final class BeaconManager { - private static final String TAG = "BeaconManager"; - private static final BeaconManager INSTANCE = new BeaconManager(); +public final class PresenceBeaconManager { + private static final String TAG = "PresenceBeaconManager"; + private static final PresenceBeaconManager INSTANCE = new PresenceBeaconManager(); @GuardedBy("this") @Nullable private RegionBootstrap regionBootstrap; - private BeaconManager() { + private PresenceBeaconManager() { } - public static BeaconManager getInstance() { + public static PresenceBeaconManager getInstance() { return INSTANCE; } @@ -50,23 +48,23 @@ private List getConfiguredScanRegions(SharedPreferences sharedPreference Set beaconList = sharedPreferences.getStringSet(BEACON_LIST, Collections.emptySet()); List scanRegions = new ArrayList<>(beaconList.size()); for (String beaconId : beaconList) { - String address = BeaconIdHelper.toAddress(beaconId); + String address = PresenceBeacon.beaconIdToAddress(beaconId); HyperLog.d(TAG, "Registering scan region for beacon " + beaconId); scanRegions.add(new Region(beaconId, address)); } return scanRegions; } - public synchronized void addBeacon(Context context, Beacon beacon) { + public synchronized void addBeacon(Context context, PresenceBeacon beacon) { Context applicationContext = context.getApplicationContext(); SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(applicationContext); Set storedBeacons = new HashSet<>(sharedPreferences.getStringSet(BEACON_LIST, Collections.emptySet())); - String beaconId = BeaconIdHelper.toBeaconId(beacon); + String beaconId = beacon.toBeaconId(); storedBeacons.add(beaconId); sharedPreferences.edit().putStringSet(BEACON_LIST, storedBeacons).apply(); HyperLog.d(TAG, "Add scanning for beacon " + beaconId); - Region region = new Region(beaconId, beacon.getBluetoothAddress()); + Region region = new Region(beaconId, beacon.getAddress()); if (regionBootstrap == null) { HyperLog.d(TAG, "Start scanning for beacons"); RegionMonitorNotifier monitorNotifier = new RegionMonitorNotifier(sharedPreferences); @@ -89,7 +87,7 @@ public synchronized void removeBeacon(Context context, String beaconId) { .apply(); HyperLog.d(TAG, "Remove scanning for beacon " + beaconId); - Region region = new Region(beaconId, BeaconIdHelper.toAddress(beaconId)); + Region region = new Region(beaconId, PresenceBeacon.beaconIdToAddress(beaconId)); if (regionBootstrap != null) { if (storedBeacons.isEmpty()) { HyperLog.i(TAG, "Disable scanning for beacons"); diff --git a/app/src/main/java/org/ostrya/presencepublisher/ui/dialog/BeaconListAdapter.java b/app/src/main/java/org/ostrya/presencepublisher/ui/dialog/BeaconListAdapter.java index ce77fb2..c66a7c7 100644 --- a/app/src/main/java/org/ostrya/presencepublisher/ui/dialog/BeaconListAdapter.java +++ b/app/src/main/java/org/ostrya/presencepublisher/ui/dialog/BeaconListAdapter.java @@ -10,16 +10,15 @@ import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.SortedList; import androidx.recyclerview.widget.SortedListAdapterCallback; -import org.altbeacon.beacon.Beacon; import org.ostrya.presencepublisher.R; -import org.ostrya.presencepublisher.ui.util.BeaconIdHelper; +import org.ostrya.presencepublisher.beacon.PresenceBeacon; import java.util.Set; @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) public class BeaconListAdapter extends RecyclerView.Adapter { - private final SortedList.Callback beaconBatchedCallback = new ListCallback(this); - private final SortedList foundBeacons = new SortedList<>(Beacon.class, beaconBatchedCallback); + private final SortedList.Callback beaconBatchedCallback = new ListCallback(this); + private final SortedList foundBeacons = new SortedList<>(PresenceBeacon.class, beaconBatchedCallback); private final BeaconScanDialogFragment.DialogCallback dialogCallback; private final Set knownBeacons; @@ -38,8 +37,8 @@ public BeaconHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) @Override public void onBindViewHolder(@NonNull BeaconHolder holder, int position) { - Beacon beacon = foundBeacons.get(position); - holder.setBeacon(beacon, !knownBeacons.contains(BeaconIdHelper.toBeaconId(beacon))); + PresenceBeacon beacon = foundBeacons.get(position); + holder.setBeacon(beacon, !knownBeacons.contains(beacon.toBeaconId())); holder.setClickHandler(this::onClick); } @@ -48,7 +47,7 @@ public int getItemCount() { return foundBeacons.size(); } - public void addBeacon(Beacon beacon) { + public void addBeacon(PresenceBeacon beacon) { foundBeacons.add(beacon); } @@ -66,7 +65,7 @@ static final class BeaconHolder extends RecyclerView.ViewHolder { final TextView beaconStrength; final TextView beaconDistance; final TextView beaconAddress; - Beacon item; + PresenceBeacon item; public BeaconHolder(@NonNull View view) { super(view); @@ -77,13 +76,13 @@ public BeaconHolder(@NonNull View view) { beaconAddress = itemView.findViewById(R.id.beaconAddress); } - void setBeacon(Beacon beacon, boolean enabled) { + void setBeacon(PresenceBeacon beacon, boolean enabled) { item = beacon; - beaconType.setText(item.getParserIdentifier()); - beaconName.setText(item.getBluetoothName()); + beaconType.setText(item.getType()); + beaconName.setText(item.getName()); beaconStrength.setText(String.format(beaconStrength.getTextLocale(), "%d dBm", item.getRssi())); beaconDistance.setText(String.format(beaconDistance.getTextLocale(), "%.1f m", item.getDistance())); - beaconAddress.setText(item.getBluetoothAddress()); + beaconAddress.setText(item.getAddress()); itemView.setEnabled(enabled); } @@ -92,32 +91,32 @@ void setClickHandler(ClickListener clickListener) { } } - private static final class ListCallback extends SortedListAdapterCallback { + private static final class ListCallback extends SortedListAdapterCallback { public ListCallback(RecyclerView.Adapter adapter) { super(adapter); } @Override - public int compare(Beacon item1, Beacon item2) { - int result = item1.getBluetoothAddress().compareTo(item2.getBluetoothAddress()); + public int compare(PresenceBeacon item1, PresenceBeacon item2) { + int result = item1.getAddress().compareTo(item2.getAddress()); if (result == 0) { - result = item1.getParserIdentifier().compareTo(item2.getParserIdentifier()); + result = item1.getType().compareTo(item2.getType()); } return result; } @Override - public boolean areContentsTheSame(Beacon oldItem, Beacon newItem) { + public boolean areContentsTheSame(PresenceBeacon oldItem, PresenceBeacon newItem) { return areItemsTheSame(oldItem, newItem) - && oldItem.getBluetoothName().equals(newItem.getBluetoothName()) + && oldItem.getName().equals(newItem.getName()) && oldItem.getRssi() == newItem.getRssi() && oldItem.getDistance() == newItem.getDistance(); } @Override - public boolean areItemsTheSame(Beacon item1, Beacon item2) { - return item1.getBluetoothAddress().equals(item2.getBluetoothAddress()) - && item1.getParserIdentifier().equals(item2.getParserIdentifier()); + public boolean areItemsTheSame(PresenceBeacon item1, PresenceBeacon item2) { + return item1.getAddress().equals(item2.getAddress()) + && item1.getType().equals(item2.getType()); } } } diff --git a/app/src/main/java/org/ostrya/presencepublisher/ui/dialog/BeaconScanDialogFragment.java b/app/src/main/java/org/ostrya/presencepublisher/ui/dialog/BeaconScanDialogFragment.java index 1ef7d16..9147aaa 100644 --- a/app/src/main/java/org/ostrya/presencepublisher/ui/dialog/BeaconScanDialogFragment.java +++ b/app/src/main/java/org/ostrya/presencepublisher/ui/dialog/BeaconScanDialogFragment.java @@ -26,6 +26,7 @@ import org.altbeacon.beacon.RangeNotifier; import org.altbeacon.beacon.Region; import org.ostrya.presencepublisher.R; +import org.ostrya.presencepublisher.beacon.PresenceBeacon; import java.util.Collection; import java.util.Set; @@ -87,7 +88,7 @@ public void onDestroyView() { beaconManager.unbind(this); } - private void onSelect(Beacon beacon) { + private void onSelect(PresenceBeacon beacon) { dialogCallback.accept(beacon); dismiss(); } @@ -155,7 +156,7 @@ public boolean bindService(Intent intent, ServiceConnection serviceConnection, i } public interface DialogCallback { - void accept(@Nullable Beacon beacon); + void accept(@Nullable PresenceBeacon beacon); } private class ScanCallback implements RangeNotifier { @@ -163,23 +164,13 @@ private class ScanCallback implements RangeNotifier { public void didRangeBeaconsInRegion(Collection beacons, Region region) { HyperLog.v(TAG, "Got callback from beacon scan for region " + region); for (Beacon beacon : beacons) { - if (beacon != null && beacon.getBluetoothAddress() != null) { + if (beacon != null && beacon.getBluetoothAddress() != null && beacon.getParserIdentifier() != null) { HyperLog.d(TAG, "Found beacon " + beacon); - adapter.addBeacon(fixEmptyName(beacon)); + adapter.addBeacon(new PresenceBeacon(beacon)); } else { - HyperLog.w(TAG, "Beacon " + beacon + " does not have a Bluetooth address"); + HyperLog.w(TAG, "Beacon " + beacon + " is incomplete"); } } } - - private Beacon fixEmptyName(Beacon beacon) { - if (beacon.getBluetoothName() != null) { - return beacon; - } - return new Beacon.Builder() - .copyBeaconFields(beacon) - .setBluetoothName(beacon.getBluetoothAddress()) - .build(); - } } } diff --git a/app/src/main/java/org/ostrya/presencepublisher/ui/preference/condition/AddBeaconChoicePreferenceDummy.java b/app/src/main/java/org/ostrya/presencepublisher/ui/preference/condition/AddBeaconChoicePreferenceDummy.java index c59b130..0b7f1f2 100644 --- a/app/src/main/java/org/ostrya/presencepublisher/ui/preference/condition/AddBeaconChoicePreferenceDummy.java +++ b/app/src/main/java/org/ostrya/presencepublisher/ui/preference/condition/AddBeaconChoicePreferenceDummy.java @@ -10,9 +10,9 @@ import androidx.fragment.app.Fragment; import androidx.preference.Preference; import com.hypertrack.hyperlog.HyperLog; -import org.altbeacon.beacon.Beacon; import org.ostrya.presencepublisher.R; -import org.ostrya.presencepublisher.beacon.BeaconManager; +import org.ostrya.presencepublisher.beacon.PresenceBeacon; +import org.ostrya.presencepublisher.beacon.PresenceBeaconManager; import org.ostrya.presencepublisher.ui.dialog.BeaconScanDialogFragment; import java.util.Collections; @@ -52,10 +52,10 @@ public AddBeaconChoicePreferenceDummy(Context context, Fragment fragment) { } @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) - private void onScanResult(@Nullable Beacon beacon) { + private void onScanResult(@Nullable PresenceBeacon beacon) { if (beacon == null) { return; } - BeaconManager.getInstance().addBeacon(getContext(), beacon); + PresenceBeaconManager.getInstance().addBeacon(getContext(), beacon); } } diff --git a/app/src/main/java/org/ostrya/presencepublisher/ui/preference/condition/BeaconPreference.java b/app/src/main/java/org/ostrya/presencepublisher/ui/preference/condition/BeaconPreference.java index 2eee00b..e8764d3 100644 --- a/app/src/main/java/org/ostrya/presencepublisher/ui/preference/condition/BeaconPreference.java +++ b/app/src/main/java/org/ostrya/presencepublisher/ui/preference/condition/BeaconPreference.java @@ -7,7 +7,7 @@ import androidx.fragment.app.Fragment; import androidx.preference.PreferenceViewHolder; import org.ostrya.presencepublisher.R; -import org.ostrya.presencepublisher.beacon.BeaconManager; +import org.ostrya.presencepublisher.beacon.PresenceBeaconManager; import org.ostrya.presencepublisher.ui.dialog.ConfirmationDialogFragment; import org.ostrya.presencepublisher.ui.preference.common.TextPreferenceBase; import org.ostrya.presencepublisher.ui.util.ExplanationSummaryProvider; @@ -49,7 +49,7 @@ public boolean onLongClick(View v) { @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) private void deleteOnContinue(boolean ok) { if (ok) { - BeaconManager.getInstance().removeBeacon(getContext(), beaconId); + PresenceBeaconManager.getInstance().removeBeacon(getContext(), beaconId); } } diff --git a/app/src/main/java/org/ostrya/presencepublisher/ui/util/BeaconIdHelper.java b/app/src/main/java/org/ostrya/presencepublisher/ui/util/BeaconIdHelper.java deleted file mode 100644 index d0e1cf6..0000000 --- a/app/src/main/java/org/ostrya/presencepublisher/ui/util/BeaconIdHelper.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.ostrya.presencepublisher.ui.util; - -import org.altbeacon.beacon.Beacon; - -public final class BeaconIdHelper { - private static final String BEACON_FORMAT = "%s (%s)%n%s"; - - private BeaconIdHelper() { - } - - public static String toBeaconId(Beacon beacon) { - return String.format(BEACON_FORMAT, beacon.getBluetoothName(), beacon.getParserIdentifier(), beacon.getBluetoothAddress()); - } - - public static String toAddress(String beaconId) { - return beaconId.substring(beaconId.lastIndexOf('\n') + 1); - } -}