package com.javispedro.rempe; import android.app.Activity; 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"; public static final int INVALID_DEVICE = -1; private int mDeviceNumber; private PccReleaseHandle 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 onDeviceSearchFinished(RequestAccessResult result); void onDeviceInfoChanged(); void onDeviceStateChanged(); void onDeviceNewReading(); void onDeviceRssiChanged(); } private DeviceObserver mObserver; /** Creates empty Device object not attached to a specific device number. * Only valid operation is searchForDevice. */ public Device() { mDeviceNumber = INVALID_DEVICE; mDeviceName = null; mConnectResult = RequestAccessResult.SUCCESS; mCurState = DeviceState.DEAD; } /** Creates Device object with deviceNumber. Initial state will be unconnected. * Can use connect() afterwards. */ public Device(int deviceNumber, String initialDeviceName) { mDeviceNumber = deviceNumber; mDeviceName = initialDeviceName; mConnectResult = RequestAccessResult.SUCCESS; mCurState = DeviceState.DEAD; } public void searchForDevice(Activity parentActivity) { Log.d(TAG, "searchForNewDevice"); if (isOpen()) { Log.e(TAG, "Already open"); return; } // Clear old state mConnectResult = RequestAccessResult.BAD_PARAMS; mCurState = DeviceState.DEAD; if (mObserver != null) { mObserver.onDeviceStateChanged(); } mEnvPccHandle = AntPlusEnvironmentPcc.requestAccess(parentActivity, parentActivity, mResultReceiver, mDeviceStateChangeReceiver); } public void connect(Context context) { Log.d(TAG, "connect (" + mDeviceNumber + ")"); if (isOpen()) { Log.e(TAG, "Already open"); return; } // Clear old connect result / state mConnectResult = RequestAccessResult.SUCCESS; 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 (mEnvPcc != null) { mEnvPcc.subscribeTemperatureDataEvent(null); mEnvPcc.subscribeRssiEvent(null); mEnvPcc.releaseAccess(); mEnvPcc = null; } if (mEnvPccHandle != null) { mEnvPccHandle.close(); mEnvPccHandle = 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) { assert mEnvPcc == null; mEnvPcc = envPcc; final String deviceName = mEnvPcc.getDeviceName(); final int deviceNumber = mEnvPcc.getAntDeviceNumber(); Log.d(TAG, "handleConnection deviceName=" + deviceName + " deviceNumber=" + deviceNumber); if (mDeviceNumber == INVALID_DEVICE) { mDeviceNumber = deviceNumber; // This is the initial search } else if (deviceNumber != mDeviceNumber) { // We tried to reconnect to a device and now it has a different number? Log.e(TAG, "device number mismatch"); } mDeviceName = deviceName; mEnvPcc.subscribeTemperatureDataEvent(mTemperatureDataReceiver); mEnvPcc.subscribeRssiEvent(mRssiReceiver); if (mObserver != null) { mObserver.onDeviceInfoChanged(); } } public int getDeviceNumber() { return mDeviceNumber; } 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 final AntPluginPcc.IPluginAccessResultReceiver mResultReceiver = new AntPluginPcc.IPluginAccessResultReceiver() { @Override public void onResultReceived(AntPlusEnvironmentPcc result, RequestAccessResult resultCode, DeviceState initialDeviceState) { Log.d(TAG, "onResultReceived resultCode=" + resultCode + " initialDeviceState=" + initialDeviceState); mConnectResult = resultCode; mCurState = initialDeviceState; if (resultCode == RequestAccessResult.SUCCESS) { setEnvPcc(result); } if (mObserver != null) { mObserver.onDeviceSearchFinished(resultCode); } if (mObserver != null) { mObserver.onDeviceStateChanged(); } } }; private final 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 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 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); } } }