com.lef.ibeacon.service.UpdateService.java Source code

Java tutorial

Introduction

Here is the source code for com.lef.ibeacon.service.UpdateService.java

Source

/*******************************************************************************
 * Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved.
 * 
 * The information contained herein is property of Nordic Semiconductor ASA.
 * Terms and conditions of usage are described in detail in NORDIC SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
 * Licensees are granted free, non-transferable use of the information. NO WARRANTY of ANY KIND is provided. 
 * This heading must NOT be removed from the file.
 ******************************************************************************/
package com.lef.ibeacon.service;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;

import publicdata.PublicData;

import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.ParcelUuid;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import com.whh.beaconsdk.BuildConfig;
import com.lef.scanner.BeaconConnection;

public class UpdateService extends Service {
    private static final String TAG = "Debug";
    /**
     * action??
     */
    /**
     * ???
     */
    public final static String ACTION_STATE_CHANGED = "no.nordicsemi.android.nrfbeacon.ACTION_STATE_CHANGED";
    public final static String ACTION_GATT_ERROR = "no.nordicsemi.android.nrfbeacon.ACTION_GATT_ERROR";
    /**
     * ??service
     */
    public final static String ACTION_DONE = "no.nordicsemi.android.nrfbeacon.ACTION_DONE";
    public final static String ACTION_SOFTREBOOT_READY = "no.nordicsemi.android.nrfbeacon.ACTION_SOFTREBOOT_READY";

    public final static String ACTION_UUID1_READ_READY = "no.nordicsemi.android.nrfbeacon.ACTION_UUID1_READ_READY";
    public final static String ACTION_MAJOR1_READ_READY = "no.nordicsemi.android.nrfbeacon.ACTION_MAJOR1_READ_READY";
    public final static String ACTION_MINOR1_READ_READY = "no.nordicsemi.android.nrfbeacon.ACTION_MINOR1_READ_READY";
    public final static String ACTION_UUID2_READ_READY = "no.nordicsemi.android.nrfbeacon.ACTION_UUID2_READ_READY";
    public final static String ACTION_MAJOR2_READ_READY = "no.nordicsemi.android.nrfbeacon.ACTION_MAJOR2_READ_READY";
    public final static String ACTION_MINOR2_READ_READY = "no.nordicsemi.android.nrfbeacon.ACTION_MINOR2_READ_READY";

    public final static String ACTION_RSSI_READ_READY = "no.nordicsemi.android.nrfbeacon.ACTION_RSSI_READ_READY";

    public final static String ACTION_ADVERTISINGINTERVAL_READ_READY = "no.nordicsemi.android.nrfbeacon.ACTION_ADVERTISINGINTERVAL_READ_READY";
    public final static String ACTION_TRANSMITPOWER_READ_READY = "no.nordicsemi.android.nrfbeacon.ACTION_TRANSMITPOWER_READ_READY";
    public final static String ACTION_TIMER_READ_READY = "no.nordicsemi.android.nrfbeacon.ACTION_TIMER_READ_READY";
    public final static String ACTION_RESET_READ_READY = "no.nordicsemi.android.nrfbeacon.ACTION_RESET_READ_READY";

    public final static String ACTION_RSSI_UPDATE_READY = "no.nordicsemi.android.nrfbeacon.ACTION_RSSI_UPDATE_READY";

    public final static String ACTION_UUID1_WRITE_READY = "no.nordicsemi.android.nrfbeacon.ACTION_UUID1_WRITE_READY";
    public final static String ACTION_MAJOR1_WRITE_READY = "no.nordicsemi.android.nrfbeacon.ACTION_MAJOR1_WRITE_READY";
    public final static String ACTION_MINOR1_WRITE_READY = "no.nordicsemi.android.nrfbeacon.ACTION_MINOR1_WRITE_READY";
    public final static String ACTION_UUID2_WRITE_READY = "no.nordicsemi.android.nrfbeacon.ACTION_UUID2_WRITE_READY";
    public final static String ACTION_MAJOR2_WRITE_READY = "no.nordicsemi.android.nrfbeacon.ACTION_MAJOR2_WRITE_READY";
    public final static String ACTION_MINOR2_WRITE_READY = "no.nordicsemi.android.nrfbeacon.ACTION_MINOR2_WRITE_READY";

    public final static String ACTION_RSSI_WRITE_READY = "no.nordicsemi.android.nrfbeacon.ACTION_RSSI_WRITE_READY";

    public final static String ACTION_ADVERTISINGINTERVAL_WRITE_READY = "no.nordicsemi.android.nrfbeacon.ACTION_ADVERTISINGINTERVAL_WRITE_READY";
    public final static String ACTION_TRANSMITPOWER_WRITE_READY = "no.nordicsemi.android.nrfbeacon.ACTION_TRANSMITPOWER_WRITE_READY";
    public final static String ACTION_TIMER_WRITE_READY = "no.nordicsemi.android.nrfbeacon.ACTION_TIMER_WRITE_READY";
    public final static String ACTION_RESET_WRITE_READY = "no.nordicsemi.android.nrfbeacon.ACTION_RESET_WRITE_READY";

    public final static String EXTRA_DATA = "no.nordicsemi.android.nrfbeacon.EXTRA_DATA";
    public final static String EXTRA_DATA1 = "no.nordicsemi.android.nrfbeacon.EXTRA_DATA1";
    public final static String EXTRA_DATA2 = "no.nordicsemi.android.nrfbeacon.EXTRA_DATA2";

    public final static String EXTRA_MAJOR1 = "no.nordicsemi.android.nrfbeacon.EXTRA_MAJOR1";
    public final static String EXTRA_MINOR1 = "no.nordicsemi.android.nrfbeacon.EXTRA_MINOR1";
    public final static String EXTRA_MAJOR2 = "no.nordicsemi.android.nrfbeacon.EXTRA_MAJOR2";
    public final static String EXTRA_MINOR2 = "no.nordicsemi.android.nrfbeacon.EXTRA_MINOR2";

    public final static String EXTRA_ADVERTISINGINTERVAL = "no.nordicsemi.android.nrfbeacon.EXTRA_ADVERTISINGINTERVAL";
    public final static String EXTRA_TRANSMITPOWER = "no.nordicsemi.android.nrfbeacon.EXTRA_TRANSMITPOWER";
    public final static String EXTRA_RESET = "no.nordicsemi.android.nrfbeacon.EXTRA_RESETL";
    public final static String EXTRA_TIMER = "no.nordicsemi.android.nrfbeacon.EXTRA_TIMER";

    public final static int ERROR_UNSUPPORTED_DEVICE = -1;

    private int mConnectionState;
    public final static int STATE_DISCONNECTED = 0;
    public final static int STATE_CONNECTING = 1;
    public final static int STATE_DISCOVERING_SERVICES = 2;
    public final static int STATE_CONNECTED = 3;
    public final static int STATE_DISCONNECTING = 4;

    public final static int SERVICE_UUID = 1;
    public final static int SERVICE_MAJOR_MINOR = 2;
    public final static int SERVICE_CALIBRATION = 3;
    /**
     * ??uuid
     */
    //?
    //1?? ?   2?? ?
    private static final UUID ACCESS_SERVICE_UUID = new UUID(0X000015231212efdel, 0x1523785feabcd123l);
    private static final UUID ACCESS_PWD_CHARACTERISTIC_UUID = new UUID(0X000015241212efdel, 0x1523785feabcd123l);
    private static final UUID ACCESS_CHGEPWD_CHARACTERISTIC_UUID = new UUID(0X000015251212efdel,
            0x1523785feabcd123l);

