/*
* Copyright (c) 2013, Will Szumski
* Copyright (c) 2013, Doug Szumski
*
* This file is part of Cyclismo.
*
* Cyclismo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Cyclismo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Cyclismo. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.cowboycoders.cyclismo;
import android.os.Bundle;
import android.os.RemoteException;
import android.text.format.DateFormat;
import android.util.Log;
import android.widget.TextView;
import com.google.protobuf.InvalidProtocolBufferException;
import org.cowboycoders.cyclismo.content.Sensor;
import org.cowboycoders.cyclismo.services.ITrackRecordingService;
import org.cowboycoders.cyclismo.services.TrackRecordingServiceConnection;
import org.cowboycoders.cyclismo.services.sensors.SensorManager;
import org.cowboycoders.cyclismo.services.sensors.SensorManagerFactory;
import org.cowboycoders.cyclismo.services.sensors.SensorUtils;
import org.cowboycoders.cyclismo.util.TrackRecordingServiceConnectionUtils;
import java.util.Timer;
import java.util.TimerTask;
/**
* An activity that displays information about sensors.
*
* @author Sandor Dornbush
*/
public class SensorStateActivity extends AbstractMyTracksActivity {
private static final String TAG = SensorStateActivity.class.getName();
private static final long REFRESH_PERIOD_MS = 250;
/**
* A Runnable to update the UI.
*/
private final Runnable updateRunnable = new Runnable() {
public void run() {
ITrackRecordingService trackRecordingService = trackRecordingServiceConnection
.getServiceIfBound();
// Check if service is available and recording
boolean isRecording = false;
if (trackRecordingService != null) {
try {
isRecording = trackRecordingService.isRecording();
} catch (RemoteException e) {
Log.e(TAG, "Unable to determine if the track recording service is recording.", e);
}
}
if (!isRecording) {
updateFromTempSensorManager();
} else {
stopTempSensorManager();
updateFromSystemSensorManager();
}
}
};
/**
* A TimeTask to update the UI.
*/
private class UpdateTimerTask extends TimerTask {
@Override
public void run() {
if (isVisible) {
runOnUiThread(updateRunnable);
}
}
};
private TrackRecordingServiceConnection trackRecordingServiceConnection;
private boolean isVisible = false;
private Timer timer = null;
private SensorManager tempSensorManager = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
trackRecordingServiceConnection = new TrackRecordingServiceConnection(this, null);
}
@Override
protected void onStart() {
super.onStart();
TrackRecordingServiceConnectionUtils.startConnection(this, trackRecordingServiceConnection);
}
@Override
protected void onResume() {
super.onResume();
isVisible = true;
timer = new Timer();
timer.schedule(new UpdateTimerTask(), 0, REFRESH_PERIOD_MS);
}
@Override
protected void onPause() {
super.onPause();
isVisible = false;
timer.cancel();
timer.purge();
timer = null;
stopTempSensorManager();
}
@Override
protected void onStop() {
super.onStop();
trackRecordingServiceConnection.unbind();
}
@Override
protected int getLayoutResId() {
return R.layout.sensor_state;
}
/**
* Stops the temp sensor manager.
*/
private void stopTempSensorManager() {
if (tempSensorManager != null) {
SensorManagerFactory.releaseTempSensorManager();
tempSensorManager = null;
}
}
/**
* Updates from a temp sensor manager.
*/
private void updateFromTempSensorManager() {
Sensor.SensorState sensorState = Sensor.SensorState.NONE;
Sensor.SensorDataSet sensorDataSet = null;
if (tempSensorManager == null) {
tempSensorManager = SensorManagerFactory.getTempSensorManager(this);
}
if (tempSensorManager != null) {
sensorState = tempSensorManager.getSensorState();
sensorDataSet = tempSensorManager.getSensorDataSet();
}
updateSensorStateAndDataSet(sensorState, sensorDataSet);
}
/**
* Updates from the system sensor manager.
*/
private void updateFromSystemSensorManager() {
Sensor.SensorState sensorState = Sensor.SensorState.NONE;
Sensor.SensorDataSet sensorDataSet = null;
ITrackRecordingService trackRecordingService = trackRecordingServiceConnection
.getServiceIfBound();
// Get sensor details from the service.
if (trackRecordingService == null) {
Log.d(TAG, "Cannot get teh track recording service.");
} else {
try {
sensorState = Sensor.SensorState.valueOf(trackRecordingService.getSensorState());
} catch (RemoteException e) {
Log.e(TAG, "Cannote read sensor state.", e);
sensorState = Sensor.SensorState.NONE;
}
try {
byte[] buff = trackRecordingService.getSensorData();
if (buff != null) {
sensorDataSet = Sensor.SensorDataSet.parseFrom(buff);
}
} catch (RemoteException e) {
Log.e(TAG, "Cannot read sensor data set.", e);
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "Cannot read sensor data set.", e);
}
}
updateSensorStateAndDataSet(sensorState, sensorDataSet);
}
/**
* Updates the sensor state and data set.
*
* @param sensorState sensor state
* @param sensorDataSet sensor data set
*/
private void updateSensorStateAndDataSet(
Sensor.SensorState sensorState, Sensor.SensorDataSet sensorDataSet) {
((TextView) findViewById(R.id.sensor_state)).setText(
SensorUtils.getStateAsString(sensorState, this));
String lastSensorTime = sensorDataSet == null ? getString(R.string.value_unknown)
: getLastSensorTime(sensorDataSet);
String heartRate = sensorDataSet == null ? getString(R.string.value_unknown)
: getHeartRate(sensorDataSet);
String cadence = sensorDataSet == null ? getString(R.string.value_unknown)
: getCadence(sensorDataSet);
String power = sensorDataSet == null ? getString(R.string.value_unknown)
: getPower(sensorDataSet);
String battery = sensorDataSet == null ? getString(R.string.value_unknown)
: getBattery(sensorDataSet);
((TextView) findViewById(R.id.sensor_state_last_sensor_time)).setText(lastSensorTime);
((TextView) findViewById(R.id.sensor_state_heart_rate)).setText(heartRate);
((TextView) findViewById(R.id.sensor_state_cadence)).setText(cadence);
((TextView) findViewById(R.id.sensor_state_power)).setText(power);
((TextView) findViewById(R.id.sensor_state_battery)).setText(battery);
}
/**
* Gets the last sensor time.
*
* @param sensorDataSet sensor data set
*/
private String getLastSensorTime(Sensor.SensorDataSet sensorDataSet) {
return DateFormat.format("h:mm:ss aa", sensorDataSet.getCreationTime()).toString();
}
/**
* Gets the heart rate.
*
* @param sensorDataSet sensor data set
*/
private String getHeartRate(Sensor.SensorDataSet sensorDataSet) {
String value;
if (sensorDataSet.hasHeartRate() && sensorDataSet.getHeartRate().hasValue()
&& sensorDataSet.getHeartRate().getState() == Sensor.SensorState.SENDING) {
value = getString(
R.string.sensor_state_heart_rate_value, sensorDataSet.getHeartRate().getValue());
} else {
value = SensorUtils.getStateAsString(
sensorDataSet.hasHeartRate() ? sensorDataSet.getHeartRate().getState()
: Sensor.SensorState.NONE, this);
}
return value;
}
/**
* Gets the cadence.
*
* @param sensorDataSet sensor data set
*/
private String getCadence(Sensor.SensorDataSet sensorDataSet) {
String value;
if (sensorDataSet.hasCadence() && sensorDataSet.getCadence().hasValue()
&& sensorDataSet.getCadence().getState() == Sensor.SensorState.SENDING) {
value = getString(R.string.sensor_state_cadence_value, sensorDataSet.getCadence().getValue());
} else {
value = SensorUtils.getStateAsString(
sensorDataSet.hasCadence() ? sensorDataSet.getCadence().getState()
: Sensor.SensorState.NONE, this);
}
return value;
}
/**
* Gets the power.
*
* @param sensorDataSet sensor data set
*/
private String getPower(Sensor.SensorDataSet sensorDataSet) {
String value;
if (sensorDataSet.hasPower() && sensorDataSet.getPower().hasValue()
&& sensorDataSet.getPower().getState() == Sensor.SensorState.SENDING) {
value = getString(R.string.sensor_state_power_value, sensorDataSet.getPower().getValue());
} else {
value = SensorUtils.getStateAsString(
sensorDataSet.hasPower() ? sensorDataSet.getPower().getState() : Sensor.SensorState.NONE,
this);
}
return value;
}
/**
* Gets the battery.
*
* @param sensorDataSet sensor data set
*/
private String getBattery(Sensor.SensorDataSet sensorDataSet) {
String value;
if (sensorDataSet.hasBatteryLevel() && sensorDataSet.getBatteryLevel().hasValue()
&& sensorDataSet.getBatteryLevel().getState() == Sensor.SensorState.SENDING) {
value = getString(R.string.value_integer_percent, sensorDataSet.getBatteryLevel().getValue());
} else {
value = SensorUtils.getStateAsString(
sensorDataSet.hasBatteryLevel() ? sensorDataSet.getBatteryLevel().getState()
: Sensor.SensorState.NONE, this);
}
return value;
}
}