SocketService1.java 18.1 KB
package com.qnbar.smc.service;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import com.gimi.common.cinema.model.MessageEvent;
import com.gimi.common.cinema.model.RoomInfo;
import com.gimi.common.cinema.utils.SystemUtils;
import com.gimi.common.cinema.utils.Utils;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.qnbar.smc.utils.LightOperationUtils;
import com.xgimi.gimicinema.activity.QrCodeShowActivity;
import com.xgimi.gimicinema.application.FangTangApplication;
import com.xgimi.smartscreen.encrypt.AuthCode;
import org.greenrobot.eventbus.EventBus;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.net.Socket;
import java.util.Arrays;

import static com.qnbar.smc.service.SocketService.JUST_OPEN_DOOR;
import static com.qnbar.smc.service.SocketService.USER_OPEN_DOOR;
import static com.qnbar.smc.service.SocketService.USER_OPEN_DOOR_AND_GET_MOVIE;

public class SocketService1 extends Service {
    private static final String TAG = "BackService1";
    private static final long HEART_BEAT_RATE = 2 * 1000;

    //    public static final int USER_OPEN_DOOR_AND_GET_MOVIE = 1703;
    /*
    * 10001 //服务器发送了命令(带命令的返回消息),这个一般是服务器主动发消息的时候code为这个值
      10002 //连接(认证)失败
      10003 //还未注册连接就进行认证
      10004 //终端编号未传
      10005 //心跳异常,没有找到房间连接信息
      10006 //心跳异常,连接标识符不一致
      10007 //收到未知命令
      10008 //收到无法解析的消息
      10009 //已经认证过了,不允许再认证
      10010 //room_sn 已连接,不能再连接

      9997  //心跳成功
      9998  //请求认证被服务器接受了,服务器返回了认证码
      9999  //认证成功,可以开始心跳了
    */
    private static final int HEART_BEAT_SUCCESS = 9997;
    private static final int RETURN_VERIFY_CODE = 9998;
    private static final int VERIFY_SUCCESS = 9999;
    private static final int SUCCESS_MESSAGE = 10000;
    private static final int CONTAIN_MESSAGE = 10001;
    private static final int AUTHENTICATION_FAILED = 10002; //连接(认证)失败
    private static final int CONNECTION_BEFORE_AUTHENTICATION = 10003;//还未注册连接就进行认证
    private static final int NOT_SEND_ROOM_SN = 10004;//终端编号未传
    private static final int HEART_BEAR_ERROR = 10005; //心跳异常,没有找到房间连接信息
    private static final int HEART_BEAT_ERROR_SYMBOL = 10006;//心跳异常,连接标识符不一致
    private static final int ROOM_SN_CONNECTED = 10010;//room_sn 已连接,不能再连接
    private static final int OPEN_DOOR = 50001;//开门命令
    private static final int CLEAN_OVER = 50002;//

    private static final int ROOM_HAS_REGISTERED = 1001;
    private static final int ROOM_NOT_EXIST_M = 1002;
    private static final int HEAT_BEAT_RTN = 1003;

    //    online
    public static final String SERVER_HOST_ONLINE = "conn.ft.qnbar.com";// "192.168.1.21";//
    public static final int SERVER_PORT_ONLINE = 8899;

    //    develop
    public static final String SERVER_HOST_DEVELOP = "10.10.4.6";// "192.168.1.21";//
    public static final int SERVER_PORT_DEVELOP = 9501;
    //    test
    public static final String SERVER_HOST = "10.10.4.6";// "192.168.1.21";//
    public static final int SERVER_PORT = 8899;

    private String serverHost = SERVER_HOST;
    private int serverPort = SERVER_PORT;


    public static final String END_SYMBOL = "\\r\\n\\r\\n";//心跳包内容
    //    public String testRoomSn = "R170413034374";
    public String testRoomSn = "c";

    private ReadThread mReadThread;
    private Gson gson;

    private WeakReference<Socket> mSocket;
    // For heart Beat
    private Handler mHandler = new Handler();
    private Runnable heartBeatRunnable = new Runnable() {

        @Override
        public void run() {
            Log.d(TAG, "heart beat");
            mHandler.postDelayed(this, HEART_BEAT_RATE);
            boolean isSuccess = sendMsg(new Gson().toJson(new SocketSendMsg().contractHeartBeatMsg(testRoomSn)) + END_SYMBOL);//就发送一个HEART_BEAT_STRING过去 如果发送失败,就重新初始化一个socket
            if (!isSuccess) {
                Log.d(TAG, "heart beat error restart");
                mHandler.removeCallbacks(heartBeatRunnable);
                mReadThread.release();
                sendRegister = false;
                releaseLastSocket(mSocket);
                new InitSocketThread().start();
            }
        }
    };