    //1mRSSI?
    //1?RSSI ?
    private static final UUID DIS_SERVICE_UUID = new UUID(0X4432000276655332l, 0x4573161452247644l);
    private static final UUID DIS_RSSI_CHARACTERISTIC_UUID = new UUID(0X0000000100001000l, 0x800000805f9b34fbl);

    //Ali??Beacon??
    //1?major 2?minor 3?uuid   
    private static final UUID BEACON1_SERVICE_UUID = new UUID(0X1122123133445566l, 0x7788990077666564l);
    private static final UUID CONFIG1_MAJOR_CHARACTERISTIC_UUID = new UUID(0x0000001200001000l,
            0X800000805f9b34fbl);
    private static final UUID CONFIG1_MINOR_CHARACTERISTIC_UUID = new UUID(0x0000001300001000l,
            0X800000805f9b34fbl);
    private static final UUID CONFIG1_UUID_CHARACTERISTIC_UUID = new UUID(0x0000001100001000l, 0X800000805f9b34fbl);

    //Baidu??Beacon??
    //1?major 2?minor 3?uuid   
    private static final UUID BEACON2_SERVICE_UUID = new UUID(0X1122123233445566l, 0x7438110077665444l);
    private static final UUID CONFIG2_MAJOR_CHARACTERISTIC_UUID = new UUID(0x0000002200001000l,
            0X800000805f9b34fbl);
    private static final UUID CONFIG2_MINOR_CHARACTERISTIC_UUID = new UUID(0x0000002300001000l,
            0X800000805f9b34fbl);
    private static final UUID CONFIG2_UUID_CHARACTERISTIC_UUID = new UUID(0x0000002100001000l, 0X800000805f9b34fbl);

    //????
    private static final UUID TPS_SERVICE_UUID = new UUID(0X4527000388773343l, 0x6742368453362545l);
    private static final UUID TPS_TXPOWER_CHARACTERISTIC_UUID = new UUID(0x0000003200001000l, 0X800000805f9b34fbl);
    private static final UUID TPS_ADVERTISINGINTERVAL_CHARACTERISTIC_UUID = new UUID(0x0000003100001000l,
            0X800000805f9b34fbl);

    //??
    private static final UUID KEYSET_SERVICE_UUID = new UUID(0X000044231212efdel, 0x1523785feabcd111l);
    private static final UUID KEYSET_RESET_CHARACTERISTIC_UUID = new UUID(0x000044241212efdel, 0X1523785feabcd111l);

    //??
    private static final UUID TIMER_SERVICE_UUID = new UUID(0X0000112312433276l, 0x1523212132534121l);
    private static final UUID TIMER_SET_CHARACTERISTIC_UUID = new UUID(0X0000112412433276l, 0x1523212132534121l);

    //Beacon
    private static final UUID TRACKING_SERVICE_UUID = new UUID(0X2232324114862346l, 0x2535714636125332l);
    private static final UUID TRACKING_RSSI_CHARACTERISTIC_UUID = new UUID(0X2232324214862346l,
            0x2535714636125332l);
    protected static final UUID RSSI_DESCRIPTER_UUID = new UUID(0X0000290200001000l, 0x800000805f9b34fbl);

    private BluetoothAdapter mAdapter;
    private BluetoothDevice mBluetoothDevice;
    private BluetoothGatt mBluetoothGatt;

    //?????
    private BluetoothGattCharacteristic mPwdCharacteristic;
    private BluetoothGattCharacteristic mChgepwdCharacteristic;

    private BluetoothGattCharacteristic mUuid1Characteristic;
    private BluetoothGattCharacteristic mMajor1Characteristic;
    private BluetoothGattCharacteristic mMinor1Characteristic;

    private BluetoothGattCharacteristic mUuid2Characteristic;
    private BluetoothGattCharacteristic mMajor2Characteristic;
    private BluetoothGattCharacteristic mMinor2Characteristic;

    private BluetoothGattCharacteristic mRssiCharacteristic;

    private BluetoothGattCharacteristic mAdvertisingintervalCharacteristic;
    private BluetoothGattCharacteristic mTransmitpowerCharacteristic;

    private BluetoothGattCharacteristic mKeysetCharacteristic;

    private BluetoothGattCharacteristic mTimerCharacteristic;

    private BluetoothGattCharacteristic mTrackRssiCharacteristic;

