com.yangtsaosoftware.pebblemessenger.services.PebbleCenter.java Source code

Java tutorial

Introduction

Here is the source code for com.yangtsaosoftware.pebblemessenger.services.PebbleCenter.java

Source

/*
 * Pebble Messenger is used to display non-english message on Pebble.
 * Copyright (C) 2014  Yang Tsao
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

package com.yangtsaosoftware.pebblemessenger.services;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager;
import android.telephony.PhoneNumberUtils;
import android.telephony.SmsManager;
import android.telephony.TelephonyManager;
// import android.text.format.Time;
import android.view.KeyEvent;

import com.android.internal.telephony.ITelephony;
import com.getpebble.android.kit.PebbleKit;
import com.getpebble.android.kit.util.PebbleDictionary;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import com.yangtsaosoftware.pebblemessenger.Constants;
import com.yangtsaosoftware.pebblemessenger.R;
import com.yangtsaosoftware.pebblemessenger.activities.SetupFragment;
import com.yangtsaosoftware.pebblemessenger.db.MessageDbHandler;
import com.yangtsaosoftware.pebblemessenger.models.CharacterMatrix;
import com.yangtsaosoftware.pebblemessenger.models.PebbleCall;
import com.yangtsaosoftware.pebblemessenger.models.PebbleMessage;

public class PebbleCenter extends Service {
    public final static int PEBBLE_SEND_MESSAGE = 1;
    public final static int PEBBLE_SEND_CALL = 2;

    public final static int PEBBLE_SEND_MESSAGE_TABLE = 4;
    public final static int PEBBLE_SEND_CALL_TABLE = 5;

    public boolean isPebbleEnable = true;

    public Messenger mPebbleCenterHandler;
    private static final int PREPARE_MESSAGE = 1;
    private static final int PREPARE_CALL = 2;
    private static final int PREPARE_MESSAGE_TABLE = 3;
    private static final int PREPARE_CALL_TABLE = 4;
    private static final int PREPARE_TEST = 5;

    private static final int SEND_MESSAGE = 1;
    private static final int SEND_NEXT_PAGE = 2;
    private static final int SEND_CONTINUE = 3;
    private static final int SEND_CALL = 4;
    private static final int SEND_CALL_END = 5;
    private static final int SEND_CLOSE_APP = 6;
    private static final int SEND_CALL_HOOK = 7;
    private static final int SEND_OPEN_APP = 8;

    private static final int TRANS_ID_COMMON = 0;
    private static final int TRANS_ID_END = 1;
    private static final int TRANS_ID_EMPTY = 13;
    private static final int TRANS_ID_TEST = 99;

    //   private int fChars;  //line contain chars
    private int fLines; //page contain lines
    //   private int fLength; //package max length
    private byte char_scale;
    private Long timeOut;
    private boolean callEnable = true;
    private boolean whiteBackground = true;
    private String sms1;
    private String sms2;

    private Deque<PebbleDictionary> sendQueue;
    //    private Deque<PebbleMessage> waitQueue;
    //    private boolean pebbleBusy=false;
    //   private Time busyBegin;
    //   private boolean need_delay=true;
    //private final static long MAX_WAITING_MILLIS=30000;
    private final static int MAX_CHARS_PACKAGE_CONTAIN = 60;
    //   private int appStatue=0;
    //pebble request. Use transaction id to receive command, and extra data for the addition information.
    private static final int REQUEST_TRANSID_MESSAGE = 1;
    private static final int REQUEST_TRANSID_CALL = 2;
    private static final int REQUEST_TRANSID_MESSAGE_TABLE = 3;
    private static final int REQUEST_TRANSID_CALL_TABLE = 4;
    private static final int REQUEST_TRANSID_CLOSE_APP = 5;
    private static final int REQUEST_TRANSID_PICKUP_PHONE = 6;
    private static final int REQUEST_TRANSID_HANGOFF_PHONE = 7;
    private static final int REQUEST_TRANSID_HANGOFF_SMS1 = 8;
    private static final int REQUEST_TRANSID_HANGOFF_SMS2 = 9;
    private static final int REQUEST_TRANSID_NEXTPAGE = 10;
    private static final int REQUEST_TRANSID_READ_NOTIFY = 11;
    private static final int REQUEST_TRANSID_IM_FREE = 12;
    private static final int REQUEST_TRANSID_VERSION = 13;
    private static final int ID_EXTRA_DATA = 2;
    private static final int REQUEST_EXTRA_SPEAKER_ON = 1;
    private static final int REQUEST_EXTRA_SPEAKER_OFF = 2;
    //   private static final int REQUEST_EXTRA_DELAY_OFF=0;
    private static final int REQUEST_EXTRA_DELAY_ON = 1;
    private static final int ID_EXTRA_DATA2 = 3;

    //pebble command
    private static final int ID_COMMAND = 0;
    private static final byte REMOTE_EMPTY = 0;
    private static final byte REMOTE_EXCUTE_NEW_MESSAGE = 1;
    private static final byte REMOTE_EXCUTE_NEW_CALL = 2;
    private static final byte REMOTE_EXCUTE_CONTINUE_MESSAGE = 3;
    private static final byte REMOTE_EXCUTE_CONTINUE_CALL = 4;
    private static final byte REMOTE_DISPLAY_MESSAGE_TABLE = 5;
    private static final byte REMOTE_DISPLAY_CALL_TABLE = 6;
    private static final byte REMOTE_EXCUTE_CALL_END = 7;
    private static final byte REMOTE_DISPLAY_CONTINUE = 8;
    private static final byte REMOTE_EXCUTE_CALL_HOOK = 9;
    private static final byte REMOTE_EXCUTE_TEST = 10;
    //  private static final int ID_TOTAL_PAGES=1;
    private static final int ID_PAGE_INFO = 1;
    //  private static final int ID_TOTAL_PACKAGES=3;
    //  private static final int ID_PACKAGE_NUM=4;
    /*
    ID_PAGE_INFO contain a byte array with 4 elements:
    index 0: total pages
    index 1: current pages number
    index 2: total packages
    index 3: current package number
     */
    private static final int ID_ASCSTR = 5;
    private static final int ID_UNICHR_BYTES = 6;
    private static final int ID_UNICHR_INFO = 7;
    /*
    ID_UNICHAR_INFO contain a byte array with 3 elements:
    index 0: unichar width (1 for one byte char 2 for two byte char)
    index 1: unichar position X(row index);
    index 2: unichar position Y(colon index);
     */
    //   private static final int ID_UNICHR_POS=8;
    private static final int ID_CLOSE_DELAY_SEC = 9;
    private static final int ID_CHAR_SCALE = 10;
    private static final int ID_INFO_ID = 11;
    private static final int ID_PHONE_NUM = 12;
    private static final int ID_WHITE_BACKGROUND = 13;
    private static final int ID_EXTRA_POS_NUM = 100;

    private static final String TAG_NAME = "PebbleCenter";

    private Handler prepareThreadHandler;
    private Handler sendMsgThreadHandler;
    private boolean send_full_page = true;

    private boolean send_test_get_return = false;

    private Context _contex;
    private Messenger rMessageProcessingHandler = null;

    private static Lock sendLock = new ReentrantLock();

    private ServiceConnection connToMessageProcessing = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            rMessageProcessingHandler = new Messenger(iBinder);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            rMessageProcessingHandler = null;
        }
    };

    public PebbleCenter() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Handler pebbleCenterHandler = new PebbleCenterHandler();
        mPebbleCenterHandler = new Messenger(pebbleCenterHandler);
        Constants.log(TAG_NAME, "Create PebbleCenter Messenger.");
        loadPref();
        _contex = this;
        //   busyBegin=new Time();
        //        waitQueue=new ArrayDeque<PebbleMessage>();
        sendQueue = new ArrayDeque<PebbleDictionary>();
        bindService(new Intent(this, MessageProcessingService.class), connToMessageProcessing,
                Context.BIND_AUTO_CREATE);
        Thread prepareThread = new PrepareThread();
        prepareThread.start();
        Thread sendMsgThread = new SendMsgThread();
        sendMsgThread.start();
        isPebbleEnable = PebbleKit.isWatchConnected(_contex);
        PebbleKit.registerReceivedDataHandler(_contex, new PebbleKit.PebbleDataReceiver(Constants.PEBBLE_UUID) {
            @Override
            public void receiveData(Context context, int transactionId, PebbleDictionary data) {
                PebbleKit.sendAckToPebble(_contex, transactionId);
                //          appStatue++;
                Constants.log(TAG_NAME, "Received data form pebble");
                switch (data.getUnsignedIntegerAsLong(ID_COMMAND).intValue()) {
                case REQUEST_TRANSID_CALL_TABLE: {
                    Constants.log(TAG_NAME, "Request call table.");
                    clean_SendQue();
                    Message msg = Message.obtain();
                    msg.what = MessageProcessingService.MSG_GET_CALL_TABLE;
                    try {
                        rMessageProcessingHandler.send(msg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
                    break;
                case REQUEST_TRANSID_MESSAGE_TABLE: {
                    Constants.log(TAG_NAME, "Request message table.");
                    clean_SendQue();
                    Message msg = Message.obtain();
                    msg.what = MessageProcessingService.MSG_GET_MESSAGE_TABLE;
                    try {
                        rMessageProcessingHandler.send(msg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
                    break;
                case REQUEST_TRANSID_CALL: {
                    clean_SendQue();
                    Message msg = Message.obtain();
                    msg.what = MessageProcessingService.MSG_GET_CALL;
                    Bundle b = new Bundle();
                    b.putString(MessageDbHandler.COL_CALL_ID, data.getString(ID_EXTRA_DATA));
                    Constants.log(TAG_NAME, "Request call id:" + data.getString(ID_EXTRA_DATA));

                    msg.setData(b);
                    try {
                        rMessageProcessingHandler.send(msg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }

                }
                    break;
                case REQUEST_TRANSID_MESSAGE:
                    clean_SendQue();
                    Message msg = Message.obtain();
                    msg.what = MessageProcessingService.MSG_GET_MESSAGE;
                    Bundle b = new Bundle();
                    b.putString(MessageDbHandler.COL_MESSAGE_ID, data.getString(ID_EXTRA_DATA));
                    Constants.log(TAG_NAME, "Request message id:" + data.getString(ID_EXTRA_DATA));

                    msg.setData(b);
                    try {
                        rMessageProcessingHandler.send(msg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
                case REQUEST_TRANSID_PICKUP_PHONE:
                    TelephonyManager telMag = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
                    Constants.log("Receivephone", "Receive phone:" + data.getString(ID_EXTRA_DATA2));
                    if (telMag.getCallState() == TelephonyManager.CALL_STATE_RINGING) {
                        switch (data.getUnsignedIntegerAsLong(ID_EXTRA_DATA).intValue()) {
                        case REQUEST_EXTRA_SPEAKER_ON:
                            answerCall(true);
                            break;
                        case REQUEST_EXTRA_SPEAKER_OFF:
                            answerCall(false);
                            break;
                        }
                    } else {
                        switch (data.getUnsignedIntegerAsLong(ID_EXTRA_DATA).intValue()) {
                        case REQUEST_EXTRA_SPEAKER_ON:
                            dialNumber(data.getString(ID_EXTRA_DATA2), true);
                            break;
                        case REQUEST_EXTRA_SPEAKER_OFF:
                            dialNumber(data.getString(ID_EXTRA_DATA2), false);
                            break;
                        }

                    }
                    //                pebbleBusy = false;
                    break;
                case REQUEST_TRANSID_HANGOFF_PHONE:
                    endCall();
                    //                pebbleBusy=false;

                    break;
                case REQUEST_TRANSID_HANGOFF_SMS1:
                    Constants.log(TAG_NAME, "Request hangoff and send sms1");

                    endCall();
                    doSendSMSTo(data.getString(ID_EXTRA_DATA), sms1);
                    //               pebbleBusy=false;

                    break;
                case REQUEST_TRANSID_HANGOFF_SMS2:
                    Constants.log(TAG_NAME, "Request hangoff and send sms2");

                    endCall();
                    doSendSMSTo(data.getString(ID_EXTRA_DATA), sms2);
                    //              pebbleBusy=false;

                    break;
                case REQUEST_TRANSID_CLOSE_APP:
                    Constants.log(TAG_NAME, "Request close app command.");
                    sendMsgThreadHandler.sendEmptyMessage(SEND_CLOSE_APP);
                    //               need_delay=true;

                    break;
                case REQUEST_TRANSID_NEXTPAGE:
                    Constants.log(TAG_NAME, "Request send next page.");

                    sendMsgThreadHandler.sendEmptyMessage(SEND_NEXT_PAGE);
                    break;
                case REQUEST_TRANSID_READ_NOTIFY: {
                    Constants.log(TAG_NAME, "Request  read msg");
                    Message read_msg = Message.obtain();
                    read_msg.what = MessageProcessingService.MSG_READ;
                    Bundle bd = new Bundle();
                    bd.putString(MessageDbHandler.COL_MESSAGE_ID,
                            data.getUnsignedIntegerAsLong(ID_EXTRA_DATA).toString());
                    read_msg.setData(bd);
                    try {
                        rMessageProcessingHandler.send(read_msg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
                    break;
                case REQUEST_TRANSID_IM_FREE:
                    Constants.log(TAG_NAME, "Request pebble app is free to receive data.");

                    //               need_delay = data.getUnsignedInteger(ID_EXTRA_DATA).intValue() == REQUEST_EXTRA_DELAY_ON ;
                    //               clean_SendQue();
                    break;
                case REQUEST_TRANSID_VERSION: {
                    send_test_get_return = true;
                    String result = data.getString(ID_EXTRA_DATA);
                    Constants.log("PmpVersion", result);
                    StringTokenizer tokens = new StringTokenizer(result, ".");

                    Intent inner_intent = new Intent(SetupFragment.class.getName());
                    inner_intent.putExtra(Constants.BROADCAST_VERSION,
                            new byte[] { Byte.parseByte(tokens.nextToken()), Byte.parseByte(tokens.nextToken()),
                                    Byte.parseByte(tokens.nextToken()) });
                    LocalBroadcastManager.getInstance(context).sendBroadcast(inner_intent);
                    sendMsgThreadHandler.sendEmptyMessage(SEND_CLOSE_APP);
                    break;
                }
                }
            }
        });

        PebbleKit.registerReceivedAckHandler(_contex, new PebbleKit.PebbleAckReceiver(Constants.PEBBLE_UUID) {
            @Override
            public void receiveAck(Context context, int transactionId) {
                Constants.log(TAG_NAME, "Get a receiveAck:" + String.valueOf(transactionId));
                switch (transactionId) {
                case TRANS_ID_COMMON:
                    Constants.log(TAG_NAME, "Send continue...");
                    //                  pebbleBusy=true;
                    sendMsgThreadHandler.sendEmptyMessage(SEND_CONTINUE);
                    break;
                case TRANS_ID_END:
                    send_full_page = true;
                    break;
                case TRANS_ID_EMPTY:
                    //                 pebbleBusy=true;
                    sendMsgThreadHandler.sendEmptyMessage(SEND_CONTINUE);
                    break;
                case TRANS_ID_TEST: {
                    break;
                }
                }
            }
        });

        PebbleKit.registerReceivedNackHandler(_contex, new PebbleKit.PebbleNackReceiver(Constants.PEBBLE_UUID) {
            @Override
            public void receiveNack(Context context, int transactionId) {
                Constants.log(TAG_NAME, "Get a receivedNack:" + String.valueOf(transactionId));
                if (PebbleKit.isWatchConnected(_contex)) {
                    switch (transactionId) {
                    case TRANS_ID_COMMON:
                        sendMsgThreadHandler.sendEmptyMessage(SEND_CONTINUE);
                        break;
                    case TRANS_ID_END:
                        send_full_page = true;
                        break;
                    case TRANS_ID_EMPTY:
                        //                   appStatue=0;
                        sendMsgThreadHandler.sendEmptyMessage(SEND_OPEN_APP);
                        break;
                    case TRANS_ID_TEST: {
                        Intent inner_intent = new Intent(SetupFragment.class.getName());
                        inner_intent.putExtra(Constants.BROADCAST_VERSION, new byte[] { 0, 0, 0 });
                        LocalBroadcastManager.getInstance(context).sendBroadcast(inner_intent);
                    }
                    }
                } else {
                    sendMsgThreadHandler.sendEmptyMessage(SEND_CLOSE_APP);
                }

            }
        });

        PebbleKit.registerPebbleConnectedReceiver(_contex, new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                isPebbleEnable = true;
            }
        });

        PebbleKit.registerPebbleDisconnectedReceiver(_contex, new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                isPebbleEnable = false;
                sendMsgThreadHandler.sendEmptyMessage(SEND_CLOSE_APP);
            }
        });

        BroadcastReceiver br = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                int command = intent.getIntExtra(Constants.BROADCAST_COMMAND, Constants.BROADCAST_PREFER_CHANGED);

                switch (command) {
                case Constants.BROADCAST_PREFER_CHANGED:
                    loadPref();
                    break;
                case Constants.BROADCAST_CALL_IDLE:
                    if (callEnable) {
                        sendMsgThreadHandler.sendEmptyMessage(SEND_CALL_END);
                    }
                    break;
                case Constants.BROADCAST_CALL_HOOK:
                    if (callEnable) {
                        sendMsgThreadHandler.sendEmptyMessage(SEND_CALL_HOOK);
                    }
                    break;
                case Constants.BROADCAST_PEBBLE_TEST:
                    if (isPebbleEnable) {
                        prepareThreadHandler.sendEmptyMessage(PREPARE_TEST);
                    }
                    break;
                }
            }
        };
        IntentFilter intentFilter = new IntentFilter(PebbleCenter.class.getName());
        LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(br, intentFilter);
    }

    @Override
    public void onDestroy() {
        unbindService(connToMessageProcessing);
        super.onDestroy();
    }

    class PebbleCenterHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            Constants.log(TAG_NAME,
                    "Get a msg. Pebble is " + String.valueOf(isPebbleEnable) + " what:" + String.valueOf(msg.what));
            if (!isPebbleEnable)
                return;
            switch (msg.what) {
            case PEBBLE_SEND_MESSAGE: {
                //                  waitQueue.add((PebbleMessage) msg.getData().getSerializable(MessageProcessingService.PROCEED_MSG));
                Message pebbleMsg = prepareThreadHandler.obtainMessage(PREPARE_MESSAGE);
                pebbleMsg.setData(msg.getData());
                prepareThreadHandler.sendMessage(pebbleMsg);
            }
                break;
            case PEBBLE_SEND_CALL: {
                if (callEnable == false)
                    return;
                Message callMsg = prepareThreadHandler.obtainMessage(PREPARE_CALL);
                callMsg.setData(msg.getData());
                prepareThreadHandler.sendMessageAtFrontOfQueue(callMsg);
            }
                break;
            case PEBBLE_SEND_MESSAGE_TABLE: {
                Message ptMsg = prepareThreadHandler.obtainMessage(PREPARE_MESSAGE_TABLE);
                ptMsg.setData(msg.getData());
                prepareThreadHandler.sendMessage(ptMsg);
            }
                break;
            case PEBBLE_SEND_CALL_TABLE: {
                Message ctMsg = prepareThreadHandler.obtainMessage(PREPARE_CALL_TABLE);
                ctMsg.setData(msg.getData());
                prepareThreadHandler.sendMessage(ctMsg);
            }
                break;

            default:
                super.handleMessage(msg);
            }
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        //throw new UnsupportedOperationException("Not yet implemented");
        return mPebbleCenterHandler.getBinder();
    }

    class PrepareThread extends Thread {
        @Override
        public void run() {
            Looper.prepare();
            prepareThreadHandler = new PrepareHandler(Looper.myLooper());
            Looper.loop();
        }
    }

    class PrepareHandler extends Handler {
        public PrepareHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            //super.handleMessage(msg);
            if (!isPebbleEnable) {
                return;
            }

            switch (msg.what) {
            case PREPARE_MESSAGE: {

                if (!send_full_page) {
                    Constants.log("PREPARE", "pebble is busy.");
                    Message pmMsg = this.obtainMessage(PREPARE_MESSAGE);
                    pmMsg.setData(msg.getData());
                    this.sendMessageDelayed(pmMsg, 3000);
                    return;
                }
                clean_SendQue();
                List<PebbleMessage> pages = splitPages(
                        (PebbleMessage) msg.getData().getSerializable(MessageProcessingService.PROCEED_MSG));
                split_message_to_packages_add_to_sendQue(pages);
                sendMsgThreadHandler.sendEmptyMessage(SEND_MESSAGE);
            }
                break;
            case PREPARE_CALL:
                if (!send_full_page) {
                    Message pcMsg = this.obtainMessage(PREPARE_CALL);
                    pcMsg.setData(msg.getData());
                    this.sendMessageDelayed(pcMsg, 1000);
                    return;
                }
                PebbleCall pbCall = (PebbleCall) msg.getData()
                        .getSerializable(MessageProcessingService.PROCEED_CALL);
                split_call_to_package_add_to_sendQue(pbCall);
                sendMsgThreadHandler.sendEmptyMessage(SEND_CALL);
                break;
            case PREPARE_MESSAGE_TABLE:
                clean_SendQue();
                split_string_to_package_add_to_sendQue(msg.getData().getString(MessageDbHandler.TABLE_MESSAGE_NAME),
                        REMOTE_DISPLAY_MESSAGE_TABLE);
                sendMsgThreadHandler.sendEmptyMessage(SEND_CONTINUE);
                break;
            case PREPARE_CALL_TABLE:
                clean_SendQue();
                split_string_to_package_add_to_sendQue(msg.getData().getString(MessageDbHandler.TABLE_CALL_NAME),
                        REMOTE_DISPLAY_CALL_TABLE);
                sendMsgThreadHandler.sendEmptyMessage(SEND_CONTINUE);
                break;
            case PREPARE_TEST: {
                if (!send_full_page) {
                    this.sendEmptyMessageDelayed(PREPARE_TEST, 3000);
                    return;
                }
                clean_SendQue();
                PebbleDictionary testCmd = new PebbleDictionary();
                testCmd.addUint8(ID_COMMAND, REMOTE_EXCUTE_TEST);
                sendQueue.add(testCmd);
                sendMsgThreadHandler.sendEmptyMessage(SEND_MESSAGE);
                send_test_get_return = false;
                this.postDelayed(check_test_return, 3000);
            }
                break;
            }

        }

        Runnable check_test_return = new Runnable() {
            @Override
            public void run() {
                //         appStatue=0;
                if (!send_test_get_return) {
                    Intent inner_intent = new Intent(SetupFragment.class.getName());
                    inner_intent.putExtra(Constants.BROADCAST_VERSION, new byte[] { 0, 0, 0 });
                    LocalBroadcastManager.getInstance(_contex).sendBroadcast(inner_intent);
                }
            }
        };

    }

    private void split_string_to_package_add_to_sendQue(String strMsg, byte commandID) {
        sendLock.lock();
        PebbleDictionary dataMsg;

        byte totalPackges = (byte) bigInt((float) strMsg.length() / (float) MAX_CHARS_PACKAGE_CONTAIN);
        Constants.log(TAG_NAME, "Send Table:\n" + strMsg + "\ntotalpackages:" + String.valueOf(totalPackges)
                + " strlen:" + String.valueOf(strMsg.length()));
        for (int pg = 1; pg <= totalPackges; pg++) {
            dataMsg = new PebbleDictionary();
            if (pg == 1) {
                dataMsg.addUint8(ID_COMMAND, commandID);
            } else {
                dataMsg.addUint8(ID_COMMAND, REMOTE_DISPLAY_CONTINUE);
            }
            byte[] pageInfo = new byte[4];
            pageInfo[0] = 1;
            pageInfo[1] = 1;
            pageInfo[2] = totalPackges;
            pageInfo[3] = (byte) pg;
            dataMsg.addBytes(ID_PAGE_INFO, pageInfo);
            dataMsg.addString(ID_ASCSTR,
                    strMsg.substring((pg - 1) * MAX_CHARS_PACKAGE_CONTAIN,
                            (pg * MAX_CHARS_PACKAGE_CONTAIN > strMsg.length() ? strMsg.length()
                                    : pg * MAX_CHARS_PACKAGE_CONTAIN)));

            sendQueue.add(dataMsg);

        }
        sendLock.unlock();
    }

    private List<PebbleMessage> splitPages(PebbleMessage tmpPM) {
        List<PebbleMessage> pmPages = new ArrayList<PebbleMessage>();
        String[] splitString = tmpPM.getAscMsg().split("\n");
        Constants.log(TAG_NAME, tmpPM.getAscMsg());
        for (String str : splitString) {
            Constants.log(TAG_NAME, "splitPages, deal:" + str);
        }
        int pageCount = bigInt((float) splitString.length / (float) fLines);
        for (int page = 1; page <= pageCount; page++) {
            PebbleMessage itemPm = new PebbleMessage();
            itemPm.set_id(tmpPM.get_id());
            StringBuilder tmpSB = new StringBuilder();
            for (int line = (page - 1) * fLines; line < (page * fLines > splitString.length ? splitString.length
                    : page * fLines); line++) {
                tmpSB.append(splitString[line]);
                tmpSB.append('\n');
            }
            itemPm.setAscMsg(tmpSB.toString());
            Deque<CharacterMatrix> itemDqCM = new ArrayDeque<CharacterMatrix>();
            while (!tmpPM.getCharacterQueue().isEmpty()) {
                CharacterMatrix tmpCM = tmpPM.getCharacterQueue().pollFirst();
                if (tmpCM.getPos()[0] >= (page - 1) * fLines && tmpCM.getPos()[0] <= page * fLines) {
                    itemDqCM.add(tmpCM);
                } else {
                    tmpPM.getCharacterQueue().addFirst(tmpCM);
                    break;
                }
            }
            itemPm.setCharacterQueue(itemDqCM);
            pmPages.add(page - 1, itemPm);
        }
        return pmPages;
    }

    private void split_message_to_packages_add_to_sendQue(List<PebbleMessage> listPM) {
        sendLock.lock();
        PebbleDictionary dataMsg = new PebbleDictionary();
        dataMsg.addUint8(ID_COMMAND, REMOTE_EXCUTE_NEW_MESSAGE);

        dataMsg.addUint8(ID_CLOSE_DELAY_SEC, (byte) (timeOut / 1000));
        dataMsg.addUint8(ID_CHAR_SCALE, char_scale);
        Constants.log(TAG_NAME, "add char_scale:" + String.valueOf(char_scale));
        dataMsg.addUint32(ID_INFO_ID, listPM.get(0).get_id().intValue());
        byte[] packInfo = new byte[] { 1, 1, 2, 1 };
        dataMsg.addBytes(ID_PAGE_INFO, packInfo);
        dataMsg.addUint8(ID_WHITE_BACKGROUND, whiteBackground ? (byte) 1 : (byte) 0);
        sendQueue.add(dataMsg);
        HashMap unicodeMap = new HashMap();

        Constants.log(TAG_NAME, "listpm.size:" + String.valueOf(listPM.size()));
        for (int page = 1; page <= listPM.size(); page++) {
            PebbleMessage dealPM = listPM.get(page - 1);
            int strPackages = bigInt((float) dealPM.getAscMsg().length() / (float) MAX_CHARS_PACKAGE_CONTAIN);
            byte totalPackages = (byte) (dealPM.getCharacterQueue().size() + strPackages);
            Constants.log(TAG_NAME, "total Packages:" + String.valueOf(totalPackages));
            for (int pg = 1; pg <= strPackages; pg++) {
                dataMsg = new PebbleDictionary();
                dataMsg.addUint8(ID_COMMAND, REMOTE_EXCUTE_CONTINUE_MESSAGE);
                byte[] strPackInfo = new byte[] { (byte) listPM.size(), (byte) page, 0, 0 };
                dataMsg.addBytes(ID_PAGE_INFO, strPackInfo);
                //       dataMsg.addUint8(ID_TOTAL_PAGES,(byte)listPM.size());
                //       dataMsg.addUint8(ID_PAGE_NUM,(byte)page);
                //       dataMsg.addUint8(ID_TOTAL_PACKAGES,totalPackages);
                //       dataMsg.addUint8(ID_PACKAGE_NUM,(byte) pg);
                dataMsg.addString(ID_ASCSTR,
                        dealPM.getAscMsg().substring((pg - 1) * MAX_CHARS_PACKAGE_CONTAIN,
                                (pg * MAX_CHARS_PACKAGE_CONTAIN > dealPM.getAscMsg().length()
                                        ? (dealPM.getAscMsg().length())
                                        : (pg * MAX_CHARS_PACKAGE_CONTAIN))));
                Constants.log(TAG_NAME, "Add Queue a strmsg:<" + dataMsg.getString(ID_ASCSTR) + ">");
                unicodeMap.put(pg, dataMsg);
            }
            for (int pg = strPackages + 1; pg <= totalPackages; pg++) {
                CharacterMatrix cm = dealPM.getCharacterQueue().pollFirst();
                PebbleDictionary duoPD = (PebbleDictionary) unicodeMap.get(cm.getCode());
                if (duoPD == null) {
                    dataMsg = new PebbleDictionary();
                    dataMsg.addUint8(ID_COMMAND, REMOTE_EXCUTE_CONTINUE_MESSAGE);
                    byte[] uniPackInfo = new byte[] { (byte) listPM.size(), (byte) page, 0, 0 };
                    dataMsg.addBytes(ID_PAGE_INFO, uniPackInfo);
                    // dataMsg.addUint8(ID_TOTAL_PAGES,(byte)listPM.size());
                    // dataMsg.addUint8(ID_PAGE_NUM,(byte)page);
                    //        dataMsg.addUint8(ID_TOTAL_PACKAGES,totalPackages);
                    //dataMsg.addUint8(ID_PACKAGE_NUM,(byte) pg);
                    Constants.log(TAG_NAME,
                            "There are " + String.valueOf(dealPM.getCharacterQueue().size()) + "unicode in queue");
                    int size = cm.getByteList().size();
                    byte[] b2 = new byte[size];
                    cm.getbyteArray(b2, size);
                    byte[] uniInfo = new byte[] { (byte) cm.getWidthBytes(), cm.getPos()[0], cm.getPos()[1] };
                    dataMsg.addBytes(ID_UNICHR_INFO, uniInfo);
                    //dataMsg.addUint8(ID_UNICHR_WIDTH,(byte) cm.getWidthBytes());
                    //dataMsg.addBytes(ID_UNICHR_POS,cm.getPos());
                    Constants.log(TAG_NAME,
                            "row:" + String.valueOf(cm.getPos()[0]) + " col:" + String.valueOf(cm.getPos()[1]));
                    dataMsg.addBytes(ID_UNICHR_BYTES, b2);
                    Constants.log(TAG_NAME, "b2 length:" + String.valueOf(b2.length));
                    //        Constants.log(TAG_NAME,"Add Queue a unimsg:" + dataMsg.getUnsignedInteger(ID_PACKAGE_NUM).toString());
                    unicodeMap.put(cm.getCode(), dataMsg);
                } else {
                    if (duoPD.contains(ID_EXTRA_POS_NUM)) {
                        byte[] soubyte = duoPD.getBytes(ID_EXTRA_POS_NUM);
                        byte num = soubyte[0];
                        byte[] tarbyte = new byte[num + 2];
                        tarbyte[0] = (byte) (num + 1);
                        for (int i = 1; i <= num; i++) {
                            tarbyte[i] = soubyte[i];
                        }
                        tarbyte[num + 1] |= (cm.getPos()[1] - 1) << 4;
                        tarbyte[num + 1] |= (cm.getPos()[0] - 1);
                        duoPD.addBytes(ID_EXTRA_POS_NUM, tarbyte);

                    } else {
                        byte[] tmpbyte = new byte[2];
                        tmpbyte[0] = 1;
                        tmpbyte[1] |= (cm.getPos()[1] - 1) << 4;
                        tmpbyte[1] |= (cm.getPos()[0] - 1);
                        duoPD.addBytes(ID_EXTRA_POS_NUM, tmpbyte);
                    }
                }

            }

            totalPackages = (byte) unicodeMap.size();
            Iterator it = unicodeMap.keySet().iterator();
            int i = 0;
            while (it.hasNext()) {
                PebbleDictionary tmpPD = (PebbleDictionary) unicodeMap.get(it.next());
                byte[] tmpPackInfo = tmpPD.getBytes(ID_PAGE_INFO);
                tmpPackInfo[2] = totalPackages;
                tmpPackInfo[3] = (byte) ++i;
                tmpPD.addBytes(ID_PAGE_INFO, tmpPackInfo);
                //tmpPD.addUint8(ID_TOTAL_PACKAGES, totalPackages);
                //tmpPD.addUint8(ID_PACKAGE_NUM,(byte)++i);
                sendQueue.add(tmpPD);
            }
            unicodeMap.clear();
        }
        sendLock.unlock();
    }

    private void split_call_to_package_add_to_sendQue(PebbleCall pbCall) {
        sendLock.lock();
        byte totalPackages = (byte) (pbCall.getCharacterQueue().size() + 1);
        PebbleDictionary dataMsg;
        for (int pg = totalPackages; pg > 1; pg--) {
            dataMsg = new PebbleDictionary();
            dataMsg.addUint8(ID_COMMAND, REMOTE_EXCUTE_CONTINUE_CALL);
            byte[] packInfo = new byte[] { 1, 1, totalPackages, (byte) pg };
            dataMsg.addBytes(ID_PAGE_INFO, packInfo);
            //   dataMsg.addUint8(ID_TOTAL_PACKAGES,totalPackages);
            //   dataMsg.addUint8(ID_PACKAGE_NUM,(byte) pg);
            CharacterMatrix cm = pbCall.getCharacterQueue().pollLast();
            int size = cm.getByteList().size();
            byte[] b2 = new byte[size];
            cm.getbyteArray(b2, size);
            dataMsg.addBytes(ID_UNICHR_BYTES, b2);
            byte[] uniInfo = new byte[] { (byte) cm.getWidthBytes(), cm.getPos()[0], cm.getPos()[1] };
            dataMsg.addBytes(ID_UNICHR_INFO, uniInfo);
            //    dataMsg.addUint8(ID_UNICHR_WIDTH,(byte) cm.getWidthBytes());
            //    dataMsg.addBytes(ID_UNICHR_POS,cm.getPos());
            sendQueue.addFirst(dataMsg);
        }
        dataMsg = new PebbleDictionary();
        dataMsg.addUint8(ID_COMMAND, REMOTE_EXCUTE_NEW_CALL);
        byte[] packInfo = new byte[] { 1, 1, totalPackages, 1 };
        dataMsg.addBytes(ID_PAGE_INFO, packInfo);
        //dataMsg.addUint8(ID_TOTAL_PACKAGES,totalPackages);
        //dataMsg.addUint8(ID_PACKAGE_NUM, (byte) 1);
        dataMsg.addString(ID_ASCSTR, pbCall.getAscMsg());
        dataMsg.addString(ID_PHONE_NUM, pbCall.getPhoneNum());
        dataMsg.addUint32(ID_INFO_ID, pbCall.get_id().intValue());
        dataMsg.addUint8(ID_WHITE_BACKGROUND, whiteBackground ? (byte) 1 : (byte) 0);
        sendQueue.addFirst(dataMsg);
        sendLock.unlock();
    }

    private int bigInt(float d) {
        Constants.log(TAG_NAME, "get big int:" + String.valueOf(d));
        if ((d - ((int) d)) > 0.01) {
            return (int) d + 1;
        } else {
            return (int) d;
        }
    }

    private void clean_SendQue() {

        sendQueue.clear();
        send_full_page = true;
        //pebbleBusy=false;
    }

    class SendMsgThread extends Thread {
        @Override
        public void run() {
            Looper.prepare();
            sendMsgThreadHandler = new SendMsgHandler(Looper.myLooper());
            Looper.loop();
        }
    }

    class SendMsgHandler extends Handler {
        public SendMsgHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            Constants.log(TAG_NAME, "get send command: what:" + String.valueOf(msg.what));
            if (!isPebbleEnable) {
                clean_SendQue();
                Constants.log(TAG_NAME, "Pebble is disable, clean!");
                return;
            }
            switch (msg.what) {
            case SEND_MESSAGE:
                this.post(sendEmpty);
                break;
            case SEND_CONTINUE: {
                //               if(appStatue==0) clean_SendQue();
                if (sendQueue.isEmpty()) {
                    Constants.log(TAG_NAME, "sendQueue is empty! Can not send");
                    return;
                }
                this.post(sendToPebble);
            }
                break;
            case SEND_NEXT_PAGE: {
                //             if(appStatue==0) clean_SendQue();
                if (sendQueue.isEmpty()) {
                    Constants.log(TAG_NAME, "sendQueue is empty! Can not send");
                    return;
                }
                this.post(sendToPebble);

            }
                break;
            case SEND_CALL:
                this.post(sendEmpty);
                break;
            case SEND_CALL_END: {
                //              if(appStatue==0) return;
                sendLock.lock();
                PebbleDictionary callEnd = new PebbleDictionary();
                byte[] packInfo = new byte[] { 1, 1, 1, 1 };
                callEnd.addBytes(ID_PAGE_INFO, packInfo);
                // callEnd.addUint8(ID_TOTAL_PACKAGES,(byte)1);
                // callEnd.addUint8(ID_PACKAGE_NUM,(byte)1);
                callEnd.addUint8(ID_COMMAND, REMOTE_EXCUTE_CALL_END);
                sendQueue.addFirst(callEnd);
                this.postAtFrontOfQueue(sendToPebble);
                sendLock.unlock();
            }
                break;
            case SEND_CLOSE_APP:
                this.postAtFrontOfQueue(closeApp);
                break;
            case SEND_CALL_HOOK:
                //              if(appStatue==0) return;
                sendLock.lock();
                PebbleDictionary callHook = new PebbleDictionary();
                byte[] packInfo = new byte[] { 1, 1, 1, 1 };
                callHook.addBytes(ID_PAGE_INFO, packInfo);
                //callHook.addUint8(ID_TOTAL_PACKAGES,(byte)1);
                //callHook.addUint8(ID_PACKAGE_NUM,(byte)1);
                callHook.addUint8(ID_COMMAND, REMOTE_EXCUTE_CALL_HOOK);
                sendQueue.addFirst(callHook);
                this.postAtFrontOfQueue(sendToPebble);
                sendLock.unlock();
                break;
            case SEND_OPEN_APP:
                wait_for_open_pebble_app();
                this.post(sendToPebble);
                break;

            }

        }

        void wait_for_open_pebble_app() {

            PebbleKit.startAppOnPebble(_contex, Constants.PEBBLE_UUID);
            try {
                Thread.sleep(1500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }

    Runnable sendToPebble = new Runnable() {
        @Override
        public void run() {
            Constants.log(TAG_NAME, "Data send to pebble, sendQueue length:" + String.valueOf(sendQueue.size()));
            if (sendQueue.size() == 0) {
                return;
            }
            PebbleDictionary tmpPD = sendQueue.poll();
            if (tmpPD.getUnsignedIntegerAsLong(ID_COMMAND) == REMOTE_EXCUTE_TEST) {
                PebbleKit.sendDataToPebbleWithTransactionId(_contex, Constants.PEBBLE_UUID, tmpPD, TRANS_ID_TEST);
                return;
            }
            byte[] tmpPackInfo = tmpPD.getBytes(ID_PAGE_INFO);
            if (tmpPackInfo[3] == tmpPackInfo[2]) {
                PebbleKit.sendDataToPebbleWithTransactionId(_contex, Constants.PEBBLE_UUID, tmpPD, TRANS_ID_END);

                Constants.log(TAG_NAME, "Send last package.sendQueue length:" + String.valueOf(sendQueue.size()));
                /*             if(tmpPD.getUnsignedInteger(ID_COMMAND).byteValue()==REMOTE_EXCUTE_CONTINUE_MESSAGE ){
                busyBegin.setToNow();
                             }*/
            } else {
                send_full_page = false;
                PebbleKit.sendDataToPebbleWithTransactionId(_contex, Constants.PEBBLE_UUID, tmpPD, TRANS_ID_COMMON);
                Constants.log(TAG_NAME,
                        "Send common package. sendQueue length:" + String.valueOf(sendQueue.size()));

            }

        }
    };

    Runnable closeApp = new Runnable() {
        @Override
        public void run() {
            //         appStatue=0;
            PebbleKit.closeAppOnPebble(_contex, Constants.PEBBLE_UUID);
            clean_SendQue();
        }
    };

    Runnable sendEmpty = new Runnable() {
        @Override
        public void run() {
            PebbleDictionary empPd = new PebbleDictionary();
            empPd.addUint8(ID_COMMAND, REMOTE_EMPTY);
            PebbleKit.sendDataToPebbleWithTransactionId(_contex, Constants.PEBBLE_UUID, empPd, TRANS_ID_EMPTY);
        }
    };

    private void loadPref() {
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        //     fLength=Constants.MAX_PACKAGE_LENGTH;
        timeOut = Long.parseLong(sharedPref.getString(Constants.PREFERENCE_MIN_NOTIFICATION_WAIT, "10000"));
        callEnable = sharedPref.getBoolean(Constants.PREFERENCE_CALL_ENABLE, true);
        //      Constants.log("callstatue", "callEnable is " + String.valueOf(callEnable));
        char_scale = (byte) Integer.parseInt(sharedPref.getString(Constants.PREFERENCE_MESSAGE_SCALE,
                String.valueOf(Constants.MESSAGE_SCALE_SMALL)));
        whiteBackground = !sharedPref.getBoolean(Constants.PREFERENCE_BLACK_BACKGROUND, false);
        switch ((int) char_scale) {
        case Constants.MESSAGE_SCALE_SMALL:
            //             fChars=Constants.SMALL_LINE_CONTAIN_CHARS;
            fLines = Constants.SMALL_PAGE_CONTAIN_LINES;
            break;
        case Constants.MESSAGE_SCALE_MID:
            //             fChars=Constants.MID_LINE_CONTAIN_CHARS;
            fLines = Constants.MID_PAGE_CONTAIN_LINES;
            break;
        case Constants.MESSAGE_SCALE_LARGE:
            //              fChars=Constants.LARGE_LINE_CONTAIN_CHARS;
            fLines = Constants.LARGE_PAGE_CONTAIN_LINES;
            break;
        }
        if (callEnable) {
            sms1 = sharedPref.getString(Constants.PREFERENCE_CALL_SMS_SHORT,
                    getString(R.string.pref_call_sms_short_default));
            sms2 = sharedPref.getString(Constants.PREFERENCE_CALL_SMS_LONG,
                    getString(R.string.pref_call_sms_long_default));
        }
    }

    private void endCall() {
        TelephonyManager telMag = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        Class<TelephonyManager> c = TelephonyManager.class;
        Method mthEndCall;
        try {
            mthEndCall = c.getDeclaredMethod("getITelephony", (Class[]) null);
            mthEndCall.setAccessible(true);
            ITelephony iTel = (ITelephony) mthEndCall.invoke(telMag, (Object[]) null);
            iTel.endCall();

        } catch (Exception e) {
            e.printStackTrace();
        }

        /*Context context = getApplicationContext();
        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        Constants.log("speakerset", String.format("AudioManager before mode:%d speaker mod:%s", audioManager.getMode(), String.valueOf(audioManager.isSpeakerphoneOn())));
        Intent meidaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
        KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK);
        meidaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
        context.sendOrderedBroadcast(meidaButtonIntent, "android.permission.CALL_PRIVILEGED");*/

    }

    private void answerCall(boolean isSpeakon) {

        Context context = getApplicationContext();
        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        // ??
        if (!(audioManager.isWiredHeadsetOn() || audioManager.isBluetoothA2dpOn())) {
            // 4.1??? 4.1??Permission Denial: not allowed to
            // send broadcast android.intent.action.HEADSET_PLUG from pid=1324,
            // uid=10017
            // ??????android.permission.CALL_PRIVLEGED?????4.1??????????NULL??

            Constants.log("speakerset", String.format("AudioManager before mode:%d speaker mod:%s",
                    audioManager.getMode(), String.valueOf(audioManager.isSpeakerphoneOn())));
            Intent meidaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
            KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK);
            meidaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
            context.sendOrderedBroadcast(meidaButtonIntent, "android.permission.CALL_PRIVILEGED");

            /*TelephonyManager telMag = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
            Class<TelephonyManager> c = TelephonyManager.class;
            Method mthAnswerCall;
            try {
            mthAnswerCall = c.getDeclaredMethod("getITelephony", (Class[]) null);
            mthAnswerCall.setAccessible(true);
            ITelephony iTel = (ITelephony) mthAnswerCall.invoke(telMag, (Object[]) null);
            iTel.answerRingingCall();
                
            } catch (Exception e) {
            e.printStackTrace();
            }*/
            if (isSpeakon) {
                try {
                    Thread.sleep(500);

                } catch (InterruptedException e) {
                    Constants.log("speakerset", "Problem while sleeping");
                }
                Constants.log("speakerset", "AudioManager answer mode:" + audioManager.getMode() + " speaker mod:"
                        + String.valueOf(audioManager.isSpeakerphoneOn()));
                while (audioManager.getMode() != AudioManager.MODE_IN_CALL) {
                    try {
                        Thread.sleep(300);

                    } catch (InterruptedException e) {
                        Constants.log("speakerset", "Problem while sleeping");
                    }
                }
                // audioManager.setMicrophoneMute(true);
                audioManager.setSpeakerphoneOn(true);
                // audioManager.setMode(AudioManager.MODE_IN_CALL);
                Constants.log("speakerset", String.format("AudioManager set mode:%d speaker mod:%s",
                        audioManager.getMode(), String.valueOf(audioManager.isSpeakerphoneOn())));

            }
        } else {
            Constants.log("speakerset", String.format("AudioManager before mode:%d speaker mod:%s",
                    audioManager.getMode(), String.valueOf(audioManager.isSpeakerphoneOn())));

            Intent meidaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
            KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK);
            meidaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
            context.sendOrderedBroadcast(meidaButtonIntent, "android.permission.CALL_PRIVILEGED");

        }
    }

    private void dialNumber(String phoneNumber, boolean isSpeakon) {
        Context context = getApplicationContext();

        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        Constants.log(TAG_NAME, String.format("Dial phone:%s", phoneNumber));
        // ??
        Intent callIntent = new Intent(Intent.ACTION_CALL);
        callIntent.setData(Uri.parse(String.format("tel:%s", phoneNumber)));
        callIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        callIntent.addFlags(Intent.FLAG_FROM_BACKGROUND);
        startActivity(callIntent);

        if (!(audioManager.isWiredHeadsetOn() || audioManager.isBluetoothA2dpOn())) {
            // 4.1??? 4.1??Permission Denial: not allowed to
            // send broadcast android.intent.action.HEADSET_PLUG from pid=1324,
            // uid=10017
            // ??????android.permission.CALL_PRIVLEGED?????4.1??????????NULL??

            Constants.log("speakerset", String.format("AudioManager before mode:%d speaker mod:%s",
                    audioManager.getMode(), String.valueOf(audioManager.isSpeakerphoneOn())));

            if (isSpeakon) {
                try {
                    Thread.sleep(500);

                } catch (InterruptedException e) {
                    Constants.log("speakerset", "Problem while sleeping");
                }
                Constants.log("speakerset", String.format("AudioManager answer mode:%d speaker mod:%s",
                        audioManager.getMode(), String.valueOf(audioManager.isSpeakerphoneOn())));
                while (audioManager.getMode() != AudioManager.MODE_IN_CALL) {
                    try {
                        Thread.sleep(300);

                    } catch (InterruptedException e) {
                        Constants.log("speakerset", "Problem while sleeping");
                    }
                }
                // audioManager.setMicrophoneMute(true);
                audioManager.setSpeakerphoneOn(true);
                // audioManager.setMode(AudioManager.MODE_IN_CALL);
                Constants.log("speakerset", String.format("AudioManager set mode:%d speaker mod:%s",
                        audioManager.getMode(), String.valueOf(audioManager.isSpeakerphoneOn())));

            }
        }
    }

    public void doSendSMSTo(String phoneNumber, String message) {
        if (PhoneNumberUtils.isGlobalPhoneNumber(phoneNumber)) {
            SmsManager smsmanager = SmsManager.getDefault();
            ArrayList<String> smsList = smsmanager.divideMessage(message);
            for (String sms : smsList) {
                smsmanager.sendTextMessage(phoneNumber, null, sms, null, null);
            }
            Constants.log("sendsms", String.format("send:[%s] to number:%s", message, phoneNumber));
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }

}