PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/de/androvdr/devices/Devices.java

https://code.google.com/p/androvdr/
Java | 766 lines | 662 code | 80 blank | 24 comment | 137 complexity | b4fabd16ee18ad1c4d2afb71f52c8d0d MD5 | raw file
  1. /*
  2. * Copyright (c) 2010-2011 by androvdr <androvdr@googlemail.com>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program; if not, write to the Free Software
  15. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. *
  17. * For more information on the GPL, please go to:
  18. * http://www.gnu.org/copyleft/gpl.html
  19. */
  20. package de.androvdr.devices;
  21. import java.io.BufferedReader;
  22. import java.io.File;
  23. import java.io.FilenameFilter;
  24. import java.io.InputStream;
  25. import java.io.InputStreamReader;
  26. import java.text.SimpleDateFormat;
  27. import java.util.ArrayList;
  28. import java.util.Date;
  29. import java.util.Enumeration;
  30. import java.util.Hashtable;
  31. import java.util.LinkedList;
  32. import java.util.List;
  33. import java.util.Timer;
  34. import java.util.TimerTask;
  35. import java.util.jar.JarFile;
  36. import java.util.zip.ZipEntry;
  37. import org.slf4j.Logger;
  38. import org.slf4j.LoggerFactory;
  39. import android.app.Activity;
  40. import android.content.ContentValues;
  41. import android.content.SharedPreferences;
  42. import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
  43. import android.database.Cursor;
  44. import android.database.sqlite.SQLiteDatabase;
  45. import android.os.Bundle;
  46. import android.os.Environment;
  47. import android.os.Handler;
  48. import android.os.Looper;
  49. import android.os.Message;
  50. import android.preference.PreferenceManager;
  51. import dalvik.system.DexClassLoader;
  52. import de.androvdr.AndroApplication;
  53. import de.androvdr.DBHelper;
  54. import de.androvdr.DevicesTable;
  55. import de.androvdr.Preferences;
  56. import de.androvdr.Recordings;
  57. public class Devices implements OnSharedPreferenceChangeListener, OnChannelChangedListener {
  58. private static transient Logger logger = LoggerFactory.getLogger(Devices.class);
  59. private static Devices sInstance;
  60. public static final String VDR_CLASSNAME = "VDR";
  61. public static final CharSequence[] volumePrefNames = new CharSequence[] { "volumeDevice", "volumeUp", "volumeDown" };
  62. private ActivityDevice mActivity;
  63. private SensorJob mChannelSensorJob;
  64. private final DBHelper mDBHelper;
  65. private int mDatabaseIsExternalOpen = 0;
  66. private Hashtable<String, IActuator> mDevices = new Hashtable<String, IActuator>();
  67. private Hashtable<String, Macro> mMacros = new Hashtable<String, Macro>();
  68. private OnChangeListener mOnDeviceConfigurationChangedListener = null;
  69. private Hashtable<String, Class<?>> mPlugins = new Hashtable<String, Class<?>>();
  70. private Handler mResultHandler = null;
  71. private DeviceSendThread mSendThread = null;
  72. private ArrayList<SensorJob> mSensorJobs = new ArrayList<SensorJob>();
  73. private Hashtable<String, ISensor> mSensors = new Hashtable<String, ISensor>();
  74. private Timer mSensorUpdateTimer;
  75. private SensorReceiveThread mReceiveThread = null;
  76. private String mVolumeDownCommand = "";
  77. private String mVolumeUpCommand = "";
  78. public static final String MSG_RESULT = "result";
  79. public static String macroConfig = Preferences.getMacroFileName();
  80. public static String pluginDir = Preferences.getPluginDirName();
  81. private Devices() {
  82. mReceiveThread = new SensorReceiveThread();
  83. mReceiveThread.start();
  84. mSendThread = new DeviceSendThread();
  85. mSendThread.start();
  86. mDBHelper = new DBHelper(AndroApplication.getAppContext());
  87. init();
  88. SharedPreferences sp = PreferenceManager
  89. .getDefaultSharedPreferences(AndroApplication.getAppContext());
  90. initVolumeCommands(sp);
  91. }
  92. public void addDevice(Cursor cursor) {
  93. if (cursor.getString(1).equals(VDR_CLASSNAME)) {
  94. VdrDevice vdr = new VdrDevice();
  95. vdr.setId(cursor.getLong(0));
  96. vdr.setName(cursor.getString(2));
  97. vdr.setIP(cursor.getString(3));
  98. vdr.setPort(cursor.getInt(4));
  99. vdr.macaddress = cursor.getString(7);
  100. vdr.remote_host = cursor.getString(8);
  101. vdr.remote_user = cursor.getString(9);
  102. vdr.remote_port = cursor.getInt(10);
  103. vdr.remote_local_port = cursor.getInt(11);
  104. vdr.remote_timeout = cursor.getInt(12);
  105. vdr.channellist = cursor.getString(13);
  106. vdr.epgmax = cursor.getInt(14);
  107. vdr.characterset = cursor.getString(15);
  108. vdr.margin_start = cursor.getInt(16);
  109. vdr.margin_stop = cursor.getInt(17);
  110. vdr.vps = cursor.getString(18).equals("true");
  111. vdr.timeout = cursor.getInt(19);
  112. vdr.sshkey = cursor.getString(20);
  113. vdr.streamingport = cursor.getInt(21);
  114. vdr.broadcastaddress = cursor.getString(22);
  115. vdr.extremux = cursor.getString(23).equals("true");
  116. vdr.extremux_param = cursor.getString(24);
  117. vdr.remote_streaming_port = cursor.getInt(25);
  118. vdr.extremux_command = cursor.getString(26);
  119. vdr.vdradmin = cursor.getString(27).equals("true");
  120. vdr.vdradmin_port = cursor.getInt(28);
  121. vdr.remote_vdradmin_port = cursor.getInt(29);
  122. vdr.generalstreaming = cursor.getString(30).equals("true");
  123. vdr.generalstreaming_url = cursor.getString(31);
  124. mDevices.put(vdr.getName(), vdr);
  125. mSensors.put(vdr.getName(), vdr);
  126. } else {
  127. try {
  128. if (mPlugins.containsKey(cursor.getString(1))) {
  129. IDevice c = (IDevice) mPlugins.get(cursor.getString(1)).newInstance();
  130. if (c != null && c instanceof IActuator) {
  131. IActuator actuator = (IActuator) c;
  132. actuator.setId(cursor.getLong(0));
  133. actuator.setName(cursor.getString(2));
  134. actuator.setIP(cursor.getString(3));
  135. actuator.setPort(cursor.getInt(4));
  136. actuator.setUser(cursor.getString(5));
  137. actuator.setPassword(cursor.getString(6));
  138. mDevices.put(actuator.getName(), actuator);
  139. }
  140. if (c != null && c instanceof ISensor) {
  141. ISensor sensor = (ISensor) c;
  142. sensor.setId(cursor.getLong(0));
  143. sensor.setName(cursor.getString(2));
  144. sensor.setIP(cursor.getString(3));
  145. sensor.setPort(cursor.getInt(4));
  146. sensor.setUser(cursor.getString(5));
  147. sensor.setPassword(cursor.getString(6));
  148. mSensors.put(sensor.getName(), sensor);
  149. }
  150. }
  151. } catch (Exception e) {
  152. e.printStackTrace();
  153. }
  154. }
  155. }
  156. public void addOnSensorChangeListener(String command, int interval, OnSensorChangeListener listener) {
  157. SensorJob job = new SensorJob(command, interval, listener);
  158. synchronized (mSensorJobs) {
  159. mSensorJobs.add(job);
  160. }
  161. if (VdrDevice.isChannelSensor(command)) {
  162. mChannelSensorJob = job;
  163. VdrDevice vdr = Preferences.getVdr();
  164. if (vdr != null)
  165. vdr.addChannelChangedListener(this);
  166. }
  167. }
  168. public void clearOnSensorChangeListeners() {
  169. synchronized (mSensorJobs) {
  170. VdrDevice vdr = Preferences.getVdr();
  171. if (vdr != null)
  172. for (SensorJob job : mSensorJobs) {
  173. if (VdrDevice.isChannelSensor(job.command))
  174. vdr.removeChannelChangedListener(this);
  175. }
  176. mSensorJobs.clear();
  177. }
  178. logger.trace("SensorJobs cleared");
  179. }
  180. public void dbClose() {
  181. mDatabaseIsExternalOpen -= 1;
  182. if (mDatabaseIsExternalOpen == 0)
  183. mDBHelper.close();
  184. }
  185. public int dbDelete(long id) {
  186. SQLiteDatabase db = mDBHelper.getWritableDatabase();
  187. int result = db.delete(DevicesTable.TABLE_NAME, "_id = ?", new String[] { Long.toString(id) });
  188. if (mDatabaseIsExternalOpen == 0)
  189. db.close();
  190. Recordings.clearIds(id);
  191. initDevices();
  192. return result;
  193. }
  194. public long dbStore(ContentValues values) {
  195. long result;
  196. SQLiteDatabase db = mDBHelper.getWritableDatabase();
  197. if (values.containsKey(DevicesTable.ID)) {
  198. result = db.update(DevicesTable.TABLE_NAME, values, DevicesTable.ID + "=?",
  199. new String[] { values.getAsString(DevicesTable.ID) });
  200. } else {
  201. result = db.insert(DevicesTable.TABLE_NAME, null, values);
  202. }
  203. if (mDatabaseIsExternalOpen == 0)
  204. db.close();
  205. return result;
  206. }
  207. public long dbUpdate(long id, ContentValues values) {
  208. ContentValues storevalues = new ContentValues(values);
  209. storevalues.put("_id", id);
  210. return dbStore(storevalues);
  211. }
  212. // public static Devices getInstance() {
  213. // return sDevices;
  214. // }
  215. public static Devices getInstance() {
  216. if (sInstance == null) {
  217. sInstance = new Devices();
  218. }
  219. return sInstance;
  220. }
  221. public IActuator get(String name) {
  222. return mDevices.get(name);
  223. }
  224. public Cursor getCursorForAllDevices() {
  225. final SQLiteDatabase db = mDBHelper.getReadableDatabase();
  226. mDatabaseIsExternalOpen += 1;
  227. return db.query(DevicesTable.TABLE_NAME, DevicesTable.ALL_COLUMNS,
  228. null, null, null, null, DevicesTable.NAME);
  229. }
  230. public Cursor getCursorForDevice(long id) {
  231. final SQLiteDatabase db = mDBHelper.getReadableDatabase();
  232. mDatabaseIsExternalOpen += 1;
  233. return db.query(DevicesTable.TABLE_NAME, DevicesTable.ALL_COLUMNS,
  234. "_id = ?", new String[] { Long.toString(id)}, null, null, null);
  235. }
  236. public IActuator getDevice(long id) {
  237. IActuator device = null;
  238. Enumeration<String> e = mDevices.keys();
  239. while (e.hasMoreElements()) {
  240. String key = e.nextElement();
  241. IDevice idev = (IDevice) mDevices.get(key);
  242. if ((idev instanceof IDevice) && (((IDevice) idev).getId() == id)) {
  243. device = (IActuator) idev;
  244. break;
  245. }
  246. }
  247. return device;
  248. }
  249. public ArrayList<IActuator> getDevices() {
  250. ArrayList<IActuator> actuators = new ArrayList<IActuator>();
  251. Enumeration<String> e = mDevices.keys();
  252. while (e.hasMoreElements()) {
  253. String key = e.nextElement();
  254. IActuator ac = mDevices.get(key);
  255. if ((ac instanceof IActuator) && !(ac instanceof VdrDevice)) {
  256. actuators.add(ac);
  257. }
  258. }
  259. return actuators;
  260. }
  261. public String[] getPluginNames() {
  262. List<CharSequence> list = new LinkedList<CharSequence>();
  263. Enumeration<String> e = mPlugins.keys();
  264. while (e.hasMoreElements()) {
  265. String key = e.nextElement();
  266. if (IActuator.class.isAssignableFrom(mPlugins.get(key)))
  267. list.add(key);
  268. }
  269. return list.toArray(new String[list.size()]);
  270. }
  271. public VdrDevice getFirstVdr() {
  272. VdrDevice vdr = null;
  273. Enumeration<String> e = mDevices.keys();
  274. while (e.hasMoreElements()) {
  275. String key = e.nextElement();
  276. IActuator ac = (IActuator) mDevices.get(key);
  277. if (ac instanceof VdrDevice) {
  278. vdr = (VdrDevice) ac;
  279. break;
  280. }
  281. }
  282. return vdr;
  283. }
  284. public VdrDevice getVdr(long id) {
  285. VdrDevice vdr = null;
  286. Enumeration<String> e = mDevices.keys();
  287. while (e.hasMoreElements()) {
  288. String key = e.nextElement();
  289. IActuator ac = (IActuator) mDevices.get(key);
  290. if ((ac instanceof VdrDevice) && (((VdrDevice) ac).getId() == id)) {
  291. vdr = (VdrDevice) ac;
  292. break;
  293. }
  294. }
  295. return vdr;
  296. }
  297. public ArrayList<VdrDevice> getVdrs() {
  298. ArrayList<VdrDevice> list = new ArrayList<VdrDevice>();
  299. Enumeration<String> e = mDevices.keys();
  300. while (e.hasMoreElements()) {
  301. String key = e.nextElement();
  302. IActuator ac = (IActuator) mDevices.get(key);
  303. if (ac instanceof VdrDevice) {
  304. list.add((VdrDevice) ac);
  305. }
  306. }
  307. return list;
  308. }
  309. public CharSequence[] getVdrNames() {
  310. List<CharSequence> list = new LinkedList<CharSequence>();
  311. Enumeration<String> e = mDevices.keys();
  312. while (e.hasMoreElements()) {
  313. String key = e.nextElement();
  314. IActuator ac = (IActuator) mDevices.get(key);
  315. if (ac instanceof VdrDevice) {
  316. list.add(ac.getName());
  317. }
  318. }
  319. return list.toArray(new CharSequence[list.size()]);
  320. }
  321. public boolean hasPlugins() {
  322. return (! mPlugins.isEmpty());
  323. }
  324. private void init() {
  325. mActivity = new ActivityDevice();
  326. if (new File(macroConfig).exists()) {
  327. MacroConfigParser parser = new MacroConfigParser(macroConfig);
  328. ArrayList<Macro> macros = parser.parse();
  329. if (macros == null) {
  330. logger.error("Couldn't parse macro configuration: {}", parser.lastError);
  331. } else {
  332. for (Macro macro : macros) {
  333. logger.debug("Macro: {}", macro.name);
  334. for (String command : macro.commands)
  335. logger.debug(" -> {}", command);
  336. mMacros.put(macro.name, macro);
  337. }
  338. }
  339. }
  340. loadPlugins();
  341. initDevices();
  342. }
  343. public void initDevices() {
  344. mDevices.clear();
  345. Cursor cursor = getCursorForAllDevices();
  346. while (cursor.moveToNext()) {
  347. addDevice(cursor);
  348. }
  349. cursor.close();
  350. dbClose();
  351. if (mOnDeviceConfigurationChangedListener != null)
  352. mOnDeviceConfigurationChangedListener.onChange();
  353. }
  354. private void initVolumeCommands(SharedPreferences sp) {
  355. if (sp.getBoolean("volumeVDR", false)) {
  356. mVolumeUpCommand = "VDR.vol_up";
  357. mVolumeDownCommand = "VDR.vol_down";
  358. } else {
  359. long deviceId = Long.parseLong(sp.getString("volumeDevice", "-1"));
  360. if (deviceId == -1) {
  361. mVolumeUpCommand = "";
  362. mVolumeDownCommand = "";
  363. } else {
  364. IDevice device = getDevice(deviceId);
  365. if (device == null) {
  366. mVolumeUpCommand = "";
  367. mVolumeDownCommand = "";
  368. } else {
  369. mVolumeUpCommand = device.getName() + "." + sp.getString("volumeUp", "");
  370. mVolumeDownCommand = device.getName() + "." + sp.getString("volumeDown", "");
  371. }
  372. }
  373. }
  374. }
  375. private void loadPlugins() {
  376. FilenameFilter filter = new FilenameFilter() {
  377. @Override
  378. public boolean accept(File dir, String filename) {
  379. return filename.endsWith(".jar");
  380. }
  381. };
  382. if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
  383. return;
  384. File filepath = new File(pluginDir);
  385. if (!filepath.exists())
  386. return;
  387. File dexpath = new File(pluginDir + File.separatorChar + "dex");
  388. if (!dexpath.exists())
  389. dexpath.mkdir();
  390. File files[] = filepath.listFiles(filter);
  391. if (files != null) {
  392. for (File file : files) {
  393. if (file.isFile()) {
  394. try {
  395. String className = null;
  396. JarFile jar = new JarFile(file);
  397. ZipEntry zipentry = jar
  398. .getEntry("META-INF/services/de.androvdr.devices.IActuator");
  399. if (zipentry != null) {
  400. InputStream is = jar.getInputStream(zipentry);
  401. BufferedReader br = new BufferedReader(
  402. new InputStreamReader(is), 8192);
  403. className = br.readLine();
  404. br.close();
  405. }
  406. ClassLoader loader = new DexClassLoader(file
  407. .getAbsolutePath(), dexpath.getAbsolutePath(),
  408. null, getClass().getClassLoader());
  409. Class<?> c = loader.loadClass(className);
  410. if (IDevice.class.isAssignableFrom(c)) {
  411. IDevice ac = (IDevice) c.newInstance();
  412. mPlugins.put(ac.getDisplayClassName(), c);
  413. logger.debug("Plugin: {}",
  414. (ac.getDisplayClassName() + " (" + c.getName() + ")"));
  415. }
  416. } catch (Exception e) {
  417. e.printStackTrace();
  418. }
  419. }
  420. }
  421. }
  422. }
  423. @Override
  424. public void onChannelChanged() {
  425. if (mChannelSensorJob != null) {
  426. mReceiveThread.updateChannel(mChannelSensorJob);
  427. }
  428. }
  429. @Override
  430. public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
  431. boolean isVolumePref = false;
  432. for (CharSequence s : volumePrefNames)
  433. if (s.equals(key)) {
  434. isVolumePref = true;
  435. break;
  436. }
  437. if (key.equals("volumeVDR") || isVolumePref)
  438. initVolumeCommands(sharedPreferences);
  439. if (key.equals("currentVdrId")) {
  440. VdrDevice vdr = Preferences.getVdr();
  441. if (vdr != null)
  442. vdr.addChannelChangedListener(this);
  443. }
  444. }
  445. public void onPause() {
  446. Enumeration<String> e = mDevices.keys();
  447. while (e.hasMoreElements()) {
  448. String key = e.nextElement();
  449. mDevices.get(key).disconnect();
  450. }
  451. }
  452. public void onResume() {
  453. // --- next full minute --
  454. long now = new Date().getTime();
  455. long delay = (now / 1000 / 60 + 1) * 60000 - now;
  456. // --- run SensorUpdate every minute ---
  457. mSensorUpdateTimer = new Timer();
  458. mSensorUpdateTimer.schedule(new SensorUpdater(), delay + 2000, 60000);
  459. logger.trace("Sensor update timer started");
  460. }
  461. public void send(String command) {
  462. logger.debug("send: {}", command);
  463. String sa[] = command.split("\\.");
  464. if (sa.length > 1 && sa[0].equals("Macro")) {
  465. Macro macro = mMacros.get(sa[1]);
  466. if (macro != null)
  467. new MacroThread(macro);
  468. else {
  469. sendErrorMessage("Macro " + sa[1] + " not found");
  470. }
  471. } else if (sa.length > 1 && sa[0].equals("Activity")) {
  472. String result = null;
  473. if (mActivity != null) {
  474. StringBuilder sb = new StringBuilder();
  475. for (int i = 1; i < sa.length; i++) {
  476. if (i > 1)
  477. sb.append(".");
  478. sb.append(sa[i]);
  479. }
  480. if (!mActivity.write(sb.toString()))
  481. result = mActivity.getLastError();
  482. if (result != null)
  483. sendErrorMessage(result);
  484. }
  485. } else {
  486. mSendThread.send(command);
  487. }
  488. }
  489. private void sendErrorMessage(String msg) {
  490. if (mResultHandler != null) {
  491. Bundle resultBundle = new Bundle();
  492. resultBundle.putString(MSG_RESULT, msg);
  493. Message resultMessage = new Message();
  494. resultMessage.setData(resultBundle);
  495. mResultHandler.sendMessage(resultMessage);
  496. }
  497. }
  498. public void setOnDeviceConfigurationChangedListener(OnChangeListener listener) {
  499. mOnDeviceConfigurationChangedListener = listener;
  500. }
  501. public void setParentActivity(Activity activity) {
  502. mActivity.setParentActivity(activity);
  503. }
  504. public void setResultHandler(Handler resultHandler) {
  505. mResultHandler = resultHandler;
  506. }
  507. public void startSensorUpdater(int delaySeconds) {
  508. if (mSensorJobs.size() > 0 && mSensorUpdateTimer == null) {
  509. new Timer().schedule(new SensorUpdater(), delaySeconds * 1000);
  510. mSensorUpdateTimer = new Timer();
  511. long now = new Date().getTime();
  512. long delay = (now / 60000 + 1) * 60000 - now;
  513. mSensorUpdateTimer.schedule(new SensorUpdater(), delay + 2000, 60000);
  514. logger.trace("Sensor update timer started (delay = {} sec)", delay / 1000 + 2 );
  515. }
  516. }
  517. public void stopSensorUpdater() {
  518. if (mSensorUpdateTimer != null) {
  519. mSensorUpdateTimer.cancel();
  520. mSensorUpdateTimer = null;
  521. logger.trace("Sensor update timer stopped");
  522. }
  523. }
  524. public void updateChannelSensor() {
  525. if (mChannelSensorJob != null)
  526. mReceiveThread.updateChannel(mChannelSensorJob);
  527. }
  528. public boolean volumeControl() {
  529. return (mVolumeDownCommand.length() > 0) || (mVolumeUpCommand.length() > 0);
  530. }
  531. public void volumeDown() {
  532. if (mVolumeDownCommand.length() > 0)
  533. send(mVolumeDownCommand);
  534. }
  535. public void volumeUp() {
  536. if (mVolumeUpCommand.length() > 0)
  537. send(mVolumeUpCommand);
  538. }
  539. private class DeviceSendThread extends Thread {
  540. private Handler mHandler;
  541. public void run() {
  542. Looper.prepare();
  543. mHandler = new Handler() {
  544. @Override
  545. public void handleMessage(Message msg) {
  546. Bundle bundle = msg.getData();
  547. if (bundle != null) {
  548. String command = bundle.getString("command");
  549. String[] sa = command.split("\\.");
  550. IActuator ac = null;
  551. if (sa[0].equals(VDR_CLASSNAME))
  552. ac = Preferences.getVdr();
  553. else {
  554. ac = mDevices.get(sa[0]);
  555. }
  556. String result = null;
  557. if (ac != null && sa.length > 1) {
  558. if (!ac.write(sa[1])) {
  559. result = ac.getLastError();
  560. }
  561. } else {
  562. result = "Error in command: " + command;
  563. }
  564. if (result != null)
  565. sendErrorMessage(result);
  566. }
  567. }
  568. };
  569. logger.trace("DeviceSendThread started");
  570. Looper.loop();
  571. }
  572. public void send(String command) {
  573. Bundle bundle = new Bundle();
  574. bundle.putString("command", command);
  575. Message msg = new Message();
  576. msg.setData(bundle);
  577. mHandler.sendMessage(msg);
  578. }
  579. }
  580. private class MacroThread extends Thread {
  581. private final Macro mMacro;
  582. public MacroThread(Macro macro) {
  583. mMacro = macro;
  584. start();
  585. }
  586. public void run() {
  587. for (String command : mMacro.commands) {
  588. String[] sa = command.split("\\.");
  589. if (sa.length > 1 && sa[0].equalsIgnoreCase("Sleep")) {
  590. try {
  591. int microSecond = Integer.parseInt(sa[1]);
  592. Thread.sleep(microSecond);
  593. } catch (NumberFormatException e) {
  594. logger.error("Invalid sleep value");
  595. } catch (InterruptedException e) {
  596. logger.trace("MacroThread interrupted");
  597. }
  598. } else {
  599. send(command);
  600. }
  601. }
  602. }
  603. }
  604. private class SensorJob {
  605. public String command;
  606. public int interval;
  607. public long lastReceiveTime = 0;
  608. public OnSensorChangeListener listener;
  609. public SensorJob(String command, int interval, OnSensorChangeListener listener) {
  610. this.command = command;
  611. this.interval = interval;
  612. this.listener = listener;
  613. }
  614. }
  615. private class SensorReceiveThread extends Thread {
  616. private Handler mHandler;
  617. private Boolean isUpdating = false;
  618. public void run() {
  619. Looper.prepare();
  620. mHandler = new Handler() {
  621. @Override
  622. public void handleMessage(Message msg) {
  623. SensorJob job = (SensorJob) msg.obj;
  624. logger.trace("SensorReceiveThread: {}", job.command);
  625. ISensor sensor = null;
  626. String[] sa = job.command.split("\\.");
  627. if (sa[0].equals(VDR_CLASSNAME))
  628. sensor = Preferences.getVdr();
  629. else {
  630. sensor = mSensors.get(sa[0]);
  631. }
  632. String result = null;
  633. if (sensor != null && sa.length > 1) {
  634. result = sensor.read(sa[1]);
  635. if (result != null) {
  636. job.listener.onChange(result);
  637. } else {
  638. logger.error("SensorReceiveThread: {}", sensor.getLastError());
  639. job.listener.onChange("N/A");
  640. }
  641. } else {
  642. logger.error("SensorReceiveThread: Error in command: {}", job.command);
  643. }
  644. job.lastReceiveTime = new Date().getTime() / 60000;
  645. }
  646. };
  647. logger.trace("SensorReceiveThread started");
  648. Looper.loop();
  649. }
  650. public void receive(SensorJob job) {
  651. Message msg = new Message();
  652. msg.obj = job;
  653. mHandler.sendMessage(msg);
  654. }
  655. public void updateChannel(final SensorJob job) {
  656. synchronized (isUpdating) {
  657. if (! isUpdating) {
  658. TimerTask tt = new TimerTask() {
  659. @Override
  660. public void run() {
  661. synchronized (isUpdating) {
  662. mReceiveThread.receive(job);
  663. isUpdating = false;
  664. }
  665. }
  666. };
  667. isUpdating = true;
  668. new Timer().schedule(tt, 2000);
  669. }
  670. }
  671. }
  672. }
  673. private class SensorUpdater extends TimerTask {
  674. @Override
  675. public void run() {
  676. long timeInMinutes = new Date().getTime() / 60000;
  677. logger.trace("SensorUpdater: {}", new SimpleDateFormat("HH:mm:ss").format(new Date()));
  678. synchronized (mSensorJobs) {
  679. for (SensorJob job : mSensorJobs) {
  680. if (job.lastReceiveTime + job.interval <= timeInMinutes)
  681. mReceiveThread.receive(job);
  682. }
  683. }
  684. }
  685. }
  686. }