/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package my.home.lehome.service; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.PowerManager; import android.text.TextUtils; import android.util.Log; import android.widget.Toast; import org.zeromq.ZMQ; import org.zeromq.ZMQException; import my.home.lehome.R; import my.home.lehome.activity.MainActivity; import my.home.lehome.helper.MessageHelper; import my.home.lehome.receiver.LocalMessageReceiver; import my.home.lehome.receiver.ScreenStateReceiver; import zmq.ZError; /** * Created by legendmohe on 15/3/9. */ public class LocalMessageService extends Service { private static final String TAG = "LocalMessageService"; public static final int MSG_SET_SUBSCRIBE_ADDRESS = 0; // public static final int MSG_REGISTER_CLIENT = 1; // public static final int MSG_UNREGISTER_CLIENT = 2; public static final int MSG_STOP_SERVICE = 3; // public static final int MSG_SEND_CMD = 4; public static final int MSG_SERVER_RECEIVE_MSG = 0; private static final int ONGOING_NOTIFICATION_ID = 9000; public static final String LOCAL_MESSAGE_SERVICE_NOTIFICATION_ACTION = "LOCAL_MESSAGE_SERVICE_NOTIFICATION_ACTION"; private String mServiceAddress = ""; private ScreenStateReceiver mScreenStateReceiver; NotificationManager mNM; // ArrayList<Messenger> mClients = new ArrayList<Messenger>(); private Thread mSubThread; private SubRunnable mSubRunnable; private PowerManager.WakeLock mWakeLock; /** * Handler of incoming messages from clients. */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { Bundle bundle = null; Log.d(TAG, "handle msg: " + msg.what); switch (msg.what) { // case MSG_REGISTER_CLIENT: // mClients.add(msg.replyTo); // break; // case MSG_UNREGISTER_CLIENT: // mClients.remove(msg.replyTo); // break; case MSG_SET_SUBSCRIBE_ADDRESS: bundle = msg.getData(); if (bundle != null) { setServerAddress(bundle.getString("server_address")); } break; case MSG_STOP_SERVICE: stopLocalMsgService(); break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ final Messenger mMessenger = new Messenger(new IncomingHandler()); @Override public IBinder onBind(Intent intent) { Toast.makeText(getApplicationContext(), getString(R.string.msg_local_binding), Toast.LENGTH_SHORT).show(); return mMessenger.getBinder(); } @Override public void onCreate() { super.onCreate(); // Log.d(TAG, "in onCreate"); mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); if (mScreenStateReceiver == null) { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_SCREEN_OFF); mScreenStateReceiver = new ScreenStateReceiver(); registerReceiver(mScreenStateReceiver, filter); } mServiceAddress = MessageHelper.getLocalServerSubscribeURL(this); initSubscriber(mServiceAddress); if (mWakeLock == null) { PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); mWakeLock.acquire(); } Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class); notificationIntent.setAction(LOCAL_MESSAGE_SERVICE_NOTIFICATION_ACTION); PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); Notification.Builder builder = new Notification.Builder(this) .setSmallIcon(R.drawable.ic_launcher) .setTicker(getText(R.string.foreground_local_msg_service_ticker)) // .setWhen(System.currentTimeMillis()) .setContentTitle(getText(R.string.foreground_local_msg_service_title)) .setContentText(getText(R.string.foreground_local_msg_service_message)) .setContentIntent(pendingIntent); Notification notification = builder.build(); startForeground(ONGOING_NOTIFICATION_ID, notification); } @Override public void onRebind(Intent intent) { Log.d(TAG, "in onRebind"); super.onRebind(intent); } @Override public boolean onUnbind(Intent intent) { Log.d(TAG, "in onUnbind"); return true; } @Override public void onDestroy() { stopForeground(true); if (mSubThread != null) { mSubRunnable.setGoingStop(true); if (!mSubThread.isInterrupted()) { mSubThread.interrupt(); try { mSubThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } } if (mScreenStateReceiver != null) { unregisterReceiver(mScreenStateReceiver); mScreenStateReceiver = null; } super.onDestroy(); if (mWakeLock != null) { mWakeLock.release(); mWakeLock = null; } Log.d(TAG, "onDestroy"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return START_STICKY; } private void setServerAddress(String address) { Log.d(TAG, "connect server: " + address); if (mServiceAddress != null && !mServiceAddress.equals(address)) { mServiceAddress = address; initSubscriber(mServiceAddress); } } private void stopLocalMsgService() { Log.d(TAG, "disconnect server: " + mServiceAddress); mSubRunnable.setGoingStop(true); stopSelf(); } private void initSubscriber(String serverAddress) { Log.d(TAG, "init server: " + serverAddress); if (TextUtils.isEmpty(serverAddress) && !serverAddress.startsWith("tcp://")) { return; } if (mSubThread != null) { mSubRunnable.setGoingStop(true); if (!mSubThread.isInterrupted()) { mSubThread.interrupt(); try { mSubThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } } mSubRunnable = new SubRunnable(serverAddress); mSubThread = new Thread(mSubRunnable); mSubThread.start(); } private void sendSubResponse(String repString) { // for (int i = mClients.size() - 1; i >= 0; i--) { // try { // Message msg = Message.obtain(); // msg.what = MSG_SERVER_RECEIVE_MSG; // msg.obj = repString; // mClients.get(i).send(msg); // } catch (RemoteException e) { // mClients.remove(i); // } // } if (TextUtils.isEmpty(repString)) return; Intent repIntent = new Intent(); repIntent.setAction(LocalMessageReceiver.LOCAL_MSG_RECEIVER_ACTION); repIntent.putExtra(LocalMessageReceiver.LOCAL_MSG_REP_KEY, repString); sendBroadcast(repIntent); } private boolean shouldSendReponse(String repString) { return !repString.contains("\"heartbeat\""); // JSONTokener jsonParser = new JSONTokener(repString); // try { // JSONObject repJO = (JSONObject) jsonParser.nextValue(); // String type = repJO.getString("type"); // if (!type.equals("heartbeat")) // return true; // } catch (JSONException e) { // e.printStackTrace(); // } // return false; } private class SubRunnable implements Runnable { private ZMQ.Socket subscriber; private ZMQ.Context zmqContext; private boolean isGoingStop = false; private String serverAddress = null; public SubRunnable(String serverAddress) { this.serverAddress = serverAddress; } public void setGoingStop(boolean goingStop) { this.isGoingStop = goingStop; } @Override public void run() { zmqContext = ZMQ.context(1); subscriber = zmqContext.socket(ZMQ.SUB); ZMQ.Poller poller = null; try { poller = new ZMQ.Poller(1); poller.register(subscriber, ZMQ.Poller.POLLIN); subscriber.connect(serverAddress); subscriber.subscribe("".getBytes()); while (!Thread.currentThread().isInterrupted() && !isGoingStop) { poller.poll(1000 * 5); if (poller.pollin(0) && !isGoingStop) { String repString = subscriber.recvStr(ZMQ.DONTWAIT); Log.d(TAG, "received response: " + repString); if (shouldSendReponse(repString)) sendSubResponse(repString); } } } catch (ZMQException e) { Log.e(TAG, Log.getStackTraceString(e)); e.printStackTrace(); Toast.makeText(getApplicationContext(), getString(R.string.error_connect_local_server), Toast.LENGTH_SHORT).show(); } catch (ZError.IOException e) { Log.e(TAG, Log.getStackTraceString(e)); } catch (Exception e) { Log.e(TAG, Log.getStackTraceString(e)); } finally { if (!Thread.currentThread().isInterrupted()) { if (poller != null) { poller.unregister(subscriber); } subscriber.close(); zmqContext.term(); } } Log.d(TAG, "SubRunnable exit. " + isGoingStop + " thread: " + Thread.currentThread().isInterrupted()); } } ; }