/* WearDeviceOrientationProfile.java Copyright (c) 2014 NTT DOCOMO,INC. Released under the MIT license http://opensource.org/licenses/mit-license.php */ package org.deviceconnect.android.deviceplugin.wear.profile; import android.content.Intent; import android.os.Bundle; import com.google.android.gms.wearable.MessageApi.SendMessageResult; import org.deviceconnect.android.deviceplugin.wear.WearDeviceService; import org.deviceconnect.android.deviceplugin.wear.WearManager; import org.deviceconnect.android.deviceplugin.wear.WearManager.OnMessageEventListener; import org.deviceconnect.android.deviceplugin.wear.WearManager.OnMessageResultListener; 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.ArrayList; import java.util.Collections; import java.util.List; /** * DeviceOrientation Profile. * * @author NTT DOCOMO, INC. */ public class WearDeviceOrientationProfile extends DeviceOrientationProfile { /** * 通知先のリスナーを保持するリスト. */ private final List<OnMessageEventListener> mListeners = Collections.synchronizedList(new ArrayList<OnMessageEventListener>()); /** * Android Wearからのイベントを受け取るリスナー. */ private OnMessageEventListener mListener = new OnMessageEventListener() { @Override public void onEvent(final String nodeId, final String message) { synchronized (mListeners) { for (OnMessageEventListener l : mListeners) { l.onEvent(WearUtils.createServiceId(nodeId), message); } } } }; /** * コンストラクタ. * @param mgr Android Wear管理クラス */ public WearDeviceOrientationProfile(final WearManager mgr) { mgr.addMessageEventListener(WearConst.WEAR_TO_DEVICE_DEIVCEORIENTATION_DATA, mListener); mListeners.add(new OnMessageEventListener() { @Override public void onEvent(final String nodeId, final String message) { sendMessageToEvent(nodeId, message); } }); addApi(mGetOnDeviceOrientation); addApi(mPutOnDeviceOrientation); addApi(mDeleteOnDeviceOrientation); } private final DConnectApi mGetOnDeviceOrientation = new GetApi() { @Override public String getAttribute() { return ATTRIBUTE_ON_DEVICE_ORIENTATION; } @Override public boolean onRequest(final Intent request, final Intent response) { final WearDeviceService service = (WearDeviceService) getContext(); String nodeId = WearUtils.getNodeId(getServiceID(request)); final OnMessageEventListener l = new OnMessageEventListener() { @Override public void onEvent(final String nodeId, final String message) { Bundle orientation = createOrientation(message); setResult(response, DConnectMessage.RESULT_OK); setOrientation(response, orientation); service.sendResponse(response); removeListener(this); if (isEmptyEvent(nodeId)) { stopSensor(nodeId); } } }; addListener(l); getManager().sendMessageToWear(nodeId, WearConst.DEVICE_TO_WEAR_DEIVCEORIENTATION_REGISTER, "", new OnMessageResultListener() { @Override public void onResult(final SendMessageResult result) { if (!result.getStatus().isSuccess()) { removeListener(l); MessageUtils.setIllegalDeviceStateError(response); service.sendResponse(response); } } @Override public void onError() { removeListener(l); MessageUtils.setIllegalDeviceStateError(response); service.sendResponse(response); } }); return false; } }; private final DConnectApi mPutOnDeviceOrientation = new PutApi() { @Override public String getAttribute() { return ATTRIBUTE_ON_DEVICE_ORIENTATION; } @Override public boolean onRequest(final Intent request, final Intent response) { String nodeId = WearUtils.getNodeId(getServiceID(request)); getManager().sendMessageToWear(nodeId, WearConst.DEVICE_TO_WEAR_DEIVCEORIENTATION_REGISTER, "", new OnMessageResultListener() { @Override public void onResult(final SendMessageResult result) { if (result.getStatus().isSuccess()) { EventError error = EventManager.INSTANCE.addEvent(request); if (error == EventError.NONE) { setResult(response, DConnectMessage.RESULT_OK); } else { setResult(response, DConnectMessage.RESULT_ERROR); } } else { MessageUtils.setIllegalDeviceStateError(response); } sendResponse(response); } @Override public void onError() { MessageUtils.setIllegalDeviceStateError(response); sendResponse(response); } }); return false; } }; private final DConnectApi mDeleteOnDeviceOrientation = new DeleteApi() { @Override public String getAttribute() { return ATTRIBUTE_ON_DEVICE_ORIENTATION; } @Override public boolean onRequest(final Intent request, final Intent response) { String nodeId = WearUtils.getNodeId(getServiceID(request)); stopSensor(nodeId); // Event release. EventError error = EventManager.INSTANCE.removeEvent(request); if (error == EventError.NONE) { setResult(response, DConnectMessage.RESULT_OK); } else { setResult(response, DConnectMessage.RESULT_ERROR); } return true; } }; /** * イベントの配送先の空状態を取得する. * @param nodeId wearのID * @return 空の場合はtrue、それ以外はfalse */ private boolean isEmptyEvent(final String nodeId) { List<Event> events = EventManager.INSTANCE.getEventList( nodeId, PROFILE_NAME, null, ATTRIBUTE_ON_DEVICE_ORIENTATION); return events == null || events.size() == 0; } /** * 指定されたWearのセンサーを停止する. * @param nodeId wearのID */ private void stopSensor(final String nodeId) { getManager().sendMessageToWear(nodeId, WearConst.DEVICE_TO_WEAR_DEIVCEORIENTATION_UNREGISTER, "", new OnMessageResultListener() { @Override public void onResult(final SendMessageResult result) { } @Override public void onError() { } }); } /** * リスナーを追加する. * @param l 追加するリスナー */ private void addListener(final OnMessageEventListener l) { if (!mListeners.contains(l)) { mListeners.add(l); } } /** * リスナーを削除する. * @param l 削除するリスナー */ private void removeListener(final OnMessageEventListener l) { mListeners.remove(l); } /** * Send a message to the registration event. * * @param nodeId node id * @param data Received Strings. */ private void sendMessageToEvent(final String nodeId, final String data) { Bundle orientation = createOrientation(data); List<Event> events = EventManager.INSTANCE.getEventList( nodeId, PROFILE_NAME, null, ATTRIBUTE_ON_DEVICE_ORIENTATION); synchronized (events) { for (Event event : events) { Intent intent = EventManager.createEventMessage(event); intent.putExtra(DeviceOrientationProfile.PARAM_ORIENTATION, orientation); ((WearDeviceService) getContext()).sendEvent(intent, event.getAccessToken()); } } } /** * 受信したデータからOrientationのデータを作成する. * @param data 受信したデータ * @return Orientationのデータ */ private Bundle createOrientation(final String data) { String[] mDataArray = data.split(",", 0); Bundle orientation = new Bundle(); Bundle a1 = new Bundle(); a1.putDouble(DeviceOrientationProfile.PARAM_X, 0.0); a1.putDouble(DeviceOrientationProfile.PARAM_Y, 0.0); a1.putDouble(DeviceOrientationProfile.PARAM_Z, 0.0); Bundle a2 = new Bundle(); a2.putDouble(DeviceOrientationProfile.PARAM_X, Double.parseDouble(mDataArray[0])); a2.putDouble(DeviceOrientationProfile.PARAM_Y, Double.parseDouble(mDataArray[1])); a2.putDouble(DeviceOrientationProfile.PARAM_Z, Double.parseDouble(mDataArray[2])); // Conversion the unit of angular speed from rad/s to degree/s. double alpha = Math.toDegrees(Double.parseDouble(mDataArray[3])); double beta = Math.toDegrees(Double.parseDouble(mDataArray[4])); double gamma = Math.toDegrees(Double.parseDouble(mDataArray[5])); Bundle r = new Bundle(); r.putDouble(DeviceOrientationProfile.PARAM_ALPHA, alpha); r.putDouble(DeviceOrientationProfile.PARAM_BETA, beta); r.putDouble(DeviceOrientationProfile.PARAM_GAMMA, gamma); orientation.putBundle(DeviceOrientationProfile.PARAM_ACCELERATION, a1); orientation.putBundle(DeviceOrientationProfile.PARAM_ACCELERATION_INCLUDING_GRAVITY, a2); orientation.putBundle(DeviceOrientationProfile.PARAM_ROTATION_RATE, r); orientation.putLong(DeviceOrientationProfile.PARAM_INTERVAL, 0); setInterval(orientation, Integer.parseInt(mDataArray[6])); return orientation; } /** * Android Wear管理クラスを取得する. * @return WearManager管理クラス */ private WearManager getManager() { return ((WearDeviceService) getContext()).getManager(); } }