summaryrefslogtreecommitdiff
path: root/app/src/main/java
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2021-03-20 23:57:51 +0100
committerJavier <dev.git@javispedro.com>2021-03-20 23:58:23 +0100
commit5dfa37788c7f039eff00b27cc0ca8b9b9a71f60e (patch)
tree6aea7cd13dc6a8cbb771ec1b510a5ac3cf8200f0 /app/src/main/java
downloadrempe-5dfa37788c7f039eff00b27cc0ca8b9b9a71f60e.tar.gz
rempe-5dfa37788c7f039eff00b27cc0ca8b9b9a71f60e.zip
Initial import
Diffstat (limited to 'app/src/main/java')
-rw-r--r--app/src/main/java/com/javispedro/rempe/Device.java231
-rw-r--r--app/src/main/java/com/javispedro/rempe/DeviceListRecyclerViewListAdapter.java44
-rw-r--r--app/src/main/java/com/javispedro/rempe/DeviceViewHolder.java123
-rw-r--r--app/src/main/java/com/javispedro/rempe/MainActivity.java264
-rw-r--r--app/src/main/java/com/javispedro/rempe/Preferences.java43
-rw-r--r--app/src/main/java/com/javispedro/rempe/Reading.java12
6 files changed, 717 insertions, 0 deletions
diff --git a/app/src/main/java/com/javispedro/rempe/Device.java b/app/src/main/java/com/javispedro/rempe/Device.java
new file mode 100644
index 0000000..4622eed
--- /dev/null
+++ b/app/src/main/java/com/javispedro/rempe/Device.java
@@ -0,0 +1,231 @@
+package com.javispedro.rempe;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.dsi.ant.plugins.antplus.pcc.AntPlusEnvironmentPcc;
+import com.dsi.ant.plugins.antplus.pcc.defines.DeviceState;
+import com.dsi.ant.plugins.antplus.pcc.defines.EventFlag;
+import com.dsi.ant.plugins.antplus.pcc.defines.RequestAccessResult;
+import com.dsi.ant.plugins.antplus.pccbase.AntPluginPcc;
+import com.dsi.ant.plugins.antplus.pccbase.AntPlusCommonPcc;
+import com.dsi.ant.plugins.antplus.pccbase.PccReleaseHandle;
+
+import java.math.BigDecimal;
+import java.util.EnumSet;
+
+public class Device {
+ private final static String TAG = "Device";
+
+ private final int mDeviceNumber;
+
+ private PccReleaseHandle<AntPlusEnvironmentPcc> mEnvPccHandle;
+ private AntPlusEnvironmentPcc mEnvPcc;
+
+ private String mDeviceName;
+
+ private final Reading mLastReading = new Reading();
+ private int mLastRssi;
+ private RequestAccessResult mConnectResult;
+ private DeviceState mCurState;
+
+ public interface DeviceObserver {
+ void onDeviceInfoChanged();
+ void onDeviceStateChanged();
+ void onDeviceNewReading();
+ void onDeviceRssiChanged();
+ }
+ private DeviceObserver mObserver;
+
+ public Device(int deviceNumber) {
+ mDeviceNumber = deviceNumber;
+ mDeviceName = "dev-" + deviceNumber;
+ mConnectResult = RequestAccessResult.SUCCESS;
+ mCurState = DeviceState.DEAD;
+ }
+
+ public void connect(Context context) {
+ Log.d(TAG, "connect (" + mDeviceNumber + ")");
+ if (mEnvPccHandle != null) {
+ Log.w(TAG, "Already connected");
+ }
+ mConnectResult = RequestAccessResult.SUCCESS; // Clear old connect result
+ mCurState = DeviceState.SEARCHING;
+ if (mObserver != null) {
+ mObserver.onDeviceStateChanged();
+ }
+ mEnvPccHandle = AntPlusEnvironmentPcc.requestAccess(context, mDeviceNumber, 0, mResultReceiver, mDeviceStateChangeReceiver);
+ }
+
+ public void close() {
+ Log.d(TAG, "close (" + mDeviceNumber + ")");
+ if (mEnvPccHandle != null) {
+ mEnvPccHandle.close();
+ mEnvPccHandle = null;
+ }
+ if (mEnvPcc != null) {
+ mEnvPcc = null;
+ }
+ mConnectResult = RequestAccessResult.SUCCESS;
+ mCurState = DeviceState.DEAD;
+ if (mObserver != null) {
+ mObserver.onDeviceStateChanged();
+ }
+ }
+
+ public void setObserver(DeviceObserver observer) {
+ mObserver = observer;
+ }
+
+ public boolean isOpen() {
+ return mEnvPccHandle != null;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + "(" + mDeviceNumber + ")";
+ }
+
+ private void setEnvPcc(AntPlusEnvironmentPcc envPcc) {
+ if (mEnvPcc != null) {
+ mEnvPcc.releaseAccess();
+ mEnvPcc = null;
+ }
+ mEnvPcc = envPcc;
+ final String deviceName = mEnvPcc.getDeviceName();
+ final int deviceNumber = mEnvPcc.getAntDeviceNumber();
+ Log.d(TAG, "handleConnection deviceName=" + deviceName + " deviceNumber=" + deviceNumber);
+ if (deviceNumber != mDeviceNumber) {
+ Log.e(TAG, "device number mismatch");
+ }
+ mDeviceName = deviceName;
+ mEnvPcc.subscribeTemperatureDataEvent(mTemperatureDataReceiver);
+ mEnvPcc.subscribeRssiEvent(mRssiReceiver);
+ if (mObserver != null) {
+ mObserver.onDeviceInfoChanged();
+ }
+ }
+
+ public String getDeviceName() {
+ return mDeviceName;
+ }
+
+ public Reading getLastReading() {
+ return mLastReading;
+ }
+
+ public int getLastRssi() {
+ return mLastRssi;
+ }
+
+ public DeviceState getCurrentDeviceState() {
+ return mCurState;
+ }
+
+ public RequestAccessResult getConnectResult() {
+ return mConnectResult;
+ }
+
+ private AntPluginPcc.IPluginAccessResultReceiver<AntPlusEnvironmentPcc> mResultReceiver = new AntPluginPcc.IPluginAccessResultReceiver<AntPlusEnvironmentPcc>() {
+ @Override
+ public void onResultReceived(AntPlusEnvironmentPcc result, RequestAccessResult resultCode, DeviceState initialDeviceState) {
+ Log.d(TAG, "onResultReceived resultCode=" + resultCode + " initialDeviceState=" + initialDeviceState);
+ mConnectResult = resultCode;
+ mCurState = initialDeviceState;
+ if (resultCode.equals(RequestAccessResult.SUCCESS)) {
+ setEnvPcc(result);
+ }
+ if (mObserver != null) {
+ mObserver.onDeviceStateChanged();
+ }
+
+ if (resultCode.equals(RequestAccessResult.SEARCH_TIMEOUT)) {
+ Log.d(TAG, "timeout");
+ }
+ }
+ };
+
+ private AntPluginPcc.IDeviceStateChangeReceiver mDeviceStateChangeReceiver = new AntPluginPcc.IDeviceStateChangeReceiver() {
+ @Override
+ public void onDeviceStateChange(DeviceState newDeviceState) {
+ Log.d(TAG, "onDeviceStateChange newDeviceState=" + newDeviceState);
+ mCurState = newDeviceState;
+ if (mObserver != null) {
+ mObserver.onDeviceStateChanged();
+ }
+ }
+ };
+
+ private final AntPlusEnvironmentPcc.ITemperatureDataReceiver mTemperatureDataReceiver = new AntPlusEnvironmentPcc.ITemperatureDataReceiver() {
+ @Override
+ public void onNewTemperatureData(long estTimestamp, EnumSet<EventFlag> eventFlags, BigDecimal currentTemperature, long eventCount, BigDecimal lowLast24Hours, BigDecimal highLast24Hours) {
+ Log.d(TAG, "onNewTemperatureData");
+ mLastReading.timestamp = estTimestamp;
+ mLastReading.temperature = currentTemperature;
+ mLastReading.highLast24Hours = highLast24Hours;
+ mLastReading.lowLast24Hours = lowLast24Hours;
+ if (mObserver != null) {
+ mObserver.onDeviceNewReading();
+ }
+ }
+ };
+
+ private final AntPlusCommonPcc.IRssiReceiver mRssiReceiver = new AntPlusCommonPcc.IRssiReceiver() {
+ @Override
+ public void onRssiData(long estTimestamp, EnumSet<EventFlag> eventFlags, int rssi) {
+ Log.d(TAG, "onRssiData rssi=" + rssi);
+ mLastRssi = rssi;
+ if (mObserver != null) {
+ mObserver.onDeviceRssiChanged();
+ }
+ }
+ };
+
+ public static String deviceStateToString(Context context, DeviceState state) {
+ switch (state) {
+ case DEAD:
+ return context.getString(R.string.state_dead);
+ case CLOSED:
+ return context.getString(R.string.state_closed);
+ case SEARCHING:
+ return context.getString(R.string.state_searching);
+ case TRACKING:
+ return context.getString(R.string.state_tracking);
+ case PROCESSING_REQUEST:
+ return context.getString(R.string.state_processing);
+ case UNRECOGNIZED:
+ return context.getString(R.string.state_unrecognized);
+ default:
+ return context.getString(R.string.state_unknown);
+ }
+ }
+
+ public static String connectionRequestAccessResultToString(Context context, RequestAccessResult result) {
+ switch (result) {
+ case SUCCESS:
+ return context.getString(R.string.connection_result_success);
+ case USER_CANCELLED:
+ return context.getString(R.string.connection_result_user_cancelled);
+ case CHANNEL_NOT_AVAILABLE:
+ return context.getString(R.string.connection_result_channel_not_available);
+ case OTHER_FAILURE:
+ return context.getString(R.string.connection_result_other_failure);
+ case DEPENDENCY_NOT_INSTALLED:
+ return context.getString(R.string.connection_result_dependency_not_installed);
+ case DEVICE_ALREADY_IN_USE:
+ return context.getString(R.string.connection_result_device_already_in_use);
+ case SEARCH_TIMEOUT:
+ return context.getString(R.string.connection_result_search_timeout);
+ case ALREADY_SUBSCRIBED:
+ return context.getString(R.string.connection_result_already_subscribed);
+ case BAD_PARAMS:
+ return context.getString(R.string.connection_result_bad_params);
+ case ADAPTER_NOT_DETECTED:
+ return context.getString(R.string.connection_result_adapter_not_detected);
+ case UNRECOGNIZED:
+ return context.getString(R.string.connection_result_unrecognized);
+ default:
+ return context.getString(R.string.connection_result_unknown);
+ }
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/com/javispedro/rempe/DeviceListRecyclerViewListAdapter.java b/app/src/main/java/com/javispedro/rempe/DeviceListRecyclerViewListAdapter.java
new file mode 100644
index 0000000..2288f20
--- /dev/null
+++ b/app/src/main/java/com/javispedro/rempe/DeviceListRecyclerViewListAdapter.java
@@ -0,0 +1,44 @@
+package com.javispedro.rempe;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.List;
+
+/**
+ * {@link RecyclerView.Adapter} that can display a {@link Device}.
+ */
+public class DeviceListRecyclerViewListAdapter extends RecyclerView.Adapter<DeviceViewHolder> {
+
+ private List<Device> mList;
+
+ @Override
+ @NonNull
+ public DeviceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.fragment_device, parent, false);
+ return new DeviceViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(final DeviceViewHolder holder, int position) {
+ holder.setDevice(mList.get(position));
+ }
+
+ @Override
+ public int getItemCount() {
+ if (mList != null) {
+ return mList.size();
+ } else {
+ return 0;
+ }
+ }
+
+ public void setDeviceList(List<Device> list) {
+ mList = list;
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/com/javispedro/rempe/DeviceViewHolder.java b/app/src/main/java/com/javispedro/rempe/DeviceViewHolder.java
new file mode 100644
index 0000000..9731471
--- /dev/null
+++ b/app/src/main/java/com/javispedro/rempe/DeviceViewHolder.java
@@ -0,0 +1,123 @@
+package com.javispedro.rempe;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.dsi.ant.plugins.antplus.pcc.defines.RequestAccessResult;
+
+import java.math.BigDecimal;
+
+public class DeviceViewHolder extends RecyclerView.ViewHolder implements Device.DeviceObserver {
+ private static final String TAG = "DeviceViewHolder";
+
+ private final View mView;
+ private final Context mContext;
+
+ private final TextView mTemperatureView;
+ private final TextView mMinTemperatureView;
+ private final TextView mMaxTemperatureView;
+ private final TextView mNameView;
+ private final TextView mStatusView;
+ private final ProgressBar mSignalBar;
+ private final TextView mSignalLabel;
+
+ private Device mDevice;
+
+ public DeviceViewHolder(View view) {
+ super(view);
+ mView = view;
+ mContext = view.getContext();
+ mNameView = view.findViewById(R.id.nameView);
+ mStatusView = view.findViewById(R.id.statusView);
+ mTemperatureView = view.findViewById(R.id.temperatureView);
+ mMinTemperatureView = view.findViewById(R.id.minTemperatureView);
+ mMaxTemperatureView = view.findViewById(R.id.maxTemperatureView);
+ mSignalBar = view.findViewById(R.id.signalBar);
+ mSignalLabel = view.findViewById(R.id.signalLabel);
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + " '" + mNameView.getText() + "'";
+ }
+
+ public void setDevice(Device device) {
+ resetDisplay();
+ if (mDevice != null) {
+ mDevice.setObserver(null);
+ }
+ mDevice = device;
+ if (mDevice != null) {
+ mNameView.setText(mDevice.getDeviceName());
+ mDevice.setObserver(this);
+ }
+ }
+
+ private void runOnUiThread(Runnable r) {
+ mView.post(r);
+ }
+
+ private void resetDisplay() {
+ mTemperatureView.setText(mContext.getString(R.string.temperature_nothing));
+ mMinTemperatureView.setText(mContext.getString(R.string.temperature_nothing));
+ mMaxTemperatureView.setText(mContext.getString(R.string.temperature_nothing));
+ mNameView.setText("");
+ mStatusView.setText("");
+ mSignalBar.setProgress(0);
+ mSignalLabel.setVisibility(View.INVISIBLE);
+ }
+
+ private String formatTemperature(BigDecimal temp) {
+ final String value = temp.setScale(1, BigDecimal.ROUND_HALF_EVEN).toPlainString();
+ return mContext.getString(R.string.temperature_celsius, value);
+ }
+
+ @Override
+ public void onDeviceInfoChanged() {
+ runOnUiThread(() -> {
+ mNameView.setText(mDevice.getDeviceName());
+ });
+ }
+
+ @Override
+ public void onDeviceStateChanged() {
+ runOnUiThread(() -> {
+ if (mDevice.getConnectResult() != RequestAccessResult.SUCCESS) {
+ mStatusView.setText(Device.connectionRequestAccessResultToString(mContext, mDevice.getConnectResult()));
+ } else {
+ mStatusView.setText(Device.deviceStateToString(mContext, mDevice.getCurrentDeviceState()));
+ }
+ });
+ }
+
+ @Override
+ public void onDeviceNewReading() {
+ runOnUiThread(() -> {
+ final Reading reading = mDevice.getLastReading();
+ mTemperatureView.setText(formatTemperature(reading.temperature));
+ mMinTemperatureView.setText(formatTemperature(reading.lowLast24Hours));
+ mMaxTemperatureView.setText(formatTemperature(reading.highLast24Hours));
+ });
+ }
+
+ private int rssiToMeterValue(float rssi) {
+ final float minThreshold = -100;
+ final float maxThreshold = 0;
+
+ final float step = (maxThreshold - minThreshold) / 100;
+
+ return Math.round((rssi - minThreshold) / step);
+ }
+
+ @Override
+ public void onDeviceRssiChanged() {
+ runOnUiThread(() -> {
+ mSignalBar.setProgress(rssiToMeterValue(mDevice.getLastRssi()));
+ mSignalLabel.setVisibility(View.VISIBLE);
+ });
+ }
+}
diff --git a/app/src/main/java/com/javispedro/rempe/MainActivity.java b/app/src/main/java/com/javispedro/rempe/MainActivity.java
new file mode 100644
index 0000000..e458468
--- /dev/null
+++ b/app/src/main/java/com/javispedro/rempe/MainActivity.java
@@ -0,0 +1,264 @@
+package com.javispedro.rempe;
+
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+import androidx.preference.PreferenceManager;
+import androidx.recyclerview.widget.DiffUtil;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.ListUpdateCallback;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.dsi.ant.plugins.antplus.pcc.AntPlusEnvironmentPcc;
+import com.dsi.ant.plugins.antplus.pcc.defines.DeviceState;
+import com.dsi.ant.plugins.antplus.pcc.defines.RequestAccessResult;
+import com.dsi.ant.plugins.antplus.pccbase.AntPluginPcc;
+import com.dsi.ant.plugins.antplus.pccbase.PccReleaseHandle;
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+import com.google.android.material.snackbar.Snackbar;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MainActivity extends AppCompatActivity {
+ private final static String TAG = "MainActivity";
+
+ private SharedPreferences mPrefs = null;
+ private SharedPreferences.OnSharedPreferenceChangeListener mPrefsListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ switch (key) {
+ case Preferences.PREFS_DEVICES:
+ refreshDevices();
+ break;
+ }
+ }
+ };
+
+ private final ArrayList<Integer> mDeviceNumbers = new ArrayList<Integer>();
+ private final ArrayList<Device> mDevices = new ArrayList<Device>();
+
+ private DeviceListRecyclerViewListAdapter mDeviceListAdapter;
+
+ private PccReleaseHandle<AntPlusEnvironmentPcc> mPccSearchHandle;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+
+ setContentView(R.layout.activity_main);
+ Toolbar toolbar = findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ FloatingActionButton fab = findViewById(R.id.fabAddDevice);
+ fab.setOnClickListener(view -> onConnectButtonClicked());
+
+ RecyclerView list = findViewById(R.id.list);
+ list.setLayoutManager(new LinearLayoutManager(list.getContext()));
+ mDeviceListAdapter = new DeviceListRecyclerViewListAdapter();
+ list.setAdapter(mDeviceListAdapter);
+
+ refreshDevices();
+ }
+
+ @Override
+ protected void onDestroy() {
+ disconnectAll();
+ mPrefs = null;
+ mDeviceListAdapter = null;
+ super.onDestroy();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mPrefs.registerOnSharedPreferenceChangeListener(mPrefsListener);
+ connectToDevices();
+ }
+
+ @Override
+ public void onPause() {
+ disconnectAll();
+ mPrefs.unregisterOnSharedPreferenceChangeListener(mPrefsListener);
+ super.onPause();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.menu_main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle action bar item clicks here. The action bar will
+ // automatically handle clicks on the Home/Up button, so long
+ // as you specify a parent activity in AndroidManifest.xml.
+ int id = item.getItemId();
+
+ switch (id) {
+ case R.id.action_remove_all:
+ removeAllDevices();
+ return true;
+ case R.id.action_settings:
+ return true;
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void onConnectButtonClicked() {
+ searchForNewDevice();
+ }
+
+ public void searchForNewDevice() {
+ Log.d(TAG, "searchForNewDevice");
+ if (mPccSearchHandle != null) {
+ mPccSearchHandle.close();
+ mPccSearchHandle = null;
+ }
+ mPccSearchHandle = AntPlusEnvironmentPcc.requestAccess(this, this, mResultReceiver, mDeviceStateChangeReceiver);
+ }
+
+ private AntPluginPcc.IPluginAccessResultReceiver<AntPlusEnvironmentPcc> mResultReceiver = new AntPluginPcc.IPluginAccessResultReceiver<AntPlusEnvironmentPcc>() {
+ @Override
+ public void onResultReceived(AntPlusEnvironmentPcc result, RequestAccessResult resultCode, DeviceState initialDeviceState) {
+ Log.d(TAG, "onResultReceived resultCode=" + resultCode);
+ if (resultCode == RequestAccessResult.SUCCESS) {
+ int deviceNumber = result.getAntDeviceNumber();
+ result.releaseAccess();
+ runOnUiThread(() -> addDevice(result.getAntDeviceNumber()));
+ } else if (resultCode != RequestAccessResult.USER_CANCELLED) {
+ runOnUiThread(() -> {
+ final String resultText = Device.connectionRequestAccessResultToString(MainActivity.this, resultCode);
+ Snackbar.make(findViewById(R.id.fabAddDevice),
+ getString(R.string.add_device_failed, resultText), Snackbar.LENGTH_INDEFINITE).show();
+ });
+ }
+ mPccSearchHandle.close();
+ mPccSearchHandle = null;
+ }
+ };
+
+ private AntPluginPcc.IDeviceStateChangeReceiver mDeviceStateChangeReceiver = new AntPluginPcc.IDeviceStateChangeReceiver() {
+ @Override
+ public void onDeviceStateChange(DeviceState newDeviceState) {
+ Log.d(TAG, "onDeviceStateChange newDeviceState=" + newDeviceState);
+ }
+ };
+
+ public void addDevice(int deviceNumber) {
+ Log.d(TAG, "addDevice " + deviceNumber);
+ List<Integer> list = Preferences.getDeviceNumbers(mPrefs);
+ if (list.contains(deviceNumber)) {
+ Snackbar.make(findViewById(R.id.fabAddDevice),
+ getString(R.string.add_device_already), Snackbar.LENGTH_INDEFINITE).show();
+ return;
+ }
+ list.add(deviceNumber);
+ Preferences.saveDeviceNumbers(mPrefs, list);
+ }
+
+ public void removeAllDevices() {
+ List<Integer> list = new ArrayList<Integer>();
+ Preferences.saveDeviceNumbers(mPrefs, list);
+ }
+
+ public void refreshDevices() {
+ Log.d(TAG, "refreshDevices");
+
+ setDeviceNumberList(Preferences.getDeviceNumbers(mPrefs));
+ }
+
+ public void connectToDevices() {
+ Log.d(TAG, "connectToDevices");
+ for (Device dev : mDevices) {
+ if (!dev.isOpen()) {
+ dev.connect(this);
+ }
+ }
+ }
+
+ public void disconnectAll() {
+ Log.d(TAG, "disconnectAll");
+ for (Device dev : mDevices) {
+ dev.close();
+ }
+ }
+
+ void setDeviceNumberList(List<Integer> newDeviceNumbers) {
+ DiffUtil.DiffResult diff = DiffUtil.calculateDiff(new DiffUtil.Callback() {
+ @Override
+ public int getOldListSize() {
+ return mDeviceNumbers.size();
+ }
+
+ @Override
+ public int getNewListSize() {
+ return newDeviceNumbers.size();
+ }
+
+ @Override
+ public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
+ return mDeviceNumbers.get(oldItemPosition).equals(newDeviceNumbers.get(newItemPosition));
+ }
+
+ @Override
+ public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
+ return areItemsTheSame(oldItemPosition, newItemPosition);
+ }
+ });
+
+ diff.dispatchUpdatesTo(new ListUpdateCallback() {
+ @Override
+ public void onInserted(int position, int count) {
+ for (int i = 0; i < count; ++i) {
+ final int deviceNumber = newDeviceNumbers.get(position + i);
+ Device device = new Device(deviceNumber);
+ mDeviceNumbers.add(position + i, deviceNumber);
+ mDevices.add(position + i, device);
+ }
+ }
+
+ @Override
+ public void onRemoved(int position, int count) {
+ for (int i = 0; i < count; ++i) {
+ mDevices.get(position + i).close();
+ }
+ mDevices.subList(position, position + count).clear();
+ mDeviceNumbers.subList(position, position + count).clear();
+ }
+
+ @Override
+ public void onMoved(int fromPosition, int toPosition) {
+ mDevices.set(toPosition, mDevices.get(fromPosition));
+ mDevices.set(fromPosition, null);
+ mDeviceNumbers.set(toPosition, mDeviceNumbers.get(fromPosition));
+ mDeviceNumbers.set(fromPosition, 0);
+ }
+
+ @Override
+ public void onChanged(int position, int count, @Nullable Object payload) {
+ // Nothing to be done
+ }
+ });
+
+ if (mDeviceListAdapter != null) {
+ mDeviceListAdapter.setDeviceList(mDevices);
+ diff.dispatchUpdatesTo(mDeviceListAdapter);
+ }
+ }
+
+ public List<Integer> getDeviceNumberList() {
+ return mDeviceNumbers;
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/com/javispedro/rempe/Preferences.java b/app/src/main/java/com/javispedro/rempe/Preferences.java
new file mode 100644
index 0000000..41c943c
--- /dev/null
+++ b/app/src/main/java/com/javispedro/rempe/Preferences.java
@@ -0,0 +1,43 @@
+package com.javispedro.rempe;
+
+import android.content.SharedPreferences;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import static android.content.ContentValues.TAG;
+
+class Preferences {
+ public final static String PREFS_DEVICES = "devices";
+
+ public static List<Integer> getDeviceNumbers(SharedPreferences prefs) {
+ ArrayList<Integer> result = new ArrayList<Integer>();
+
+ try {
+ StringTokenizer st = new StringTokenizer(prefs.getString(PREFS_DEVICES, ""), ",");
+ while (st.hasMoreTokens()) {
+ result.add(Integer.parseInt(st.nextToken()));
+ }
+ } catch (java.lang.Exception ex) {
+ // Ensure that at least we can recover from a corrupted preferences situation...
+ Log.e(TAG, ex.toString());
+ }
+
+ return result;
+ }
+
+ public static void saveDeviceNumbers(SharedPreferences prefs, List<Integer> list) {
+ StringBuilder sb = new StringBuilder();
+ for (Integer i : list) {
+ sb.append(i.toString());
+ sb.append(",");
+ }
+ final String pref = sb.toString();
+ Log.d(TAG, "saveDeviceNumbers: " + pref);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString(PREFS_DEVICES, pref);
+ editor.apply();
+ }
+}
diff --git a/app/src/main/java/com/javispedro/rempe/Reading.java b/app/src/main/java/com/javispedro/rempe/Reading.java
new file mode 100644
index 0000000..a49e29a
--- /dev/null
+++ b/app/src/main/java/com/javispedro/rempe/Reading.java
@@ -0,0 +1,12 @@
+package com.javispedro.rempe;
+
+import java.math.BigDecimal;
+
+public class Reading {
+ public long timestamp;
+
+ public BigDecimal temperature;
+
+ public BigDecimal lowLast24Hours;
+ public BigDecimal highLast24Hours;
+}