PageRenderTime 57ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/Android/src/com/drhelper/service/NoticeService.java

https://github.com/weiganyi/dr-helper
Java | 581 lines | 422 code | 92 blank | 67 comment | 79 complexity | 0c66e5c3990895a9cc35b5a80f06da3e MD5 | raw file
  1. package com.drhelper.service;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.OutputStream;
  5. import java.io.UnsupportedEncodingException;
  6. import java.net.Socket;
  7. import java.net.UnknownHostException;
  8. import java.util.Timer;
  9. import java.util.TimerTask;
  10. import java.util.concurrent.locks.ReentrantLock;
  11. import com.alibaba.fastjson.JSON;
  12. import com.drhelper.R;
  13. import com.drhelper.activity.CheckTableActivity;
  14. import com.drhelper.activity.MainActivity;
  15. import com.drhelper.bean.com.NoticeDetail;
  16. import com.drhelper.bean.com.NoticeHeartBeat;
  17. import com.drhelper.bean.com.NoticeLogin;
  18. import com.drhelper.bean.com.NoticeLogout;
  19. import com.drhelper.bean.com.NoticePush;
  20. import com.drhelper.bean.com.NoticeSubscribe;
  21. import com.drhelper.util.HttpEngine;
  22. import com.drhelper.util.PrefsManager;
  23. import android.annotation.SuppressLint;
  24. import android.app.Notification;
  25. import android.app.NotificationManager;
  26. import android.app.PendingIntent;
  27. import android.app.Service;
  28. import android.content.BroadcastReceiver;
  29. import android.content.Context;
  30. import android.content.Intent;
  31. import android.content.IntentFilter;
  32. import android.content.SharedPreferences;
  33. import android.os.IBinder;
  34. import android.util.Log;
  35. @SuppressLint("WorldReadableFiles")
  36. public class NoticeService extends Service {
  37. private static final String NOTICE_SERVICE_TAG = "NoticeService";
  38. private static final int PORT = 30000;
  39. private ExitReceiver exitReceiver;
  40. private SubReceiver subReceiver;
  41. private KilledReceiver killedReceiver;
  42. private NotificationManager noticeMgr;
  43. private int noticeNum = 0;
  44. private Thread threadId = null;
  45. private Socket socket = null;
  46. private String userName;
  47. private String userPasswd;
  48. private OutputStream out = null;
  49. private InputStream in = null;
  50. private static final String heartBeatEvent = "heartbeat";
  51. private boolean is_empty_table = false;
  52. private boolean is_finish_menu = false;
  53. private ServiceWorker worker;
  54. private String logoutUserName = null;
  55. private ReentrantLock lock;
  56. private Timer timer;
  57. private HeartBeatTask task;
  58. private static final String connectLostEvent = "connlost";
  59. @Override
  60. public void onCreate() {
  61. Log.e(NOTICE_SERVICE_TAG, "NoticeService.onCreate(): enter");
  62. //register the exit receiver
  63. exitReceiver = new ExitReceiver();
  64. IntentFilter filter = new IntentFilter();
  65. filter.addAction("com.drhelper.service.intent.action.EXIT");
  66. registerReceiver(exitReceiver, filter);
  67. //register the subscribe receiver
  68. subReceiver = new SubReceiver();
  69. IntentFilter filter2 = new IntentFilter();
  70. filter2.addAction("com.drhelper.service.intent.action.SUBSCRIBE");
  71. registerReceiver(subReceiver, filter2);
  72. //register the kill receiver
  73. killedReceiver = new KilledReceiver();
  74. IntentFilter filter3 = new IntentFilter();
  75. filter3.addAction("com.drhelper.service.intent.action.KILLED");
  76. registerReceiver(killedReceiver, filter3);
  77. //get the notice manager
  78. noticeMgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
  79. //create a thread to detect notice from background
  80. worker = new ServiceWorker();
  81. if (worker != null) {
  82. threadId = new Thread(worker, "NoticeService");
  83. if (threadId != null) {
  84. threadId.start();
  85. }
  86. }
  87. //create a lock
  88. lock = new ReentrantLock();
  89. //start a timer to do heartbeat
  90. timer = new Timer();
  91. task = new HeartBeatTask();
  92. timer.schedule(task, 10000, 10000); //after 10s to start, loop 10s timeout
  93. super.onCreate();
  94. }
  95. @Override
  96. public int onStartCommand(Intent intent, int flags, int startId) {
  97. is_empty_table = intent.getExtras().getBoolean("empty_table");
  98. is_finish_menu = intent.getExtras().getBoolean("finish_menu");
  99. return super.onStartCommand(intent, flags, startId);
  100. }
  101. @Override
  102. public void onDestroy() {
  103. Log.e(NOTICE_SERVICE_TAG, "NoticeService.onDestroy(): enter");
  104. //stop the timer
  105. task.cancel();
  106. timer.purge();
  107. //do logout
  108. if (logoutUserName != null && logoutUserName.equals("") != true) {
  109. worker.doLogout();
  110. }
  111. //unregister the receiver
  112. unregisterReceiver(exitReceiver);
  113. unregisterReceiver(subReceiver);
  114. unregisterReceiver(killedReceiver);
  115. //close the socket
  116. if (socket != null) {
  117. try {
  118. socket.close();
  119. } catch (IOException e) {
  120. Log.e(NOTICE_SERVICE_TAG, "NoticeService.destoryNoticeThread(): close the socket failure");
  121. }
  122. }
  123. //cancel all notice
  124. noticeMgr.cancelAll();
  125. //stop the notice recv thread
  126. //after do it, the thread will detect the interrupt flag, then exit
  127. if (threadId != null) {
  128. threadId.interrupt();
  129. }
  130. super.onDestroy();
  131. }
  132. @Override
  133. public IBinder onBind(Intent intent) {
  134. return null;
  135. }
  136. private class ServiceWorker implements Runnable {
  137. @Override
  138. public void run() {
  139. boolean result = false;
  140. String content = null;
  141. boolean isConnLost = false;
  142. Log.e(NOTICE_SERVICE_TAG, "ServiceWorker.run(): thread enter");
  143. // do login first
  144. result = doLogin();
  145. if (!result) {
  146. Log.e(NOTICE_SERVICE_TAG, "ServiceWorker.run(): doLogin failure");
  147. doExitService();
  148. return;
  149. }
  150. //check if thread had been interrupted
  151. while (!Thread.interrupted()) {
  152. try {
  153. lock.lock();
  154. // get message from server
  155. if ((content = readFromServer(in)) == null) {
  156. lock.unlock();
  157. continue;
  158. }
  159. //check if is connectLostEvent
  160. if (content.equals(connectLostEvent) == true) {
  161. //because it means the remote connect had lost, exit this worker and service
  162. lock.unlock();
  163. isConnLost = true;
  164. break;
  165. }
  166. // check if is NoticeHeartBeat response
  167. NoticeHeartBeat nhb = JSON.parseObject(content, NoticeHeartBeat.class);
  168. if (nhb != null &&
  169. nhb.getMsg() != null &&
  170. nhb.getMsg().equals(heartBeatEvent) == true &&
  171. nhb.isResult() == true) {
  172. lock.unlock();
  173. continue;
  174. }
  175. // check if is NoticePush
  176. NoticePush np = JSON.parseObject(content, NoticePush.class);
  177. if (np != null && np.getEvent() != null) {
  178. doNoticeDetailPull(np.getEvent());
  179. }
  180. lock.unlock();
  181. }catch (Exception e) {
  182. Log.e(NOTICE_SERVICE_TAG, "NoticeService.ServiceWorker.run(): catch Exception");
  183. lock.unlock();
  184. }
  185. }
  186. //if connect lost, it means the thread had been killed, we should start this thread again
  187. if (isConnLost) {
  188. Log.e(NOTICE_SERVICE_TAG, "ServiceWorker.run(): connect lost");
  189. doKilledService();
  190. }
  191. Log.e(NOTICE_SERVICE_TAG, "ServiceWorker.run(): thread exit");
  192. return;
  193. }
  194. private boolean doExitService() {
  195. String action = null;
  196. Intent intent = null;
  197. String userName = null;
  198. SharedPreferences prefs = getSharedPreferences("login_user", MODE_WORLD_WRITEABLE);
  199. if (prefs != null) {
  200. //get the user
  201. userName = prefs.getString("user_name", "");
  202. }
  203. action = "com.drhelper.service.intent.action.EXIT";
  204. intent = new Intent(action);
  205. intent.putExtra("logout_user", userName);
  206. sendBroadcast(intent);
  207. PrefsManager.setNotice_service_start(false);
  208. return true;
  209. }
  210. private boolean doKilledService() {
  211. if (PrefsManager.isEmpty_table_notice() == true ||
  212. PrefsManager.isFinish_menu_notice() == true) {
  213. String action = null;
  214. Intent intent = null;
  215. action = "com.drhelper.service.intent.action.KILLED";
  216. intent = new Intent(action);
  217. sendBroadcast(intent);
  218. }
  219. return true;
  220. }
  221. private void doNoticeDetailPull(String event) {
  222. // if has notice, then get the notice detail from server
  223. NoticeDetail noticeDetailReq = new NoticeDetail();
  224. noticeDetailReq.setEvent(event);
  225. //serialize by fastjson
  226. String reqBody = JSON.toJSONString(noticeDetailReq);
  227. // send the http post and recv response
  228. String specUrl = "getNotice.do";
  229. String respBody = HttpEngine.doPost(specUrl, reqBody);
  230. if (respBody == null || respBody.length() == 0) {
  231. Log.e(NOTICE_SERVICE_TAG,
  232. "NoticeService.ServiceWorker.doNoticeDetailPull(): respBody is null");
  233. return;
  234. }
  235. // unserialize from response string
  236. NoticeDetail noticeDetailResp = JSON.parseObject(
  237. respBody, NoticeDetail.class);
  238. // send the empty table notice
  239. if (noticeDetailResp.isEmptyTable() == true) {
  240. int emptyTableIcon = R.drawable.empty_table;
  241. String emptyTableInfo = getString(R.string.notice_service_empty_table);
  242. long emptyTableWhen = System.currentTimeMillis();
  243. Notification emptyTableNotice = new Notification(
  244. emptyTableIcon, emptyTableInfo,
  245. emptyTableWhen);
  246. // emptyTableNotice.flags = Notification.FLAG_NO_CLEAR;
  247. Intent intent1 = new Intent(NoticeService.this,
  248. CheckTableActivity.class);
  249. PendingIntent emptyTableIntent = PendingIntent
  250. .getActivity(NoticeService.this, 0,
  251. intent1, 0);
  252. emptyTableNotice.setLatestEventInfo(
  253. NoticeService.this, null, emptyTableInfo,
  254. emptyTableIntent);
  255. noticeMgr.notify(noticeNum++, emptyTableNotice);
  256. }
  257. // send the finish menu notice
  258. if (noticeDetailResp.isFinishMenu() == true) {
  259. int finishMenuTable = noticeDetailResp.getTable();
  260. int finishMenuIcon = R.drawable.finish_menu;
  261. String finishMenuInfo = String
  262. .valueOf(finishMenuTable)
  263. + getString(R.string.notice_service_finish_menu);
  264. long finishMenuWhen = System.currentTimeMillis();
  265. Notification finishMenuNotice = new Notification(
  266. finishMenuIcon, finishMenuInfo,
  267. finishMenuWhen);
  268. // finishMenuNotice.flags = Notification.FLAG_NO_CLEAR;
  269. Intent intent2 = new Intent(NoticeService.this,
  270. MainActivity.class);
  271. PendingIntent finishMenuIntent = PendingIntent
  272. .getActivity(NoticeService.this, 0,
  273. intent2, 0);
  274. finishMenuNotice.setLatestEventInfo(
  275. NoticeService.this, null, finishMenuInfo,
  276. finishMenuIntent);
  277. noticeMgr.notify(noticeNum++, finishMenuNotice);
  278. }
  279. }
  280. private boolean doLogin() {
  281. //create a socket
  282. String url = PrefsManager.getServer_address();
  283. try {
  284. socket = new Socket(url, PORT);
  285. //set the noblock timeout to 1s
  286. socket.setSoTimeout(1000);
  287. } catch (UnknownHostException e) {
  288. Log.e(NOTICE_SERVICE_TAG, "NoticeService.ServiceWorker.doLogin(): create the socket parse host failure ");
  289. return false;
  290. } catch (IOException e) {
  291. Log.e(NOTICE_SERVICE_TAG, "NoticeService.ServiceWorker.doLogin(): create the socket failure");
  292. return false;
  293. }
  294. //construct InputStream and OutputStream
  295. try {
  296. out = socket.getOutputStream();
  297. } catch (IOException e) {
  298. Log.e(NOTICE_SERVICE_TAG, "NoticeService.ServiceWorker.doLogin(): getOutputStream connect to remote failure");
  299. return false;
  300. }
  301. try {
  302. in = socket.getInputStream();
  303. } catch (IOException e) {
  304. Log.e(NOTICE_SERVICE_TAG, "NoticeService.ServiceWorker.doLogin(): getInputStream connect to remote failure");
  305. return false;
  306. }
  307. //do login
  308. SharedPreferences prefs = getSharedPreferences("login_user", MODE_WORLD_READABLE);
  309. if (prefs == null) {
  310. Log.e(NOTICE_SERVICE_TAG, "NoticeService.ServiceWorker.doLogin(): getSharedPreferences failure");
  311. return false;
  312. }
  313. //get the name and passwd from shared prefs
  314. userName = prefs.getString("user_name", "");
  315. userPasswd = prefs.getString("user_passwd", "");
  316. if (userName.equals("") || userPasswd.equals("")) {
  317. Log.e(NOTICE_SERVICE_TAG, "NoticeService.ServiceWorker.doLogin(): userName or userPasswd is null");
  318. return false;
  319. }
  320. //create NoticeLogin object
  321. NoticeLogin loginReq = new NoticeLogin();
  322. loginReq.setLoginUserName(userName);
  323. loginReq.setLoginUserPasswd(userPasswd);
  324. //serialize by fastjson
  325. String request = JSON.toJSONString(loginReq);
  326. //send the request and recv response
  327. writeToServer(out, request);
  328. String content = readFromServer(in);
  329. if (content == null) {
  330. Log.e(NOTICE_SERVICE_TAG, "NoticeService.ServiceWorker.doLogin(): login return null");
  331. return false;
  332. }
  333. NoticeLogin loginResp = JSON.parseObject(content, NoticeLogin.class);
  334. if (loginResp.isResult() != true ||
  335. loginResp.getLoginUserName().equals(userName) == false) {
  336. Log.e(NOTICE_SERVICE_TAG, "NoticeService.ServiceWorker.doLogin(): login result is failure");
  337. return false;
  338. }
  339. //subscribe the notice
  340. if (is_empty_table || is_finish_menu) {
  341. doSubscribe(is_empty_table, is_finish_menu);
  342. }
  343. return true;
  344. }
  345. public boolean doLogout() {
  346. //create NoticeLogout object
  347. NoticeLogout logoutReq = new NoticeLogout();
  348. logoutReq.setLogoutUserName(logoutUserName);
  349. //serialize by fastjson
  350. String request = JSON.toJSONString(logoutReq);
  351. //send the request and recv response
  352. writeToServer(out, request);
  353. /*
  354. String content = readFromServer(in);
  355. if (content == null) {
  356. Log.e(NOTICE_SERVICE_TAG, "NoticeService.ServiceWorker.doLogout(): logout return null");
  357. return false;
  358. }
  359. NoticeLogout logoutResp = JSON.parseObject(content, NoticeLogout.class);
  360. if (logoutResp.isResult() != true ||
  361. logoutResp.getLogoutUserName().equals(logoutUserName) == false) {
  362. Log.e(NOTICE_SERVICE_TAG, "NoticeService.ServiceWorker.doLogout(): logout result is failure");
  363. return false;
  364. }
  365. */
  366. return true;
  367. }
  368. public boolean doSubscribe(boolean emptyTable, boolean finishMenu) {
  369. //create NoticeLogout object
  370. NoticeSubscribe subReq = new NoticeSubscribe();
  371. subReq.setEmptyTable(emptyTable);
  372. subReq.setFinishMenu(finishMenu);
  373. //serialize by fastjson
  374. String request = JSON.toJSONString(subReq);
  375. //send the request and recv response
  376. lock.lock();
  377. writeToServer(out, request);
  378. String content = readFromServer(in);
  379. lock.unlock();
  380. if (content == null) {
  381. Log.e(NOTICE_SERVICE_TAG, "NoticeService.ServiceWorker.doSubscribe(): subscribe return null");
  382. return false;
  383. }
  384. NoticeSubscribe subResp = JSON.parseObject(content, NoticeSubscribe.class);
  385. if (subResp.isResult() != true) {
  386. Log.e(NOTICE_SERVICE_TAG, "NoticeService.ServiceWorker.doSubscribe(): subscribe result is failure");
  387. return false;
  388. }
  389. return true;
  390. }
  391. }
  392. public boolean writeToServer(OutputStream out, String request) {
  393. if (out != null) {
  394. try {
  395. out.write(request.getBytes("utf-8"));
  396. return true;
  397. } catch (UnsupportedEncodingException e) {
  398. Log.e(NOTICE_SERVICE_TAG, "NoticeService.writeToServer(): message encode failure");
  399. } catch (IOException e) {
  400. Log.e(NOTICE_SERVICE_TAG, "NoticeService.writeToServer(): write data catch IOException");
  401. }
  402. }
  403. return false;
  404. }
  405. public String readFromServer(InputStream in) {
  406. if (in != null) {
  407. byte[] receiveBuf = new byte[128];
  408. int recvMsgSize = 0;
  409. String content = null;
  410. try {
  411. recvMsgSize = in.read(receiveBuf);
  412. if (recvMsgSize != -1) {
  413. if (recvMsgSize != 0) {
  414. content = new String(receiveBuf, 0, recvMsgSize);
  415. return content;
  416. }
  417. }else {
  418. //if remote disconnect, come here
  419. content = new String(connectLostEvent);
  420. return content;
  421. }
  422. } catch (IOException e) {
  423. Log.e(NOTICE_SERVICE_TAG, "NoticeService.readFromServer(): read data catch IOException");
  424. }
  425. }
  426. return null;
  427. }
  428. private class ExitReceiver extends BroadcastReceiver {
  429. @Override
  430. public void onReceive(Context context, Intent intent) {
  431. if (intent.getAction().equals("com.drhelper.service.intent.action.EXIT")) {
  432. if (intent.getExtras() != null) {
  433. logoutUserName = intent.getExtras().getString("logout_user");
  434. }
  435. //exit this service
  436. stopSelf();
  437. }
  438. }
  439. }
  440. private class SubReceiver extends BroadcastReceiver {
  441. @Override
  442. public void onReceive(Context context, Intent intent) {
  443. if (intent.getAction().equals("com.drhelper.service.intent.action.SUBSCRIBE")) {
  444. is_empty_table = intent.getExtras().getBoolean("empty_table");
  445. is_finish_menu = intent.getExtras().getBoolean("finish_menu");
  446. //do subscribe
  447. worker.doSubscribe(is_empty_table, is_finish_menu);
  448. }
  449. }
  450. }
  451. private class KilledReceiver extends BroadcastReceiver {
  452. @Override
  453. public void onReceive(Context context, Intent intent) {
  454. if (intent.getAction().equals("com.drhelper.service.intent.action.KILLED")) {
  455. //close the socket
  456. if (socket != null) {
  457. try {
  458. socket.close();
  459. } catch (IOException e) {
  460. Log.e(NOTICE_SERVICE_TAG, "NoticeService.KilledReceiver.onReceive(): close the socket failure");
  461. }
  462. }
  463. //create a thread to detect notice from background
  464. worker = new ServiceWorker();
  465. if (worker != null) {
  466. threadId = new Thread(worker, "NoticeService");
  467. if (threadId != null) {
  468. threadId.start();
  469. }
  470. }
  471. }
  472. }
  473. }
  474. class HeartBeatTask extends TimerTask {
  475. @Override
  476. public void run() {
  477. //create the NoticeHeartBeat object
  478. NoticeHeartBeat hbReq = new NoticeHeartBeat();
  479. hbReq.setMsg(heartBeatEvent);
  480. //serialize by fastjson
  481. String request = JSON.toJSONString(hbReq);
  482. //send the request
  483. lock.lock();
  484. writeToServer(out, request);
  485. lock.unlock();
  486. return;
  487. }
  488. }
  489. }