Skip to content

Commit

Permalink
#25 use wrapper object and copy all relevant fields
Browse files Browse the repository at this point in the history
  • Loading branch information
ostrya committed Sep 9, 2020
1 parent a31eb7b commit 5cc371d
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -85,7 +85,7 @@ private void initBeaconReceiver() {
Set<String> 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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}

Expand All @@ -50,23 +48,23 @@ private List<Region> getConfiguredScanRegions(SharedPreferences sharedPreference
Set<String> beaconList = sharedPreferences.getStringSet(BEACON_LIST, Collections.emptySet());
List<Region> 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<String> 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);
Expand All @@ -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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<BeaconListAdapter.BeaconHolder> {
private final SortedList.Callback<Beacon> beaconBatchedCallback = new ListCallback(this);
private final SortedList<Beacon> foundBeacons = new SortedList<>(Beacon.class, beaconBatchedCallback);
private final SortedList.Callback<PresenceBeacon> beaconBatchedCallback = new ListCallback(this);
private final SortedList<PresenceBeacon> foundBeacons = new SortedList<>(PresenceBeacon.class, beaconBatchedCallback);
private final BeaconScanDialogFragment.DialogCallback dialogCallback;
private final Set<String> knownBeacons;

Expand All @@ -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);
}

Expand All @@ -48,7 +47,7 @@ public int getItemCount() {
return foundBeacons.size();
}

public void addBeacon(Beacon beacon) {
public void addBeacon(PresenceBeacon beacon) {
foundBeacons.add(beacon);
}

Expand All @@ -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);
Expand All @@ -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);
}

Expand All @@ -92,32 +91,32 @@ void setClickHandler(ClickListener clickListener) {
}
}

private static final class ListCallback extends SortedListAdapterCallback<Beacon> {
private static final class ListCallback extends SortedListAdapterCallback<PresenceBeacon> {
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());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -87,7 +88,7 @@ public void onDestroyView() {
beaconManager.unbind(this);
}

private void onSelect(Beacon beacon) {
private void onSelect(PresenceBeacon beacon) {
dialogCallback.accept(beacon);
dismiss();
}
Expand Down Expand Up @@ -155,31 +156,21 @@ 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 {
@Override
public void didRangeBeaconsInRegion(Collection<Beacon> 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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}

Expand Down

This file was deleted.

0 comments on commit 5cc371d

Please sign in to comment.