/*
HeartRateHealthProfile
Copyright (c) 2015 NTT DOCOMO,INC.
Released under the MIT license
http://opensource.org/licenses/mit-license.php
*/
package org.deviceconnect.android.deviceplugin.heartrate.profile;
import android.content.Intent;
import android.os.Bundle;
import org.deviceconnect.android.deviceplugin.heartrate.HeartRateDeviceService;
import org.deviceconnect.android.deviceplugin.heartrate.HeartRateManager;
import org.deviceconnect.android.deviceplugin.heartrate.ble.BleUtils;
import org.deviceconnect.android.deviceplugin.heartrate.data.HeartRateData;
import org.deviceconnect.android.deviceplugin.heartrate.data.HeartRateDevice;
import org.deviceconnect.android.deviceplugin.heartrate.data.health.TargetDeviceData;
import org.deviceconnect.android.deviceplugin.heartrate.util.RawDataParseUtils;
import org.deviceconnect.android.event.Event;
import org.deviceconnect.android.event.EventDispatcher;
import org.deviceconnect.android.event.EventDispatcherFactory;
import org.deviceconnect.android.event.EventDispatcherManager;
import org.deviceconnect.android.event.EventError;
import org.deviceconnect.android.event.EventManager;
import org.deviceconnect.android.message.DConnectMessageService;
import org.deviceconnect.android.message.MessageUtils;
import org.deviceconnect.android.profile.HealthProfile;
import org.deviceconnect.android.profile.api.DConnectApi;
import org.deviceconnect.android.profile.api.DeleteApi;
import org.deviceconnect.android.profile.api.GetApi;
import org.deviceconnect.android.profile.api.PutApi;
import org.deviceconnect.message.DConnectMessage;
import java.util.List;
/**
* Implement HealthProfile.
* @author NTT DOCOMO, INC.
*/
public class HeartRateHealthProfile extends HealthProfile {
/**
* Event Dispatcher object.
*/
private EventDispatcherManager mDispatcherManager;
/**
* Implementation of {@link HeartRateManager.OnHeartRateEventListener}.
*/
private final HeartRateManager.OnHeartRateEventListener mHeartRateEventListener =
new HeartRateManager.OnHeartRateEventListener() {
@Override
public void onReceivedData(final HeartRateDevice device, final HeartRateData data) {
notifyHeartRateDataOld(device, data);
notifyHeartRateData(device, data);
}
};
private final DConnectApi mGetHeartRateApi = new GetApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_HEART_RATE;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
String serviceId = getServiceID(request);
HeartRateData data = getManager().getHeartRateData(serviceId);
if (data == null) {
MessageUtils.setNotFoundServiceError(response);
} else {
setResult(response, DConnectMessage.RESULT_OK);
setHeartRate(response, data.getHeartRate());
}
return true;
}
};
private final DConnectApi mPutHeartRateApi = new PutApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_HEART_RATE;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
String serviceId = getServiceID(request);
HeartRateData data = getManager().getHeartRateData(serviceId);
if (data == null) {
MessageUtils.setNotFoundServiceError(response);
} else {
EventError error = EventManager.INSTANCE.addEvent(request);
if (error == EventError.NONE) {
setResult(response, DConnectMessage.RESULT_OK);
} else {
MessageUtils.setUnknownError(response);
}
}
return true;
}
};
private final DConnectApi mDeleteHeartRateApi = new DeleteApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_HEART_RATE;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
EventError error = EventManager.INSTANCE.removeEvent(request);
if (error == EventError.NONE) {
setResult(response, DConnectMessage.RESULT_OK);
} else if (error == EventError.INVALID_PARAMETER) {
MessageUtils.setInvalidRequestParameterError(response);
} else if (error == EventError.FAILED) {
MessageUtils.setUnknownError(response, "Failed to delete event.");
} else if (error == EventError.NOT_FOUND) {
MessageUtils.setUnknownError(response, "Not found event.");
} else {
MessageUtils.setUnknownError(response);
}
return true;
}
};
/**
* Get Heart rate.
*/
private final DConnectApi mGetHeart = new GetApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_HEART;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
return getHeart(request, response);
}
};
/**
* Register event heart rate.
*/
private final DConnectApi mPutHeart = new PutApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_HEART;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
registerHeartEvent(request, response);
return true;
}
};
/**
* Unregister event heart rate.
*/
private final DConnectApi mDeleteHeart = new DeleteApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_HEART;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
unregisterHeartEvent(request, response);
return true;
}
};
/**
* Get Heart rate.
*/
private final DConnectApi mGetOnHeart = new GetApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_ONHEART;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
return getHeart(request, response);
}
};
/**
* Register event heart rate.
*/
private final DConnectApi mPutOnHeart = new PutApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_ONHEART;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
registerHeartEvent(request, response);
return true;
}
};
/**
* Unregister event heart rate.
*/
private final DConnectApi mDeleteOnHeart = new DeleteApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_ONHEART;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
unregisterHeartEvent(request, response);
return true;
}
};
/**
* Get Heart Rate bundle object.
* @param data heart rate data
* @return bundle object
*/
private Bundle getHeartRateBundle(final HeartRateDevice device, final HeartRateData data) {
Bundle heart = new Bundle();
double rri = data.getRRInterval();
org.deviceconnect.android.deviceplugin.heartrate.data.health.HeartRateData health
= new org.deviceconnect.android.deviceplugin.heartrate.data.health.HeartRateData();
health.setRRInterval(RawDataParseUtils.parseRRI((float) rri));
health.setHeartRate(RawDataParseUtils.parseHeartRate((float) data.getHeartRate()));
health.setEnergyExpended(RawDataParseUtils.parseEnergyExpended((float) data.getEnergyExpended()));
HealthProfile.setRate(heart, health.getHeartRate().toBundle());
if (health.getRRInterval() != null) {
HealthProfile.setRRI(heart, health.getRRInterval().toBundle());
}
if (health.getEnergyExpended() != null) {
HealthProfile.setEnergyExtended(heart, health.getEnergyExpended().toBundle());
}
if (device != null) {
TargetDeviceData target = RawDataParseUtils.parseDeviceData(device, -1);
HealthProfile.setDevice(heart, target.toBundle());
}
return heart;
}
/**
* Constructor.
* @param mgr instance of {@link HeartRateManager}
*/
public HeartRateHealthProfile(final HeartRateManager mgr) {
mgr.setOnHeartRateEventListener(mHeartRateEventListener);
mDispatcherManager = new EventDispatcherManager();
addApi(mGetHeartRateApi);
addApi(mPutHeartRateApi);
addApi(mDeleteHeartRateApi);
addApi(mGetOnHeart);
addApi(mPutOnHeart);
addApi(mDeleteOnHeart);
// GotAPI 1.1
addApi(mGetHeart);
addApi(mPutHeart);
addApi(mDeleteHeart);
}
/**
* Bluetoothの有効設定やパーミッション設定を確認します.
* @param callback 確認した結果を通知するリスナー
*/
private void checkBleSettings(final BleUtils.BleRequestCallback callback) {
HeartRateManager mgr = getManager();
if (mgr == null) {
callback.onFail("Failed to initialize a HeartRateManager.");
return;
}
if (!mgr.isEnabledBle()) {
BleUtils.requestBluetoothEnabled(getContext(), new BleUtils.BleRequestCallback() {
@Override
public void onSuccess() {
BleUtils.requestBLEPermission(getContext(), callback);
}
@Override
public void onFail(final String deniedPermission) {
callback.onFail(deniedPermission);
}
});
} else {
BleUtils.requestBLEPermission(getContext(), callback);
}
}
/**
* Register HeartRate Event.
* @param request Request Message
* @param response Response Message
*/
private void registerHeartEvent(Intent request, Intent response) {
String serviceId = getServiceID(request);
if (serviceId == null) {
MessageUtils.setNotFoundServiceError(response, "Not found serviceID");
} else {
HeartRateData data = getManager().getHeartRateData(serviceId);
if (data == null) {
MessageUtils.setNotFoundServiceError(response);
} else {
EventError error = EventManager.INSTANCE.addEvent(request);
if (error == EventError.NONE) {
addEventDispatcher(request);
setResult(response, DConnectMessage.RESULT_OK);
} else {
MessageUtils.setUnknownError(response);
}
}
}
}
/**
* Get HeartRate Response.
* @param request Request Message
* @param response Response Message
* @return true:sync false:async
*/
private boolean getHeart(Intent request, Intent response) {
String serviceId = getServiceID(request);
if (serviceId == null) {
MessageUtils.setEmptyServiceIdError(response);
} else {
HeartRateData data = getManager().getHeartRateData(serviceId);
HeartRateDevice device = getManager().getHeartRateDevice(serviceId);
if (data == null || device == null) {
MessageUtils.setNotFoundServiceError(response);
} else {
setResult(response, DConnectMessage.RESULT_OK);
setHeart(response, getHeartRateBundle(device, data));
}
}
return true;
}
/**
* Unregister Heart rate Event.
* @param request Request Message
* @param response Response Message
*/
private void unregisterHeartEvent(Intent request, Intent response) {
String serviceId = getServiceID(request);
if (serviceId == null) {
MessageUtils.setEmptyServiceIdError(response);
} else {
removeEventDispatcher(request);
EventError error = EventManager.INSTANCE.removeEvent(request);
if (error == EventError.NONE) {
setResult(response, DConnectMessage.RESULT_OK);
} else if (error == EventError.INVALID_PARAMETER) {
MessageUtils.setInvalidRequestParameterError(response);
} else if (error == EventError.FAILED) {
MessageUtils.setUnknownError(response, "Failed to delete event.");
} else if (error == EventError.NOT_FOUND) {
MessageUtils.setUnknownError(response, "Not found event.");
} else {
MessageUtils.setUnknownError(response);
}
}
}
/**
* Notify the heart rate event to DeviceConnectManager.
* @param device Identifies the remote device
* @param data Data of heart rate
*/
private void notifyHeartRateDataOld(final HeartRateDevice device, final HeartRateData data) {
HeartRateDeviceService service = (HeartRateDeviceService) getContext();
List<Event> events = EventManager.INSTANCE.getEventList(device.getAddress(),
getProfileName(), null, ATTRIBUTE_HEART_RATE);
for (Event event : events) {
Intent intent = EventManager.createEventMessage(event);
setHeartRate(intent, data.getHeartRate());
service.sendEvent(intent, event.getAccessToken());
}
}
/**
* Notify the heart rate event to DeviceConnectManager.
* @param device Identifies the remote device
* @param data Data of heart rate
*/
private void notifyHeartRateData(final HeartRateDevice device, final HeartRateData data) {
List<Event> events = EventManager.INSTANCE.getEventList(device.getAddress(),
getProfileName(), null, ATTRIBUTE_HEART);
for (Event event : events) {
if (data == null) {
break;
}
Intent intent = EventManager.createEventMessage(event);
setHeart(intent, getHeartRateBundle(device, data));
// The interval's supported is new health profile only.
mDispatcherManager.sendEvent(event, intent);
}
events = EventManager.INSTANCE.getEventList(device.getAddress(),
getProfileName(), null, ATTRIBUTE_ONHEART);
for (Event event : events) {
if (data == null) {
break;
}
Intent intent = EventManager.createEventMessage(event);
setHeart(intent, getHeartRateBundle(device, data));
// The interval's supported is new health profile only.
mDispatcherManager.sendEvent(event, intent);
}
}
/**
* Add Event Dispatcher.
* @param request request parameter
*/
private void addEventDispatcher(final Intent request) {
Event event = EventManager.INSTANCE.getEvent(request);
EventDispatcher dispatcher = EventDispatcherFactory.createEventDispatcher(
(DConnectMessageService) getContext(), request);
mDispatcherManager.addEventDispatcher(event, dispatcher);
}
/**
* Remove Event Dispatcher.
* @param request request parameter
*/
private void removeEventDispatcher(final Intent request) {
Event event = EventManager.INSTANCE.getEvent(request);
mDispatcherManager.removeEventDispatcher(event);
}
/**
* Gets a instance of HeartRateManager.
*
* @return {@link HeartRateManager}, or null on error
*/
private HeartRateManager getManager() {
HeartRateDeviceService service = (HeartRateDeviceService) getContext();
if (service == null) {
return null;
}
return service.getManager();
}
}