/* LinkingNotifySensor.java Copyright (c) 2016 NTT DOCOMO,INC. Released under the MIT license http://opensource.org/licenses/mit-license.php */ package org.deviceconnect.android.deviceplugin.linking.linking; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.util.Log; import com.nttdocomo.android.sdaiflib.ControlSensorData; import org.deviceconnect.android.deviceplugin.linking.BuildConfig; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; class LinkingNotifySensor { private static final String TAG = "LinkingPlugIn"; private final Map<LinkingDevice, List<LinkingDeviceManager.OnSensorListener>> mSensorMap = new HashMap<>(); private final Map<LinkingDevice, List<LinkingDeviceManager.OnBatteryListener>> mBatteryMap = new HashMap<>(); private final Map<LinkingDevice, List<LinkingDeviceManager.OnHumidityListener>> mHumidityMap = new HashMap<>(); private final Map<LinkingDevice, List<LinkingDeviceManager.OnTemperatureListener>> mTemperatureMap = new HashMap<>(); private NotifySensorData mNotifySensor; private LinkingDeviceManager mLinkingDeviceManager; private Context mContext; private final Map<String, Integer> mCountOfSensor = new HashMap<>(); public LinkingNotifySensor(final Context context, final LinkingDeviceManager manager) { mContext = context; mLinkingDeviceManager = manager; startNotifySensor(); } public synchronized void release() { mSensorMap.clear(); mBatteryMap.clear(); mHumidityMap.clear(); mTemperatureMap.clear(); mCountOfSensor.clear(); if (mNotifySensor != null) { if (BuildConfig.DEBUG) { Log.d(TAG, "Stop a sensor event."); } mNotifySensor.release(); mNotifySensor = null; } } public synchronized void enableListenOrientation(final LinkingDevice device, final LinkingDeviceManager.OnSensorListener listener) { if (!device.isSupportSensor()) { return; } List<LinkingDeviceManager.OnSensorListener> listeners = mSensorMap.get(device); if (listeners == null) { listeners = new CopyOnWriteArrayList<>(); mSensorMap.put(device, listeners); } else if (listeners.contains(listener)) { return; } listeners.add(listener); if (listeners.size() > 1) { if (BuildConfig.DEBUG) { Log.i(TAG, device.getDisplayName() + ": orientation is already running."); } return; } if (BuildConfig.DEBUG) { Log.i(TAG, "LinkingNotifySensor:startOrientation: " + device.getDisplayName()); } startSensor(device.getBdAddress(), getSupportSensorType(device), 200); } public synchronized void disableListenOrientation(final LinkingDevice device, final LinkingDeviceManager.OnSensorListener listener) { if (BuildConfig.DEBUG) { Log.i(TAG, "LinkingNotifySensor:disableListenOrientation: " + device.getDisplayName()); } List<LinkingDeviceManager.OnSensorListener> listeners = mSensorMap.get(device); if (listeners != null) { if (listener == null) { mSensorMap.remove(device); } else { listeners.remove(listener); if (listeners.isEmpty()) { mSensorMap.remove(device); } } } stopSensors(device); } public synchronized void enableListenBattery(final LinkingDevice device, final LinkingDeviceManager.OnBatteryListener listener) { if (!device.isSupportBattery()) { return; } List<LinkingDeviceManager.OnBatteryListener> listeners = mBatteryMap.get(device); if (listeners == null) { listeners = new CopyOnWriteArrayList<>(); mBatteryMap.put(device, listeners); } else if (listeners.contains(listener)) { return; } listeners.add(listener); if (listeners.size() > 1) { if (BuildConfig.DEBUG) { Log.i(TAG, device.getDisplayName() + ": battery is already running."); } return; } int[] type = { LinkingSensorData.SensorType.BATTERY.getValue() }; startSensor(device.getBdAddress(), type, 1000); } public synchronized void disableListenBattery(final LinkingDevice device, final LinkingDeviceManager.OnBatteryListener listener) { if (BuildConfig.DEBUG) { Log.i(TAG, "LinkingNotifySensor#disableListenBattery: " + device.getDisplayName()); } List<LinkingDeviceManager.OnBatteryListener> listeners = mBatteryMap.get(device); if (listeners != null) { if (listener == null) { mBatteryMap.remove(device); } else { listeners.remove(listener); if (listeners.isEmpty()) { mBatteryMap.remove(device); } } } stopSensors(device); } public synchronized void enableListenHumidity(final LinkingDevice device, final LinkingDeviceManager.OnHumidityListener listener) { if (!device.isSupportHumidity()) { return; } List<LinkingDeviceManager.OnHumidityListener> listeners = mHumidityMap.get(device); if (listeners == null) { listeners = new CopyOnWriteArrayList<>(); mHumidityMap.put(device, listeners); } else if (listeners.contains(listener)) { return; } listeners.add(listener); if (listeners.size() > 1) { if (BuildConfig.DEBUG) { Log.i(TAG, device.getDisplayName() + ": humidity is already running."); } return; } int[] type = { LinkingSensorData.SensorType.HUMIDITY.getValue() }; startSensor(device.getBdAddress(), type, 1000); } public synchronized void disableListenHumidity(final LinkingDevice device, final LinkingDeviceManager.OnHumidityListener listener) { if (BuildConfig.DEBUG) { Log.i(TAG, "LinkingNotifySensor#disableListenHumidity: " + device.getDisplayName()); } List<LinkingDeviceManager.OnHumidityListener> listeners = mHumidityMap.get(device); if (listeners != null) { if (listener == null) { mHumidityMap.remove(device); } else { listeners.remove(listener); if (listeners.isEmpty()) { mHumidityMap.remove(device); } } } stopSensors(device); } public synchronized void enableListenTemperature(final LinkingDevice device, final LinkingDeviceManager.OnTemperatureListener listener) { if (!device.isSupportTemperature()) { return; } List<LinkingDeviceManager.OnTemperatureListener> listeners = mTemperatureMap.get(device); if (listeners == null) { listeners = new CopyOnWriteArrayList<>(); mTemperatureMap.put(device, listeners); } else if (listeners.contains(listener)) { return; } listeners.add(listener); if (listeners.size() > 1) { if (BuildConfig.DEBUG) { Log.i(TAG, device.getDisplayName() + ": temperature is already running."); } return; } int[] type = { LinkingSensorData.SensorType.TEMPERATURE.getValue() }; startSensor(device.getBdAddress(), type, 1000); } public synchronized void disableListenTemperature(final LinkingDevice device, final LinkingDeviceManager.OnTemperatureListener listener) { if (BuildConfig.DEBUG) { Log.i(TAG, "LinkingNotifySensor#disableListenTemperature: " + device.getDisplayName()); } List<LinkingDeviceManager.OnTemperatureListener> listeners = mTemperatureMap.get(device); if (listeners != null) { if (listener == null) { mTemperatureMap.remove(device); } else { listeners.remove(listener); if (listeners.isEmpty()) { mTemperatureMap.remove(device); } } } stopSensors(device); } private boolean containsOrientation(final LinkingDevice device) { return mSensorMap.keySet().contains(device); } private boolean containsBattery(final LinkingDevice device) { return mBatteryMap.keySet().contains(device); } private synchronized boolean containsHumidity(final LinkingDevice device) { return mHumidityMap.keySet().contains(device); } private synchronized boolean containsTemperature(final LinkingDevice device) { return mTemperatureMap.keySet().contains(device); } private synchronized LinkingDevice findDeviceFromSensor(final String address) { for (LinkingDevice device : mSensorMap.keySet()) { if (device.getBdAddress().equals(address)) { return device; } } return null; } private synchronized LinkingDevice findDeviceFromBattery(final String address) { for (LinkingDevice device : mBatteryMap.keySet()) { if (device.getBdAddress().equals(address)) { return device; } } return null; } private synchronized LinkingDevice findDeviceFromHumidity(final String address) { for (LinkingDevice device : mHumidityMap.keySet()) { if (device.getBdAddress().equals(address)) { return device; } } return null; } private synchronized LinkingDevice findDeviceFromTemperature(final String address) { for (LinkingDevice device : mTemperatureMap.keySet()) { if (device.getBdAddress().equals(address)) { return device; } } return null; } private void startSensor(final String address, final int[] types, final int interval) { if (BuildConfig.DEBUG) { Log.i(TAG, "LinkingNotifySensor#startSensor: " + address); } Intent intent = new Intent(mContext.getPackageName() + ".sda.action.START_SENSOR"); intent.setComponent(new ComponentName(LinkingUtil.PACKAGE_NAME, LinkingUtil.RECEIVER_NAME)); intent.putExtra(mContext.getPackageName() + ".sda.extra.BD_ADDRESS", address); intent.putExtra(mContext.getPackageName() + ".sda.extra.SENSOR_INTERVAL", interval); intent.putExtra(mContext.getPackageName() + ".sda.extra.SENSOR_DURATION", -1); intent.putExtra(mContext.getPackageName() + ".sda.extra.X_THRESHOLD", 0.0F); intent.putExtra(mContext.getPackageName() + ".sda.extra.Y_THRESHOLD", 0.0F); intent.putExtra(mContext.getPackageName() + ".sda.extra.Z_THRESHOLD", 0.0F); for (int i = 0; i < types.length; i++) { start(intent, types[i]); } countUpSensor(address, types.length); } private void stopSensors(final LinkingDevice device) { if (containsBattery(device) || containsHumidity(device) || containsOrientation(device) || containsTemperature(device)) { return; } int count = countDownSensor(device.getBdAddress()); for (int i = 0; i < count; i++) { stopSensors(device.getBdAddress()); } } private void stopSensors(final String address) { if (BuildConfig.DEBUG) { Log.i(TAG, "LinkingNotifySensor#stopSensors: " + address); } Intent intent = new Intent(mContext.getPackageName() + ".sda.action.STOP_SENSOR"); intent.setComponent(new ComponentName(LinkingUtil.PACKAGE_NAME, LinkingUtil.RECEIVER_NAME)); intent.putExtra(mContext.getPackageName() + ".sda.extra.BD_ADDRESS", address); try { mLinkingDeviceManager.getContext().sendBroadcast(intent); } catch (ActivityNotFoundException e) { if (BuildConfig.DEBUG) { e.printStackTrace(); } } } private void countUpSensor(final String address, final int length) { Integer count = mCountOfSensor.get(address); if (count == null) { count = 0; } mCountOfSensor.put(address, count + length); } private int countDownSensor(final String address) { Integer count = mCountOfSensor.remove(address); if (count == null) { count = 1; } return count; } private int[] getSupportSensorType(final LinkingDevice device) { List<Integer> type = new ArrayList<>(); if (device.isSupportGyro()) { type.add(LinkingSensorData.SensorType.GYRO.getValue()); } if (device.isSupportAcceleration()) { type.add(LinkingSensorData.SensorType.ACCELERATION.getValue()); } if (device.isSupportCompass()) { type.add(LinkingSensorData.SensorType.COMPASS.getValue()); } int[] types = new int[type.size()]; for (int i = 0; i < type.size(); i++) { types[i] = type.get(i); } return types; } private void startNotifySensor() { if (mNotifySensor != null) { if (BuildConfig.DEBUG) { Log.w(TAG, "mNotifySensor is already running."); } return; } mNotifySensor = new NotifySensorData(mContext, new ControlSensorData.SensorRequestInterface() { @Override public void onStartSensorResult(final String bd, final int type, int resultCode) { if (BuildConfig.DEBUG) { LinkingUtil.Result result = LinkingUtil.Result.valueOf(resultCode); Log.e(TAG, "onStartSensorResult: " + bd + " " + type + " " + result); } } }, new ControlSensorData.SensorDataInterface() { private final LinkingSensorData mSensorData = new LinkingSensorData(); @Override public synchronized void onSensorData(final String bd, final int type, final float x, final float y, final float z, final byte[] originalData, final long time) { mSensorData.setBdAddress(bd); mSensorData.setX(x); mSensorData.setY(y); mSensorData.setZ(z); mSensorData.setOriginalData(originalData); mSensorData.setType(LinkingSensorData.SensorType.valueOf(type)); mSensorData.setTime(time); if (BuildConfig.DEBUG) { Log.i(TAG, "onSensorData: " + mSensorData); } switch (mSensorData.getType()) { case GYRO: case ACCELERATION: case COMPASS: onOrientationSensor(bd); break; case BATTERY: onBatterySensor(bd); break; case TEMPERATURE: onTemperature(bd); break; case HUMIDITY: onHumidity(bd); break; default: if (BuildConfig.DEBUG) { Log.e(TAG, "Not support sensor type=" + mSensorData.getType()); } break; } } @Override public void onStopSensor(final String bd, final int type, final int reason) { if (BuildConfig.DEBUG) { Log.i(TAG, "onStopSensor: type:[" + type + "] reason:[" + reason + "] bd: " + bd); } } private void onBatterySensor(final String bd) { LinkingDevice device = findDeviceFromBattery(bd); if (device == null) { if (BuildConfig.DEBUG) { Log.w(TAG, "Not Found the device that address is " + bd); } } else { int value = LinkingUtil.byteToShort(mSensorData.getOriginalData()); boolean lowBatteryFlag = (value & (1 << 11)) != 0; float batteryLevel = (value & 0x07ff) / 10.0f; notifyOnBattery(device, lowBatteryFlag, batteryLevel); } } private void onTemperature(final String bd) { LinkingDevice device = findDeviceFromTemperature(bd); if (device == null) { if (BuildConfig.DEBUG) { Log.w(TAG, "Not Found the device that address is " + bd); } } else { int value = LinkingUtil.byteToShort(mSensorData.getOriginalData()); float temperature = LinkingUtil.intToFloatIEEE754(value, 7, 4, true); notifyOnTemperature(device, temperature); } } private void onHumidity(final String bd) { LinkingDevice device = findDeviceFromHumidity(bd); if (device == null) { if (BuildConfig.DEBUG) { Log.w(TAG, "Not Found the device that address is " + bd); } } else { int value = LinkingUtil.byteToShort(mSensorData.getOriginalData()); float humidity = LinkingUtil.intToFloatIEEE754(value, 8, 4, false); notifyOnHumidity(device, humidity); } } private void onOrientationSensor(final String bd) { LinkingDevice device = findDeviceFromSensor(bd); if (device == null) { if (BuildConfig.DEBUG) { Log.w(TAG, "Not Found the device that address is " + bd); } } else { notifyOnChangeSensor(device, mSensorData); } } }); } private synchronized void notifyOnChangeSensor(final LinkingDevice device, final LinkingSensorData data) { for (LinkingDeviceManager.OnSensorListener listener : mSensorMap.get(device)) { listener.onChangeSensor(device, data); } } private synchronized void notifyOnBattery(final LinkingDevice device, final boolean lowBatteryFlag, final float batteryLevel) { for (LinkingDeviceManager.OnBatteryListener listener : mBatteryMap.get(device)) { listener.onBattery(device, lowBatteryFlag, batteryLevel); } } private synchronized void notifyOnHumidity(final LinkingDevice device, final float humidity) { for (LinkingDeviceManager.OnHumidityListener listener : mHumidityMap.get(device)) { listener.onHumidity(device, humidity); } } private synchronized void notifyOnTemperature(final LinkingDevice device, final float temperature) { for (LinkingDeviceManager.OnTemperatureListener listener : mTemperatureMap.get(device)) { listener.onTemperature(device, temperature); } } private void start(Intent request, int type) { Intent intent = new Intent(mContext.getPackageName() + ".sda.action.START_SENSOR"); intent.setComponent(new ComponentName(LinkingUtil.PACKAGE_NAME, LinkingUtil.RECEIVER_NAME)); intent.putExtras(request.getExtras()); intent.putExtra(mContext.getPackageName() + ".sda.extra.SENSOR_TYPE", type); mContext.sendBroadcast(intent); } }