    private long sendTime = 0L;
    private Context context;

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        gson = new Gson();
        context = this;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        int ftTest = Utils.getInt(this, "ft-test", 0);
        switch (ftTest) {
            case 0:
                serverHost = SERVER_HOST_ONLINE;
                serverPort = SERVER_PORT_ONLINE;
                break;
            case 1:
                serverHost = SERVER_HOST_DEVELOP;
                serverPort = SERVER_PORT_DEVELOP;
                break;
            case 2:
                serverHost = SERVER_HOST;
                serverPort = SERVER_PORT;
                break;
        }

        String roomInfoStr = Utils.getString(this, "room-info");
        if (!TextUtils.isEmpty(roomInfoStr)) {
            Log.d("room-info", "room info not null");
            RoomInfo roomInfo = null;
            try {
                roomInfo = gson.fromJson(roomInfoStr, RoomInfo.class);
                Log.d("room-info", "room info room_sn update");
                testRoomSn = roomInfo.getData().getRoom_sn();
            } catch (JsonSyntaxException e) {
                Log.d("room-info", "room gson parse exception return");
                Toast.makeText(this, "房间信息配置出错,请重新进入应用获取", Toast.LENGTH_SHORT).show();
                e.printStackTrace();
                return super.onStartCommand(intent, flags, startId);
            }
        } else {
            Log.d("room-info", "room info not exist");
            Toast.makeText(this, "没有获取到房间信息,请查看后台配置", Toast.LENGTH_SHORT).show();
            return super.onStartCommand(intent, flags, startId);
        }
        new InitSocketThread().start();
        Log.d(TAG, "socket service onCreate");
        return super.onStartCommand(intent, flags, startId);
    }

    public boolean sendMsg(String msg) {
        if (null == mSocket || null == mSocket.get()) {
            return false;
        }
        Log.d(TAG, "send msg:" + msg);
        Socket soc = mSocket.get();
        try {
            if (!soc.isClosed() && !soc.isOutputShutdown()) {
                OutputStream os = soc.getOutputStream();
                String message = msg;
                os.write(message.getBytes());
                os.flush();
                sendTime = System.currentTimeMillis();//每次发送成数据,就改一下最后成功发送的时间,节省心跳间隔时间
            } else {
                return false;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    private void initSocket() throws IOException {//初始化Socket
        Log.d(TAG, "serverHost:serverPort:" + serverHost + ":" + serverPort);
        Socket so = new Socket(serverHost, serverPort);
        mSocket = new WeakReference<Socket>(so);
        mReadThread = new ReadThread(so);
        mReadThread.start();
    }


    private void releaseLastSocket(WeakReference<Socket> mSocket) {
        try {
            if (null != mSocket) {
                Socket sk = mSocket.get();
                if (!sk.isClosed()) {
                    sk.close();
                }
                sk = null;
                mSocket = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    class InitSocketThread extends Thread {
        @Override
        public void run() {
            super.run();
            try {
                initSocket();
            } catch (IOException e) {
                e.printStackTrace();
                Log.d(TAG, "init socket thread error,restart again after " + HEART_BEAT_RATE / 1000 + " seconds");
                try {
                    Thread.sleep(HEART_BEAT_RATE);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
                this.run();
            }
        }
    }

    private String verifyMsg = "";

    // Thread to read content from Socket
    class ReadThread extends Thread {
        private WeakReference<Socket> mWeakSocket;
        private boolean isStart = true;

        public ReadThread(Socket socket) {
            mWeakSocket = new WeakReference<Socket>(socket);
        }

        public void release() {
            isStart = false;
            releaseLastSocket(mWeakSocket);
        }

        @Override
        public void run() {
            super.run();
            Socket socket = mWeakSocket.get();
            if (null != socket) {
                try {
                    if (!sendRegister) {
                        Log.d(TAG, "send register mes");
                        SocketSendMsg ssm = new SocketSendMsg().contractRegisterMsg(testRoomSn);
                        String msg = gson.toJson(ssm) + END_SYMBOL;
                        sendMsg(msg);
                        Log.d(TAG, "" + msg);
                        sendRegister = true;
                    }
                    Log.d(TAG, "send register mes end");
                    InputStream is = socket.getInputStream();
                    byte[] buffer = new byte[1024 * 4];
                    int length = 0;
                    while (!socket.isClosed() && !socket.isInputShutdown()
                            && isStart && ((length = is.read(buffer)) != -1)) {
                        if (length > 0) {
                            String message = new String(Arrays.copyOf(buffer,
                                    length)).trim();
                            Log.d(TAG, "recv msg:" + message);
                            try {
                                if (message.endsWith(END_SYMBOL)) {
                                    message = message.replace(END_SYMBOL, "");
                                }
                                SocketResponse socketResponse = gson.fromJson(message, SocketResponse.class);
                                switch (socketResponse.getCode()) {
                                    case SUCCESS_MESSAGE:
                                        Log.d(TAG, "SUCCESS_MESSAGE");
                                        break;
                                    case VERIFY_SUCCESS:
                                        Log.d(TAG, "VERIFY_SUCCESS");
                                        mHandler.post(heartBeatRunnable);
                                        Log.d(TAG, "verify success start heart beat");
                                        break;
                                    case HEART_BEAT_SUCCESS:
                                        Log.d(TAG, "HEART_BEAT_SUCCESS");
                                        break;
                                    case HEART_BEAT_ERROR_SYMBOL:
                                    case ROOM_SN_CONNECTED:
                                        String msg1 = socketResponse.getCode() == HEART_BEAT_ERROR_SYMBOL ? "HEART_BEAT_ERROR_SYMBOL" : "ROOM_SN_CONNECTED";
                                        Log.d(TAG, msg1);
                                        mHandler.removeCallbacks(heartBeatRunnable);
                                        mReadThread.release();
                                        sendRegister = false;
                                        releaseLastSocket(mSocket);
                                        Log.d(TAG, msg1 + " before:" + +System.currentTimeMillis());
                                        try {
                                            Thread.sleep(10 * 1000);
                                        } catch (InterruptedException e) {
                                            e.printStackTrace();
                                        }
                                        Log.d(TAG, msg1 + "  after:" + System.currentTimeMillis());
                                        new InitSocketThread().start();
                                        break;
                                    case RETURN_VERIFY_CODE:
                                        Log.d(TAG, "RETURN_VERIFY_CODE");
                                        if (!TextUtils.isEmpty(socketResponse.getData().getVerify())) {
                                            verifyMsg = AuthCode.getDecodeStr(socketResponse.getData().getVerify());
                                            SocketSendMsg ssm = new SocketSendMsg().contractVerifyMsg(testRoomSn, verifyMsg);
                                            String msg = gson.toJson(ssm) + END_SYMBOL;
                                            sendMsg(msg);
                                        }
                                        break;
                                    case CONTAIN_MESSAGE:
                                        Log.d(TAG, "CONTAIN_MESSAGE");
                                        if (socketResponse.getData() != null) {
                                            if (socketResponse.getCmd() == OPEN_DOOR) {
                                                switch (socketResponse.getData().getUser()) {
                                                    //10用户,20管理员,默认值为0
                                                    case 10:
                                                        new SystemUtils().openFtLed(context.getApplicationContext());
                                                        if (TextUtils.isEmpty(((FangTangApplication) getApplication()).getCurrentPlayUrl())) {
                                                            LightOperationUtils.open();
                                                            LightOperationUtils.setLightValue(Utils.getInt(context, "brightness", 50));
                                                        }
                                                        sendMessage(QrCodeShowActivity.KILL_SELF, "finish the QR CODE activity when new user come in");
                                                        if (socketResponse.getData().getFirst() == 1) {
                                                            sendMessage(USER_OPEN_DOOR_AND_GET_MOVIE, "user first open the door");
                                                        } else {
                                                            sendMessage(USER_OPEN_DOOR, "user open the door");
                                                        }
                                                        break;
                                                    case 20:
                                                        if (TextUtils.isEmpty(((FangTangApplication) getApplication()).getCurrentPlayUrl())) {
                                                            Log.d("LightOperationUtils", "admin open light");
                                                            LightOperationUtils.open();
                                                            LightOperationUtils.setLightValue(Utils.getInt(context, "brightness", 50));
                                                        }
                                                        sendMessage(JUST_OPEN_DOOR, "administrator open the door");
                                                        break;
                                                    case 0:
                                                        sendMessage(JUST_OPEN_DOOR, "get zero none user or administrator open the door");
                                                        break;
                                                    default:
                                                        sendMessage(JUST_OPEN_DOOR, "none user or administrator open the door");
                                                        break;
                                                }
                                            } else if (socketResponse.getCmd() == CLEAN_OVER) {
                                                Log.d("LightOperationUtils", "admin clean over close light");
                                                LightOperationUtils.setLightValue(5);
                                                LightOperationUtils.close();
                                                new SystemUtils().closeFtLed(context.getApplicationContext());
                                                sendMessage(QrCodeShowActivity.KILL_SELF, "finish the QR CODE activity when clean over");
                                            }
                                        }
                                        break;
                                    default:
                                        Log.d(TAG, "default msg:" + socketResponse.toString());
                                }
                            } catch (JsonSyntaxException e) {
                                Log.d(TAG, message);
                                e.printStackTrace();
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void sendMessage(int type, String msg) {
        MessageEvent messageEvent = new MessageEvent();
        messageEvent.setEventId(type);
        messageEvent.setMessage(msg);
        EventBus.getDefault().post(messageEvent);
    }

    boolean sendRegister = false;

    @Override
    public void onDestroy() {
        Log.d(TAG, "socket service destroy");
        super.onDestroy();
    }
}