/* PebbleDeviceOrientationProfile.java Copyright (c) 2014 NTT DOCOMO,INC. Released under the MIT license http://opensource.org/licenses/mit-license.php */ package org.deviceconnect.android.deviceplugin.pebble.profile; import android.content.Intent; import android.os.Bundle; import com.getpebble.android.kit.util.PebbleDictionary; import org.deviceconnect.android.deviceplugin.pebble.PebbleDeviceService; import org.deviceconnect.android.deviceplugin.pebble.util.PebbleManager; import org.deviceconnect.android.deviceplugin.pebble.util.PebbleManager.OnReceivedEventListener; import org.deviceconnect.android.deviceplugin.pebble.util.PebbleManager.OnSendCommandListener; import org.deviceconnect.android.event.Event; import org.deviceconnect.android.event.EventError; import org.deviceconnect.android.event.EventManager; import org.deviceconnect.android.message.MessageUtils; import org.deviceconnect.android.profile.DeviceOrientationProfile; 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; /** * Pebble用 Device Orientationプロファイル. * @author NTT DOCOMO, INC. */ public class PebbleDeviceOrientationProfile extends DeviceOrientationProfile { /** milli G を m/s^2 の値にする係数. */ private static final double G_TO_MS2_COEFFICIENT = 9.81 / 1000.0; /** Orientationデータをキャッシュする変数. */ private Bundle mCacheOrientation; private final DConnectApi mGetOnDeviceOrientationApi = new GetApi() { @Override public String getAttribute() { return ATTRIBUTE_ON_DEVICE_ORIENTATION; } @Override public boolean onRequest(final Intent request, final Intent response) { if (isStartSensor()) { if (mCacheOrientation != null) { setResult(response, DConnectMessage.RESULT_OK); setOrientation(response, mCacheOrientation); } else { MessageUtils.setIllegalDeviceStateError(response, "Device is not ready."); } return true; } else { startSensorOnce(response); return false; } } }; private final DConnectApi mPutOnDeviceOrientationApi = new PutApi() { @Override public String getAttribute() { return ATTRIBUTE_ON_DEVICE_ORIENTATION; } @Override public boolean onRequest(final Intent request, final Intent response) { startSensor(new OnSendCommandListener() { @Override public void onReceivedData(final PebbleDictionary dic) { if (dic == null) { MessageUtils.setUnknownError(response); } else { // イベントリスナーを登録 EventError error = EventManager.INSTANCE.addEvent(request); if (error == EventError.NONE) { setResult(response, DConnectMessage.RESULT_OK); } else if (error == EventError.INVALID_PARAMETER) { MessageUtils.setInvalidRequestParameterError(response); } else { MessageUtils.setUnknownError(response); } } sendResponse(response); } }); // レスポンスを非同期で返却するので、falseを返す return false; } }; private final DConnectApi mDeleteOnDeviceOrientationApiApi = new DeleteApi() { @Override public String getAttribute() { return ATTRIBUTE_ON_DEVICE_ORIENTATION; } @Override public boolean onRequest(final Intent request, final Intent response) { stopSensor(); // イベントリスナーを解除 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 { MessageUtils.setUnknownError(response); } return true; } }; /** * コンストラクタ. * @param service Pebble デバイスサービス */ public PebbleDeviceOrientationProfile(final PebbleDeviceService service) { service.getPebbleManager().addEventListener(PebbleManager.PROFILE_DEVICE_ORIENTATION , new OnReceivedEventListener() { @Override public void onReceivedEvent(final PebbleDictionary dic) { // Pebbleから加速度が送られてきたら、登録されたイベントに対して通知を送る Bundle orientation = createOrientation(dic); mCacheOrientation = orientation; // 登録されたイベントリスナー一覧を取得 List<Event> evts = EventManager.INSTANCE.getEventList(service.getServiceId(), PROFILE_NAME, null, ATTRIBUTE_ON_DEVICE_ORIENTATION); if (evts != null && evts.size() > 0) { synchronized (evts) { for (Event evt : evts) { // 各イベントリスナーに通知 Intent intent = EventManager.createEventMessage(evt); setOrientation(intent, orientation); sendEvent(intent, evt.getAccessToken()); } } } } }); addApi(mGetOnDeviceOrientationApi); addApi(mPutOnDeviceOrientationApi); addApi(mDeleteOnDeviceOrientationApiApi); } /** * Pebbleから送られてきたデータからOrientationデータを作成する. * @param dic 受信したデータ * @return Orientationデータ */ private Bundle createOrientation(final PebbleDictionary dic) { Long x = dic.getInteger(PebbleManager.KEY_PARAM_DEVICE_ORIENTATION_X); Long y = dic.getInteger(PebbleManager.KEY_PARAM_DEVICE_ORIENTATION_Y); Long z = dic.getInteger(PebbleManager.KEY_PARAM_DEVICE_ORIENTATION_Z); Long interval = dic.getInteger(PebbleManager.KEY_PARAM_DEVICE_ORIENTATION_INTERVAL); // Pebbleからの加速度をdConnectの単位に正規化してdConnect用のデータを作成 Bundle orientation = new Bundle(); Bundle accelerationIncludingGravity = new Bundle(); setX(accelerationIncludingGravity, x.intValue() * G_TO_MS2_COEFFICIENT); setY(accelerationIncludingGravity, y.intValue() * G_TO_MS2_COEFFICIENT); setZ(accelerationIncludingGravity, z.intValue() * G_TO_MS2_COEFFICIENT); setAccelerationIncludingGravity(orientation, accelerationIncludingGravity); setInterval(orientation, interval.longValue()); return orientation; } /** * センサーが開始されているかチェックする. * @return 開始されている場合はtrue、それ以外はfalse */ private boolean isStartSensor() { PebbleDeviceService service = (PebbleDeviceService) getContext(); List<Event> evts = EventManager.INSTANCE.getEventList(service.getServiceId(), PROFILE_NAME, null, ATTRIBUTE_ON_DEVICE_ORIENTATION); return evts != null && evts.size() > 0; } /** * 1回だけセンサーを起動します. * @param response レスポンス */ private void startSensorOnce(final Intent response) { final PebbleDeviceService service = (PebbleDeviceService) getContext(); final PebbleManager mgr = service.getPebbleManager(); final OnReceivedEventListener l = new OnReceivedEventListener() { @Override public void onReceivedEvent(final PebbleDictionary dic) { Bundle orientation = createOrientation(dic); setResult(response, DConnectMessage.RESULT_OK); setOrientation(response, orientation); service.sendResponse(response); mgr.removeEventListener(PebbleManager.PROFILE_DEVICE_ORIENTATION, this); if (!isStartSensor()) { stopSensor(); } } }; mgr.addEventListener(PebbleManager.PROFILE_DEVICE_ORIENTATION, l); startSensor(new OnSendCommandListener() { @Override public void onReceivedData(final PebbleDictionary dic) { if (dic == null) { MessageUtils.setUnknownError(response); service.sendResponse(response); mgr.removeEventListener(PebbleManager.PROFILE_DEVICE_ORIENTATION, l); stopSensor(); } } }); } /** * センサーを開始する. * @param listener 開始結果を通知するリスナー */ private void startSensor(final OnSendCommandListener listener) { PebbleManager mgr = ((PebbleDeviceService) getContext()).getPebbleManager(); // Pebbleで加速度センサーの登録依頼を送る PebbleDictionary dic = new PebbleDictionary(); dic.addInt8(PebbleManager.KEY_PROFILE, (byte) PebbleManager.PROFILE_DEVICE_ORIENTATION); dic.addInt8(PebbleManager.KEY_ATTRIBUTE , (byte) PebbleManager.DEVICE_ORIENTATION_ATTRIBUTE_ON_DEVICE_ORIENTATION); dic.addInt8(PebbleManager.KEY_ACTION, (byte) PebbleManager.ACTION_PUT); mgr.sendCommandToPebble(dic, listener); } /** * センサーを停止する. */ private void stopSensor() { PebbleManager mgr = ((PebbleDeviceService) getContext()).getPebbleManager(); // Pebbleに加速度センサーの解除依頼を送る PebbleDictionary dic = new PebbleDictionary(); dic.addInt8(PebbleManager.KEY_PROFILE, (byte) PebbleManager.PROFILE_DEVICE_ORIENTATION); dic.addInt8(PebbleManager.KEY_ATTRIBUTE , (byte) PebbleManager.DEVICE_ORIENTATION_ATTRIBUTE_ON_DEVICE_ORIENTATION); dic.addInt8(PebbleManager.KEY_ACTION, (byte) PebbleManager.ACTION_DELETE); mgr.sendCommandToPebble(dic, new OnSendCommandListener() { @Override public void onReceivedData(final PebbleDictionary dic) { // No operation. } }); } }