    private Handler mHandler;
    private volatile boolean errorSign = false;
    Timer timer = new Timer();
    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) {
            if (status != BluetoothGatt.GATT_SUCCESS) {
                //            logw("Connection state change error: " + status);
                //            Log.w(TAG, status + "");
                broadcastError(status);
                return;
            }

            if (newState == BluetoothProfile.STATE_CONNECTED) {
                setState(STATE_DISCOVERING_SERVICES);

                // Attempts to discover services after successful connection.
                gatt.discoverServices();
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                setState(STATE_DISCONNECTED);
                if (gatt != null) {
                    refreshDeviceCache(gatt);
                    gatt.close();
                }
                mBluetoothGatt = null;
                stopSelf();
            }
        }

        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            //         logw("onCharacteristicChanged RSSI: " + characteristic.getIntValue(
            //               BluetoothGattCharacteristic.FORMAT_SINT8, 0));
            if (TRACKING_RSSI_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {

                PublicData.getInstance().phone_rssi = characteristic
                        .getIntValue(BluetoothGattCharacteristic.FORMAT_SINT8, 0);
                broadcastRssiUpdate();
            }

        }

        // ???8?
        @Override
        public void onServicesDiscovered(final BluetoothGatt gatt, final int status) {
            if (status != BluetoothGatt.GATT_SUCCESS) {
                //            logw("Service discovery error: " + status);
                broadcastError(status);
                return;
            }
            // ???
            List<BluetoothGattService> ListService = gatt.getServices();
            if (ListService == null) {
                broadcastError(ERROR_UNSUPPORTED_DEVICE);
                setState(STATE_DISCONNECTING);
                gatt.disconnect();
                return;
            }
            if (ListService.contains(gatt.getService(ACCESS_SERVICE_UUID))) {
                final BluetoothGattService accessService = gatt.getService(ACCESS_SERVICE_UUID);
                mPwdCharacteristic = accessService.getCharacteristic(ACCESS_PWD_CHARACTERISTIC_UUID);
                mChgepwdCharacteristic = accessService.getCharacteristic(ACCESS_CHGEPWD_CHARACTERISTIC_UUID);
                if (mPwdCharacteristic != null || mChgepwdCharacteristic != null) {
                    //               logw("ACCESS Service discovery success: ");
                    broadcastOperationCompleted();
                }

                if (mPwdCharacteristic == null && mChgepwdCharacteristic == null) {
                    // Config characteristics is not present
                    broadcastError(ERROR_UNSUPPORTED_DEVICE);
                    setState(STATE_DISCONNECTING);
                    gatt.disconnect();
                    return;
                }
            }
            if (ListService.contains(gatt.getService(DIS_SERVICE_UUID))) {
                final BluetoothGattService disService = gatt.getService(DIS_SERVICE_UUID);
                mRssiCharacteristic = disService.getCharacteristic(DIS_RSSI_CHARACTERISTIC_UUID);
                if (mRssiCharacteristic != null) {
                    //               logw("DIS Service discovery success: ");
                    broadcastOperationCompleted();
                }

                if (mRssiCharacteristic == null) {
                    // Config characteristics is not present
                    broadcastError(ERROR_UNSUPPORTED_DEVICE);
                    setState(STATE_DISCONNECTING);
                    gatt.disconnect();
                    return;
                }
            }
            if (ListService.contains(gatt.getService(KEYSET_SERVICE_UUID))) {
                final BluetoothGattService keysetService = gatt.getService(KEYSET_SERVICE_UUID);
                mKeysetCharacteristic = keysetService.getCharacteristic(KEYSET_RESET_CHARACTERISTIC_UUID);
                if (mKeysetCharacteristic != null) {
                    //               logw("KEYSET Service discovery success: ");
                    broadcastOperationCompleted();
                }

                if (mKeysetCharacteristic == null) {
                    // Config characteristics is not present
                    broadcastError(ERROR_UNSUPPORTED_DEVICE);
                    setState(STATE_DISCONNECTING);
                    gatt.disconnect();
                    return;
                }
            }
            if (ListService.contains(gatt.getService(TIMER_SERVICE_UUID))) {
                final BluetoothGattService keysetService = gatt.getService(TIMER_SERVICE_UUID);
                mTimerCharacteristic = keysetService.getCharacteristic(TIMER_SET_CHARACTERISTIC_UUID);
                if (mTimerCharacteristic != null) {
                    //               logw("TIMER Service discovery success: ");
                    broadcastOperationCompleted();
                }

                if (mTimerCharacteristic == null) {
                    // Config characteristics is not present
                    broadcastError(ERROR_UNSUPPORTED_DEVICE);
                    setState(STATE_DISCONNECTING);
                    gatt.disconnect();
                    return;
                }
            }
            if (ListService.contains(gatt.getService(TRACKING_SERVICE_UUID))) {
                final BluetoothGattService trackingService = gatt.getService(TRACKING_SERVICE_UUID);
                mTrackRssiCharacteristic = trackingService.getCharacteristic(TRACKING_RSSI_CHARACTERISTIC_UUID);
                if (mTrackRssiCharacteristic != null) {
                    logw("mTrackRssiCharacteristic Service discovery success: ");
                    broadcastOperationCompleted();
                }

                if (mTrackRssiCharacteristic == null) {
                    // Config characteristics is not present
                    broadcastError(ERROR_UNSUPPORTED_DEVICE);
                    setState(STATE_DISCONNECTING);
                    gatt.disconnect();
                    return;
                }
            }
            if (ListService.contains(gatt.getService(BEACON1_SERVICE_UUID))) {
                final BluetoothGattService beacon1Service = gatt.getService(BEACON1_SERVICE_UUID);
                mMajor1Characteristic = beacon1Service.getCharacteristic(CONFIG1_MAJOR_CHARACTERISTIC_UUID);
                mMinor1Characteristic = beacon1Service.getCharacteristic(CONFIG1_MINOR_CHARACTERISTIC_UUID);
                mUuid1Characteristic = beacon1Service.getCharacteristic(CONFIG1_UUID_CHARACTERISTIC_UUID);

                if (mMajor1Characteristic != null && mMinor1Characteristic != null
                        && mUuid1Characteristic != null) {
                    //               logw("BEACON1 Service discovery success: ");
                    broadcastOperationCompleted();
                }

                if (mMajor1Characteristic == null || mMinor1Characteristic == null
                        || mUuid1Characteristic == null) {
                    //logw("Service discovery BEACON1: " + status);
                    broadcastError(ERROR_UNSUPPORTED_DEVICE);
                    setState(STATE_DISCONNECTING);
                    gatt.disconnect();
                    return;
                }
            }

            if (ListService.contains(gatt.getService(BEACON2_SERVICE_UUID))) {
                final BluetoothGattService beacon2Service = gatt.getService(BEACON2_SERVICE_UUID);
                mMajor2Characteristic = beacon2Service.getCharacteristic(CONFIG2_MAJOR_CHARACTERISTIC_UUID);
                mMinor2Characteristic = beacon2Service.getCharacteristic(CONFIG2_MINOR_CHARACTERISTIC_UUID);
                mUuid2Characteristic = beacon2Service.getCharacteristic(CONFIG2_UUID_CHARACTERISTIC_UUID);

                if (mMajor2Characteristic != null && mMinor2Characteristic != null
                        && mUuid2Characteristic != null) {
                    //               logw("BEACON2 Service discovery success: ");
                    broadcastOperationCompleted();
                }

                if (mMajor2Characteristic == null || mMinor2Characteristic == null
                        || mUuid2Characteristic == null) {
                    //logw("Service discovery BEACON1: " + status);
                    broadcastError(ERROR_UNSUPPORTED_DEVICE);
                    setState(STATE_DISCONNECTING);
                    gatt.disconnect();
                    return;
                }
            }
            if (ListService.contains(gatt.getService(TPS_SERVICE_UUID))) {
                final BluetoothGattService tpsService = gatt.getService(TPS_SERVICE_UUID);
                mTransmitpowerCharacteristic = tpsService.getCharacteristic(TPS_TXPOWER_CHARACTERISTIC_UUID);
                mAdvertisingintervalCharacteristic = tpsService
                        .getCharacteristic(TPS_ADVERTISINGINTERVAL_CHARACTERISTIC_UUID);

                if (mTransmitpowerCharacteristic != null && mAdvertisingintervalCharacteristic != null) {
                    //               logw("TPS Service discovery success: ");
                    broadcastOperationCompleted();
                }

                if (mTransmitpowerCharacteristic == null || mAdvertisingintervalCharacteristic == null) {
                    // Config characteristics is not present
                    broadcastError(ERROR_UNSUPPORTED_DEVICE);
                    setState(STATE_DISCONNECTING);
                    gatt.disconnect();
                    return;
                }
            }
        }

        @Override
        public void onCharacteristicWrite(final BluetoothGatt gatt,
                final BluetoothGattCharacteristic characteristic, final int status) {
            if (status != BluetoothGatt.GATT_SUCCESS) {
                //            logw("Characteristic write error: " + status);
                broadcastError(status);
                return;
            }

            //?
            if (ACCESS_CHGEPWD_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
                //            logw("chgepass: " + characteristic.getValue()[0]+characteristic.getValue()[1]);

            }
            // ????????
            if (ACCESS_PWD_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
                //            logw("pass: " + characteristic.getValue()[0]+characteristic.getValue()[1]);                        
                if (mTransmitpowerCharacteristic != null) {
                    mBluetoothGatt.readCharacteristic(mTransmitpowerCharacteristic);
                }
            }
            if (CONFIG1_UUID_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
                UUID uuid1 = decodeBeaconUUID(characteristic);
                broadcastUuid1Write(uuid1);
            } else if (CONFIG1_MAJOR_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
                //            Log.d("CONFIG1_MAJOR_CHARACTERISTIC_UUID", "XXXXXXXXX");
                final int major1 = decodeUInt16(characteristic, 0);
                broadcastMajor1Write(major1);
                //            Log.d("Debug", "XXXXXXXXX");
            } else if (CONFIG1_MINOR_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
                final int minor1 = decodeUInt16(characteristic, 0);
                broadcastMinor1Write(minor1);
            }
            if (CONFIG2_UUID_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
                UUID uuid2 = decodeBeaconUUID(characteristic);
                broadcastUuid2Write(uuid2);
            } else if (CONFIG2_MAJOR_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
                //            Log.d("CONFIG2_MAJOR_CHARACTERISTIC_UUID", "XXXXXXXXX");
                final int major2 = decodeUInt16(characteristic, 0);
                broadcastMajor2Write(major2);
                //            Log.d("Debug", "XXXXXXXXX");
            } else if (CONFIG2_MINOR_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
                final int minor2 = decodeUInt16(characteristic, 0);
                broadcastMinor2Write(minor2);
            } else if (DIS_RSSI_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
                final int rssi = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT8, 0);
                //            logw("rssi write: " + rssi);
                broadcastRssiWrite(rssi);
            } else if (KEYSET_RESET_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
                final int reset = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
                //            logw("reset write: " + reset);
                broadcastResetWrite(reset);
            } else if (TIMER_SET_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
                final int timer = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
                //            logw("timer write: " + timer);
                broadcastTimerWrite(timer);
            } else if (TPS_ADVERTISINGINTERVAL_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
                final int advertisinginterval = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8,
                        0);
                broadcastAdvertisingintervalWrite(advertisinginterval);
            } else if (TPS_TXPOWER_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
                final int Transmitpower = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT8, 0);
                int t = Transmitpower;
                if (Transmitpower == 14)
                    t = -4;
                if (Transmitpower == 18)
                    t = -8;
                if (Transmitpower == 22)
                    t = -12;
                if (Transmitpower == 26)
                    t = -16;
                if (Transmitpower == 30)
                    t = -20;
                logw("Transmitpower write: " + t);
                broadcastTransmitpowerWrite(t);
                // // ?????mcurrnentBeacon?            
            }
        }

        @Override
        public void onCharacteristicRead(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic,
                final int status) {
            if (status != BluetoothGatt.GATT_SUCCESS) {
                //            logw("Characteristic read error: " + status);
                broadcastError(status);
                return;
            }

            //         if (CONFIG1_UUID_CHARACTERISTIC_UUID
            //               .equals(characteristic.getUuid())) {
            //            logw("uuid1 Characteristic read ok: ");            
            //            final UUID uuid1 = decodeBeaconUUID(characteristic);
            //            broadcastUuid1Read(uuid1);
            //            if (mMajor1Characteristic.getValue() == null)
            //               gatt.readCharacteristic(mMajor1Characteristic);            
            //         } else if (CONFIG1_MAJOR_CHARACTERISTIC_UUID.equals(characteristic
            //               .getUuid())) {
            //            logw("Major1 Characteristic read ok: ");
            //            final int major1 = decodeUInt16(characteristic, 0);
            //            broadcastMajor1Read(major1);
            //            if (mMinor1Characteristic.getValue() == null)
            //               gatt.readCharacteristic(mMinor1Characteristic);
            //         } else if (CONFIG1_MINOR_CHARACTERISTIC_UUID.equals(characteristic
            //               .getUuid())) {
            //            logw("Minor1 Characteristic read ok: ");
            //            final int minor1 = decodeUInt16(characteristic, 0);
            //            broadcastMinor1Read(minor1);
            //            if (mUuid2Characteristic.getValue() == null)
            //               gatt.readCharacteristic(mUuid2Characteristic);
            //         } 
            //         if (CONFIG2_UUID_CHARACTERISTIC_UUID
            //               .equals(characteristic.getUuid())) {
            //            logw("uuid2 Characteristic read ok: ");            
            //            final UUID uuid2 = decodeBeaconUUID(characteristic);
            //            broadcastUuid2Read(uuid2);
            //            if (mMajor2Characteristic.getValue() == null)
            //               gatt.readCharacteristic(mMajor2Characteristic);            
            //         } else if (CONFIG2_MAJOR_CHARACTERISTIC_UUID.equals(characteristic
            //               .getUuid())) {
            //            logw("Major2 Characteristic read ok: ");
            //            final int major2 = decodeUInt16(characteristic, 0);
            //            broadcastMajor2Read(major2);
            //            if (mMinor2Characteristic.getValue() == null)
            //               gatt.readCharacteristic(mMinor2Characteristic);
            //         } else if (CONFIG2_MINOR_CHARACTERISTIC_UUID.equals(characteristic
            //               .getUuid())) {
            //            logw("Minor2 Characteristic read ok: ");
            //            final int minor2 = decodeUInt16(characteristic, 0);
            //            broadcastMinor2Read(minor2);
            //            if (mRssiCharacteristic.getValue() == null)
            //               logw("RSSI Characteristic read start: ");
            //               gatt.readCharacteristic(mRssiCharacteristic);
            //         }
            //         else if (DIS_RSSI_CHARACTERISTIC_UUID.equals(characteristic
            //               .getUuid())) {         
            //            final int rssi = characteristic.getIntValue(
            //                  BluetoothGattCharacteristic.FORMAT_SINT8, 0);
            //            logw("RSSI Characteristic read ok: " + rssi);
            //            broadcastRssiRead(rssi);
            //            if (mAdvertisingintervalCharacteristic.getValue() == null) {
            //               gatt.readCharacteristic(mAdvertisingintervalCharacteristic);
            //            }
            //         } else if (TPS_ADVERTISINGINTERVAL_CHARACTERISTIC_UUID
            //               .equals(characteristic.getUuid())) {
            //            logw("ADVERTISINGINTERVAL Characteristic read ok: ");
            //            final int advertisinginterval = characteristic.getIntValue(
            //                  BluetoothGattCharacteristic.FORMAT_UINT8, 0);
            //            logw("ADVERTISINGINTERVAL: " + advertisinginterval);
            //            broadcastAdvertisingintervalRead(advertisinginterval);
            //            if (mTimerCharacteristic.getValue() == null) {
            //               gatt.readCharacteristic(mTimerCharacteristic);
            //            }
            //         } else if (TIMER_SET_CHARACTERISTIC_UUID
            //               .equals(characteristic.getUuid())) {
            //            logw("TIMER Characteristic read ok: ");
            //            final int timer = characteristic.getIntValue(
            //                  BluetoothGattCharacteristic.FORMAT_SINT8, 0);
            //            logw("TIMER: " + timer);
            //            broadcastTimerRead(timer);
            //            if (mKeysetCharacteristic.getValue() == null) {
            //               gatt.readCharacteristic(mKeysetCharacteristic);
            //            }
            //         } else if (KEYSET_RESET_CHARACTERISTIC_UUID
            //               .equals(characteristic.getUuid())) {
            //            logw("KEYSET_RESET Characteristic read ok: ");
            //            final int reset = characteristic.getIntValue(
            //                  BluetoothGattCharacteristic.FORMAT_UINT8, 0);
            //            logw("KEYSET_RESET: " + reset);
            //            broadcastResetRead(reset);
            //            if (mTransmitpowerCharacteristic.getValue() == null) {
            //               gatt.readCharacteristic(mTransmitpowerCharacteristic);
            //            }
            //         }else 
            if (TPS_TXPOWER_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
                logw("TXPOWER Characteristic read ok: ");
                final int Transmitpower = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT8, 0);
                logw("TXPOWER: " + Transmitpower);
                //            broadcastTransmitpowerRead(Transmitpower);
                // ?????mcurrnentBeacon?
                setState(STATE_CONNECTED);
                if (mBluetoothGatt.setCharacteristicNotification(mTrackRssiCharacteristic, true)) {
                    logw("setCharacteristicNotification success!!!! ");
                } else
                    logw("setCharacteristicNotification failed!!!! ");
                BluetoothGattDescriptor desc = mTrackRssiCharacteristic.getDescriptor(RSSI_DESCRIPTER_UUID);
                if (desc == null)
                    logw("desc + failed!!!! ");
                boolean test;
                test = desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); // return value = true
                //            test = gatt.readDescriptor(desc);  // return value = true
                test = gatt.writeDescriptor(desc); // return value = true

            }
        }
    };

    public class ServiceBinder extends Binder {
        /**
         * Connects to the service. The bluetooth device must have been passed
         * during binding to the service in {@link UpdateService#EXTRA_DATA}
         * field.
         * 
         * @return <code>true</code> if connection process has been initiated
         */
        public boolean connect() {
            if (mAdapter == null) {
                //            logw("BluetoothAdapter not initialized or unspecified address.");
                return false;
            }

            if (mBluetoothDevice == null) {
                //            logw("Target device not specified. Start service with the BluetoothDevice set in EXTRA_DATA field.");
                return false;
            }

            // the device may be already connected
            if (mConnectionState == STATE_CONNECTED) {
                //            logw("????");
                return true;
            }

            setState(STATE_CONNECTING);
            mBluetoothGatt = mBluetoothDevice.connectGatt(UpdateService.this, false, mGattCallback);
            //         logw("?");
            return true;
        }

        /**
         * Disconnects from the device and closes the Bluetooth GATT object
         * afterwards.
         */
        public void disconnectAndClose() {
            // This sometimes happen when called from
            // UpdateService.ACTION_GATT_ERROR event receiver in UpdateFragment.
            if (mBluetoothGatt == null)
                return;

            setState(STATE_DISCONNECTING);
            mBluetoothGatt.disconnect();

            // Sometimes the connection gets error 129 or 133. Calling
            // disconnect() method does not really disconnect... sometimes the
            // connection is already broken.
            // Here we have a security check that notifies UI about
            // disconnection even if onConnectionStateChange(...) has not been
            // called.
            // 1500??
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (mConnectionState == STATE_DISCONNECTING)
                        mGattCallback.onConnectionStateChange(mBluetoothGatt, BluetoothGatt.GATT_SUCCESS,
                                BluetoothProfile.STATE_DISCONNECTED);
                }
            }, 1500);

        }

        /**
         * Reads all the values from the device, one by one.
         * 
         * @return <code>true</code> if at least one required characteristic has
         *         been found on the beacon.
         */
        public boolean read() {
            if (mBluetoothGatt == null)
                return false;

            if (mUuid1Characteristic != null) {
                mBluetoothGatt.readCharacteristic(mUuid1Characteristic);
                return true;
            } else if (mMajor1Characteristic != null) {
                mBluetoothGatt.readCharacteristic(mMajor1Characteristic);
                return true;
            } else if (mMinor1Characteristic != null) {
                mBluetoothGatt.readCharacteristic(mMinor1Characteristic);
                return true;
            } else if (mRssiCharacteristic != null) {
                mBluetoothGatt.readCharacteristic(mRssiCharacteristic);
                return true;
            } else if (mAdvertisingintervalCharacteristic != null) {
                mBluetoothGatt.readCharacteristic(mAdvertisingintervalCharacteristic);
                return true;
            } else if (mTransmitpowerCharacteristic != null) {
                mBluetoothGatt.readCharacteristic(mTransmitpowerCharacteristic);
                return true;
            }
            return false;
        }

        /**
         * ????
         */
        public void sendConnectAuthenticate() {
            if (mBluetoothGatt == null)
                return;

            //         Log.w("PublicData.getInstance().passwd:", " "+PublicData.getInstance().passwd[0]+ " "+
            //         PublicData.getInstance().passwd[1]+" "+PublicData.getInstance().passwd[2]
            //               +PublicData.getInstance().passwd[3]+PublicData.getInstance().passwd[4]
            //                     +PublicData.getInstance().passwd[5]);
            /**
             * ?????                   
            */
            mPwdCharacteristic.setValue(BeaconConnection.PASSWORD);
            logw("DEBUG" + BeaconConnection.PASSWORD[0] + BeaconConnection.PASSWORD[1]);
            mBluetoothGatt.writeCharacteristic(mPwdCharacteristic);
        }

        //????
        public boolean sendChangePwd() {
            if (mBluetoothGatt == null)
                return false;

            //   Log.w("PublicData.getInstance().chagepwd:", " "+PublicData.getInstance().chagepwd[0]+ " "+PublicData.getInstance().chagepwd[1]);
            /**
             * ?????                   
            */
            mChgepwdCharacteristic.setValue(BeaconConnection.CHGEPWD);
            //         Log.w("CHGEPWD:", " "+BeaconConnection.CHGEPWD[0]+ " "+
            //               BeaconConnection.CHGEPWD[1]+" "+BeaconConnection.CHGEPWD[2]
            //                     +BeaconConnection.CHGEPWD[3]+BeaconConnection.CHGEPWD[4]
            //                           +BeaconConnection.CHGEPWD[5]);
            if (mBluetoothGatt.writeCharacteristic(mChgepwdCharacteristic)) {
                Log.w("sendChangePwd", " success");
                return true;
            }

            else
                return false;
        }

        /**
         * Overwrites the beacon service UUID1.
         * 
         * @param uuid
         *            the new UUID1
         * @return <code>true</code> if altering UUID1 is supported (required
         *         characteristic exists)
         */
        public boolean setBeaconUuid1(final UUID uuid) {
            if (mUuid1Characteristic == null || uuid == null)
                return false;

            final byte[] data = new byte[16];
            for (int i = 0; i < 8; ++i)
                data[i] = (byte) ((uuid.getMostSignificantBits() >>> (56 - i * 8)) & 0xFF);
            for (int i = 8; i < 16; ++i)
                data[i] = (byte) ((uuid.getLeastSignificantBits() >>> (56 - i * 8)) & 0xFF);
            mUuid1Characteristic.setValue(data);
            if (mBluetoothGatt != null)
                mBluetoothGatt.writeCharacteristic(mUuid1Characteristic);
            else
                return false;
            return true;
        }

        /**
         * Overwrites the beacon service UUID2.
         * 
         * @param uuid
         *            the new UUID2
         * @return <code>true</code> if altering UUID2 is supported (required
         *         characteristic exists)
         */
        public boolean setBeaconUuid2(final UUID uuid) {
            if (mUuid1Characteristic == null || uuid == null)
                return false;

            final byte[] data = new byte[16];
            for (int i = 0; i < 8; ++i)
                data[i] = (byte) ((uuid.getMostSignificantBits() >>> (56 - i * 8)) & 0xFF);
            for (int i = 8; i < 16; ++i)
                data[i] = (byte) ((uuid.getLeastSignificantBits() >>> (56 - i * 8)) & 0xFF);
            mUuid2Characteristic.setValue(data);
            if (mBluetoothGatt != null)
                mBluetoothGatt.writeCharacteristic(mUuid2Characteristic);
            else
                return false;
            return true;
        }

        /**
         * Returns the current UUID value. This reads the value from the local
         * cache. The {@link #read()} method must be invoked before to read the
         * current value from the device.
         * 
         * @return the beacon service UUID
         */
        public UUID getBeaconUuid1() {
            final BluetoothGattCharacteristic characteristic = mUuid1Characteristic;
            if (characteristic != null) {
                final byte[] data = characteristic.getValue();
                if (data == null || data.length != 16)
                    return null;
                return decodeBeaconUUID(characteristic);
            }
            return null;
        }

        public UUID getBeaconUuid2() {
            final BluetoothGattCharacteristic characteristic = mUuid2Characteristic;
            if (characteristic != null) {
                final byte[] data = characteristic.getValue();
                if (data == null || data.length != 16)
                    return null;
                return decodeBeaconUUID(characteristic);
            }
            return null;
        }

        /**
         * Overwrites the beacon major and minor numbers.
         * 
         * @param major
         *            the major number (0-65535)
         * @param minor
         *            the minor number (0-65535)
         * @return <code>true</code> if altering major and minor is supported
         *         (required characteristic exists)
         */
        public boolean setMajor1(final int major) {
            if (mMajor1Characteristic == null)
                return false;

            if (major < 0 || major > 0xFFFF)
                return false;

            final int majorInverted = (major & 0xFF) << 8 | ((major >> 8) & 0xFF);
            mMajor1Characteristic.setValue(majorInverted, BluetoothGattCharacteristic.FORMAT_UINT16, 0);
            if (mBluetoothGatt != null)
                mBluetoothGatt.writeCharacteristic(mMajor1Characteristic);
            else
                return false;
            return true;
        }

        public boolean setMajor2(final int major) {
            if (mMajor2Characteristic == null)
                return false;

            if (major < 0 || major > 0xFFFF)
                return false;

            final int majorInverted = (major & 0xFF) << 8 | ((major >> 8) & 0xFF);
            mMajor2Characteristic.setValue(majorInverted, BluetoothGattCharacteristic.FORMAT_UINT16, 0);
            if (mBluetoothGatt != null)
                mBluetoothGatt.writeCharacteristic(mMajor2Characteristic);
            else
                return false;
            return true;
        }

        /**
         * Overwrites the beacon major and minor numbers.
         * 
         * @param major
         *            the major number (0-65535)
         * @param minor
         *            the minor number (0-65535)
         * @return <code>true</code> if altering major and minor is supported
         *         (required characteristic exists)
         */
        public boolean setMinor1(final int minor) {
            if (mMinor1Characteristic == null)
                return false;
            if (minor < 0 || minor > 0xFFFF)
                return false;
            final int minorInverted = (minor & 0xFF) << 8 | ((minor >> 8) & 0xFF);
            mMinor1Characteristic.setValue(minorInverted, BluetoothGattCharacteristic.FORMAT_UINT16, 0);
            if (mBluetoothGatt != null)
                mBluetoothGatt.writeCharacteristic(mMinor1Characteristic);
            else
                return false;
            return true;
        }

        public boolean setMinor2(final int minor) {
            if (mMinor2Characteristic == null)
                return false;
            if (minor < 0 || minor > 0xFFFF)
                return false;
            final int minorInverted = (minor & 0xFF) << 8 | ((minor >> 8) & 0xFF);
            mMinor2Characteristic.setValue(minorInverted, BluetoothGattCharacteristic.FORMAT_UINT16, 0);
            if (mBluetoothGatt != null)
                mBluetoothGatt.writeCharacteristic(mMinor2Characteristic);
            else
                return false;
            return true;
        }

        /**
         * ???
         * 
         * @param passWord
         * @return
         */
        public boolean sendPassword(String passWord) {
            if (mPwdCharacteristic == null) {
                return false;
            }
            mPwdCharacteristic.setValue(passWord);
            if (mBluetoothGatt != null)
                mBluetoothGatt.writeCharacteristic(mPwdCharacteristic);
            return true;
        }

        /**
         * ?
         * 
         * @param passWord
         * @return
         */
        public boolean setPassword(String passWord) {
            // TODO Auto-generated method stub
            if (mPwdCharacteristic == null) {
                return false;
            }
            mPwdCharacteristic.setValue(passWord);
            if (mBluetoothGatt != null)
                mBluetoothGatt.writeCharacteristic(mPwdCharacteristic);
            return true;
        }

        /**
         * Returns the pair of current Major and Minor values. This reads the
         * value from the local cache. The {@link #read()} method must be
         * invoked before to read the current value from the device.
         * 
         * @return the pair where the first value is the major number and the
         *         second is the minor value
         */
        public int getMajor1() {
            final BluetoothGattCharacteristic characteristic = mMajor1Characteristic;
            if (characteristic != null) {
                final byte[] data = characteristic.getValue();
                if (data == null || data.length != 2)
                    return -1;
                final int major = decodeUInt16(characteristic, 0);
                return major;
            }
            return -1;
        }

        public int getMajor2() {
            final BluetoothGattCharacteristic characteristic = mMajor2Characteristic;
            if (characteristic != null) {
                final byte[] data = characteristic.getValue();
                if (data == null || data.length != 2)
                    return -1;
                final int major = decodeUInt16(characteristic, 0);
                return major;
            }
            return -1;
        }

        /**
         * Returns the pair of current Major and Minor values. This reads the
         * value from the local cache. The {@link #read()} method must be
         * invoked before to read the current value from the device.
         * 
         * @return the pair where the first value is the major number and the
         *         second is the minor value
         */
        public int getMinor1() {
            final BluetoothGattCharacteristic characteristic = mMinor1Characteristic;
            if (characteristic != null) {
                final byte[] data = characteristic.getValue();
                if (data == null || data.length != 2)
                    return -1;
                final int minor = decodeUInt16(characteristic, 0);
                return minor;
            }
            return -1;
        }

        public int getMinor2() {
            final BluetoothGattCharacteristic characteristic = mMinor2Characteristic;
            if (characteristic != null) {
                final byte[] data = characteristic.getValue();
                if (data == null || data.length != 2)
                    return -1;
                final int minor = decodeUInt16(characteristic, 0);
                return minor;
            }
            return -1;
        }

        /**
         * Overwrites the beacon calibration RSSI value.
         * 
         * @param rssi
         *            the RSSI value calculated at 1m distance from the beacon
         *            using iPhone 5S.
         * @return <code>true</code> if altering major and minor is supported
         *         (required characteristic exists)
         */
        public boolean setCalibratedRssi(final int rssi) {
            if (mRssiCharacteristic == null)
                return false;
            mRssiCharacteristic.setValue(rssi, BluetoothGattCharacteristic.FORMAT_SINT8, 0);
            if (mBluetoothGatt != null)
                mBluetoothGatt.writeCharacteristic(mRssiCharacteristic);
            return true;
        }

        /**
         * Overwrites the beacon Reset value.
         * 
         * @param reset
         *            the reset value can be 0 or 1, if it is 1 the beacon will be
         *            in the low energy state
         * @return <code>true</code> if altering reset is supported
         *         (required characteristic exists)
         */
        public boolean setReset(final int reset) {
            if (mKeysetCharacteristic == null)
                return false;
            mKeysetCharacteristic.setValue(reset, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
            if (mBluetoothGatt != null)
                mBluetoothGatt.writeCharacteristic(mKeysetCharacteristic);
            return true;
        }

        /**
         * Overwrites the beacon Timer value.
         * 
         * @param timer
         *            timer can control the 2 different advertising packet,and the 
         *            advertising interval may be not important  
         * @return <code>true</code> if altering timer is supported
         *         (required characteristic exists)
         */
        public boolean setTimer(final int timer) {
            if (mTimerCharacteristic == null)
                return false;
            mTimerCharacteristic.setValue(timer, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
            if (mBluetoothGatt != null)
                mBluetoothGatt.writeCharacteristic(mTimerCharacteristic);
            return true;
        }

        /**
         * ?beacon?
         * 
         * @param advertisingInterval
         * @return
         */
        public boolean setAdvertisingInterval(final int advertisingInterval) {
            if (mAdvertisingintervalCharacteristic == null)
                return false;

            mAdvertisingintervalCharacteristic.setValue(advertisingInterval,
                    BluetoothGattCharacteristic.FORMAT_UINT8, 0);
            if (mBluetoothGatt != null)
                mBluetoothGatt.writeCharacteristic(mAdvertisingintervalCharacteristic);
            return true;
        }

        /**
         * ?beacon?
         * 
         * @param transmitPower
         * @return
         */
        public boolean setTransmitPower(final int transmitPower) {
            if (mTransmitpowerCharacteristic == null)
                return false;
            int t = transmitPower;
            if (transmitPower == -4)
                t = 14;
            if (transmitPower == -8)
                t = 18;
            if (transmitPower == -12)
                t = 22;
            if (transmitPower == -16)
                t = 26;
            if (transmitPower == -20)
                t = 30;
            //         Log.w("setTransmitPower"," "+transmitPower);
            mTransmitpowerCharacteristic.setValue(t, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
            if (mBluetoothGatt != null)
                mBluetoothGatt.writeCharacteristic(mTransmitpowerCharacteristic);
            return true;
        }

        /**
         * Obtains the cached value of the AdvertisingInterval characteristic.
         * If the value has not been obtained yet using {@link #read()}, or the
         * characteristic has not been found on the beacon, <code>null</code> is
         * returned.
         * 
         * @return the RSSI value or <code>null</code>
         */
        public Integer getAdvertisingInterval() {
            final BluetoothGattCharacteristic characteristic = mAdvertisingintervalCharacteristic;
            if (characteristic != null) {
                final byte[] data = characteristic.getValue();
                if (data == null || data.length < 1)
                    return null;
                return characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
            }
            return null;
        }

        /**
         * Obtains the cached value of the AdvertisingInterval characteristic.
         * If the value has not been obtained yet using {@link #read()}, or the
         * characteristic has not been found on the beacon, <code>null</code> is
         * returned.
         * 
         * @return the RSSI value or <code>null</code>
         */
        public Integer getTransmitPower() {
            final BluetoothGattCharacteristic characteristic = mTransmitpowerCharacteristic;
            if (characteristic != null) {
                final byte[] data = characteristic.getValue();
                if (data == null || data.length < 1)
                    return null;
                return characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT8, 0);
            }
            return null;
        }

        /**
         * Obtains the cached value of the RSSI characteristic. If the value has
         * not been obtained yet using {@link #read()}, or the characteristic
         * has not been found on the beacon, <code>null</code> is returned.
         * 
         * @return the RSSI value or <code>null</code>
         */
        public Integer getCalibratedRssi() {
            final BluetoothGattCharacteristic characteristic = mRssiCharacteristic;
            if (characteristic != null) {
                final byte[] data = characteristic.getValue();
                if (data == null || data.length < 1)
                    return null;
                return characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT8, 0);
            }
            return null;
        }

        public int getState() {
            return mConnectionState;
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //      Log.i("Debug", "?oncreate");
        initialize();
        mHandler = new Handler();
        mConnectionState = STATE_DISCONNECTED;
        //?????
        //12??
        timer.schedule(new TimerTask() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                if (mConnectionState == STATE_DISCONNECTED || mConnectionState == STATE_CONNECTING) {
                    outOfTime(1);
                }
            }
        }, 12000);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        if (mBluetoothGatt != null)
            mBluetoothGatt.disconnect();
        mHandler = null;
        mBluetoothDevice = null;
        timer.cancel();
    }

    @Override
    public IBinder onBind(final Intent intent) {
        return new ServiceBinder();
    }

    @Override
    public boolean onUnbind(final Intent intent) {
        // We want to allow rebinding
        return true;
    }

    @Override
    public int onStartCommand(final Intent intent, final int flags, final int startId) {
        mBluetoothDevice = intent.getParcelableExtra(EXTRA_DATA);
        return START_NOT_STICKY;
    }

    /**
     * Initializes a reference to the local Bluetooth adapter.
     */
    private void initialize() {
        errorSign = false;
        final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
        mAdapter = bluetoothManager.getAdapter();
    }

    private void setState(final int state) {
        mConnectionState = state;
        final Intent intent = new Intent(ACTION_STATE_CHANGED);
        intent.putExtra(EXTRA_DATA, state);
        //      Log.w(TAG, "" + state);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastRssiUpdate() {
        Log.w("broadcastRssiUpdate", " ");
        final Intent intent = new Intent(ACTION_RSSI_UPDATE_READY);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastUuid1Write(final UUID uuid) {
        final Intent intent = new Intent(ACTION_UUID1_WRITE_READY);
        intent.putExtra(EXTRA_DATA1, new ParcelUuid(uuid));
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastMajor1Write(final int major) {
        final Intent intent = new Intent(ACTION_MAJOR1_WRITE_READY);
        intent.putExtra(EXTRA_MAJOR1, major);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastMinor1Write(final int minor) {
        final Intent intent = new Intent(ACTION_MINOR1_WRITE_READY);
        intent.putExtra(EXTRA_MINOR1, minor);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastUuid2Write(final UUID uuid) {
        final Intent intent = new Intent(ACTION_UUID2_WRITE_READY);
        intent.putExtra(EXTRA_DATA2, new ParcelUuid(uuid));
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastMajor2Write(final int major) {
        final Intent intent = new Intent(ACTION_MAJOR2_WRITE_READY);
        intent.putExtra(EXTRA_MAJOR2, major);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastMinor2Write(final int minor) {
        final Intent intent = new Intent(ACTION_MINOR2_WRITE_READY);
        intent.putExtra(EXTRA_MINOR2, minor);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastRssiWrite(final int rssi) {
        final Intent intent = new Intent(ACTION_RSSI_WRITE_READY);
        intent.putExtra(EXTRA_DATA, rssi);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastResetWrite(final int reset) {
        final Intent intent = new Intent(ACTION_RESET_WRITE_READY);
        intent.putExtra(EXTRA_RESET, reset);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastTimerWrite(final int timer) {
        final Intent intent = new Intent(ACTION_TIMER_WRITE_READY);
        intent.putExtra(EXTRA_TIMER, timer);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastAdvertisingintervalWrite(final int advertisinginterval) {
        final Intent intent = new Intent(ACTION_ADVERTISINGINTERVAL_WRITE_READY);
        intent.putExtra(EXTRA_ADVERTISINGINTERVAL, advertisinginterval);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastTransmitpowerWrite(final int transmitpower) {
        final Intent intent = new Intent(ACTION_TRANSMITPOWER_WRITE_READY);
        intent.putExtra(EXTRA_TRANSMITPOWER, transmitpower);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastUuid1Read(final UUID uuid) {
        //      logw("broadcastUuid1Read: " + uuid.toString());
        final Intent intent = new Intent(ACTION_UUID1_READ_READY);
        intent.putExtra(EXTRA_DATA1, new ParcelUuid(uuid));
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastMajor1Read(final int major) {
        final Intent intent = new Intent(ACTION_MAJOR1_READ_READY);
        intent.putExtra(EXTRA_MAJOR1, major);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastMinor1Read(final int minor) {
        final Intent intent = new Intent(ACTION_MINOR1_READ_READY);
        intent.putExtra(EXTRA_MINOR1, minor);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastUuid2Read(final UUID uuid) {
        final Intent intent = new Intent(ACTION_UUID2_READ_READY);
        intent.putExtra(EXTRA_DATA2, new ParcelUuid(uuid));
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastMajor2Read(final int major) {
        final Intent intent = new Intent(ACTION_MAJOR2_READ_READY);
        intent.putExtra(EXTRA_MAJOR2, major);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastMinor2Read(final int minor) {
        final Intent intent = new Intent(ACTION_MINOR2_READ_READY);
        intent.putExtra(EXTRA_MINOR2, minor);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastRssiRead(final int rssi) {
        final Intent intent = new Intent(ACTION_RSSI_READ_READY);
        intent.putExtra(EXTRA_DATA, rssi);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastAdvertisingintervalRead(final int advertisinginterval) {
        final Intent intent = new Intent(ACTION_ADVERTISINGINTERVAL_READ_READY);
        intent.putExtra(EXTRA_ADVERTISINGINTERVAL, advertisinginterval);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastTransmitpowerRead(final int transmitpower) {
        final Intent intent = new Intent(ACTION_TRANSMITPOWER_READ_READY);
        intent.putExtra(EXTRA_TRANSMITPOWER, transmitpower);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastTimerRead(final int timer) {
        //      Log.w("broadcastTimerRead","timer:" + timer);
        final Intent intent = new Intent(ACTION_TIMER_READ_READY);
        intent.putExtra(EXTRA_TIMER, timer);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastResetRead(final int reset) {
        final Intent intent = new Intent(ACTION_RESET_READ_READY);
        intent.putExtra(EXTRA_RESET, reset);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastSoftReboot() {
        final Intent intent = new Intent(ACTION_SOFTREBOOT_READY);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastOperationCompleted() {
        final Intent intent = new Intent(ACTION_DONE);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void outOfTime(final int error) {
        //      Log.w(TAG, "?");
        final Intent intent = new Intent(ACTION_GATT_ERROR);
        intent.putExtra(EXTRA_DATA, error);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastError(final int error) {
        //????????
        if (!this.errorSign) {
            //         Log.w("Debug", "");
            this.errorSign = true;
            timer.cancel();
        } else {
            //         Log.w("Debug", "");
            return;
        }
        final Intent intent = new Intent(ACTION_GATT_ERROR);
        intent.putExtra(EXTRA_DATA, error);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

    }

    /**
     * Clears the device cache.
     * <p>
     * CAUTION:<br />
     * It is very unsafe to call the refresh() method. First of all it's hidden
     * so it may be removed in the future release of Android. We do it because
     * Nordic Beacon may advertise as a beacon, as Beacon Config or DFU. Android
     * does not clear cache then device is disconnected unless manually
     * restarted Bluetooth Adapter. To do this in the code we need to call
     * {@link BluetoothGatt#refresh()} method. However is may cause a lot of
     * troubles. Ideally it should be called before connection attempt but we
     * get 'gatt' object by calling connectGatt method so when the connection
     * already has been started. Calling refresh() afterwards causes errors 129
     * and 133 to pop up from time to time when refresh takes place actually
     * during service discovery. It seems to be asynchronous method. Therefore
     * we are refreshing the device after disconnecting from it, before closing
     * gatt. Sometimes you may obtain services from cache, not the actual values
     * so reconnection is required.
     * 
     * @param gatt
     *            the Bluetooth GATT object to refresh.
     */
    private boolean refreshDeviceCache(final BluetoothGatt gatt) {
        /*
         * There is a refresh() method in BluetoothGatt class but for now it's
         * hidden. We will call it using reflections.
         */
        try {
            final Method refresh = gatt.getClass().getMethod("refresh");
            if (refresh != null) {
                return (Boolean) refresh.invoke(gatt);
            }
        } catch (final Exception e) {
            loge("An exception occured while refreshing device");
        }
        return false;
    }

    private void loge(final String message) {
        if (BuildConfig.DEBUG)
            Log.e(TAG, message);
    }

    private void logw(final String message) {
        if (BuildConfig.DEBUG)
            Log.w(TAG, message);
    }

    public static int decodeUInt16(final BluetoothGattCharacteristic characteristic, final int offset) {
        final byte[] data = characteristic.getValue();
        return (unsignedByteToInt(data[offset]) << 8) | unsignedByteToInt(data[offset + 1]);
    }

    //static  
    public UUID decodeBeaconUUID(final BluetoothGattCharacteristic characteristic) {
        final byte[] data = characteristic.getValue();
        //      logw("Characteristic get value: " + data.length);            
        final long mostSigBits = (unsignedByteToLong(data[0]) << 56) + (unsignedByteToLong(data[1]) << 48)
                + (unsignedByteToLong(data[2]) << 40) + (unsignedByteToLong(data[3]) << 32)
                + (unsignedByteToLong(data[4]) << 24) + (unsignedByteToLong(data[5]) << 16)
                + (unsignedByteToLong(data[6]) << 8) + unsignedByteToLong(data[7]);
        //      logw("mostSigBits value: " + mostSigBits);
        final long leastSigBits = (unsignedByteToLong(data[8]) << 56) + (unsignedByteToLong(data[9]) << 48)
                + (unsignedByteToLong(data[10]) << 40) + (unsignedByteToLong(data[11]) << 32)
                + (unsignedByteToLong(data[12]) << 24) + (unsignedByteToLong(data[13]) << 16)
                + (unsignedByteToLong(data[14]) << 8) + unsignedByteToLong(data[15]);
        //      logw("leastSigBits value: " + leastSigBits);

        UUID uuid = new UUID(mostSigBits, leastSigBits);
        //      logw("UUID: " + uuid.toString());      
        return uuid;
    }

    /**
     * Convert a signed byte to an unsigned long.
     */
    public static long unsignedByteToLong(byte b) {
        return b & 0xFF;
    }

    /**
     * Convert a signed byte to an unsigned int.
     */
    public static int unsignedByteToInt(int b) {
        return b & 0xFF;
    }
}