content: package com.agenthun.bleecg.connectivity.ble;
  
  import android.Manifest;
  import android.app.Activity;
  import android.bluetooth.BluetoothAdapter;
  import android.bluetooth.BluetoothDevice;
  import android.bluetooth.BluetoothManager;
  import android.content.ComponentName;
  import android.content.Context;
  import android.content.Intent;
  import android.content.ServiceConnection;
  import android.content.pm.PackageManager;
  import android.os.Bundle;
  import android.os.Handler;
  import android.os.IBinder;
  import android.os.Message;
  import android.support.v4.app.ActivityCompat;
  import android.support.v4.content.ContextCompat;
  import android.util.Log;
  
  import java.io.Serializable;
  import java.util.ArrayList;
  import java.util.List;
  
  
  public class ACSUtility extends Object {
  
  
      private Context context;
      private Thread timerThread;
  
      private ArrayList<blePort> ports = null;
      private blePort currentPort = null;
      private int _lengthOfPackage = 10;
      private float _scanTime;
      private Boolean bScanning;
  
      private byte[] receivedBuffer;
  
      private boolean isInitializing = true;
  
  
      private final String TAG = "ACSUtility";
      private final int ACSUTILITY_SCAN_TIMEOUT_MSG = 0x01;
  
  
      private BluetoothAdapter mBtAdapter;
      //private  BluetoothGattAdapter 	mBtGattAdapter;
      //private  BluetoothGatt 	   		mBtGatt;
  
      private BluetoothDevice mDevice;
  
      private ACSUtilityService mService;
  
      private BluetoothManager bluetoothManager = null;
  
      private IACSUtilityCallback userCallback;
  
  
      public ACSUtility() {
          Log.d(TAG, "ACS Utility Constructor");
      }
  
      public ACSUtility(Context context, IACSUtilityCallback cb) {
          // TODO Auto-generated constructor stub
          this.context = context;
          userCallback = cb;
          _lengthOfPackage = 10;
          bScanning = false;
  
          Log.d(TAG, "acsUtility 1");
  
          bluetoothManager =
                  (BluetoothManager) context.getSystemService(context.BLUETOOTH_SERVICE);
          mBtAdapter = bluetoothManager.getAdapter();
          if (mBtAdapter == null) {
              Log.d(TAG, "error, mBtAdapter == null");
              return;
          }
  
          //after andrioid m, must request Permission on runtime
          getPermissions(context);
  
          //context.registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
          Intent intent = new Intent();
          intent.setClass(context, ACSUtilityService.class);
          context.startService(intent);
          context.bindService(intent, conn, Context.BIND_AUTO_CREATE);
      }
  
      private ServiceConnection conn = new ServiceConnection() {
  
          @Override
          public void onServiceConnected(ComponentName name, IBinder service) {
              // TODO Auto-generated method stub
              //mService = ((ACSBinder)service).getServie();
              Log.d(TAG, "ACSUtilityService is connected!");
              mService = ((ACSUtilityService.ACSBinder) service).getService();
              mService.initialize();
              mService.addEventHandler(eventHandler);
              //
              //ready to use
              userCallback.utilReadyForUse();
          }
  
          @Override
          public void onServiceDisconnected(ComponentName name) {
              // TODO Auto-generated method stub
              Log.d(TAG, "ACSUtilityService is disConnected!");
              mService = null;
          }
  
      };
      boolean mIsPortOpen = false;
      private Handler eventHandler = new Handler() {
  
          @Override
          public void handleMessage(Message msg) {
              // TODO Auto-generated method stub
              //super.handleMessage(msg);
              Log.e(TAG, "EventHandler got a message.flag is " + msg.what);
              if (userCallback == null) {
                  Log.e(TAG, "UserCallback is null! All event will not be handled!");
                  return;
              }
              switch (msg.what) {
                  case ACSUtilityService.EVENT_GATT_CONNECTED:
  
                      break;
                  case ACSUtilityService.EVENT_GATT_DISCONNECTED:
                      userCallback.didClosePort(currentPort);
                      mIsPortOpen = false;
                      break;
                  case ACSUtilityService.EVENT_GATT_SERVICES_DISCOVERED:
  
                      break;
  
                  case ACSUtilityService.EVENT_OPEN_PORT_SUCCEED:
  
                      userCallback.didOpenPort(currentPort, true);
                      mIsPortOpen = true;
                      break;
                  case ACSUtilityService.EVENT_OPEN_PORT_FAILED:
  
                      userCallback.didOpenPort(currentPort, false);
                      mIsPortOpen = true;
                      break;
                  case ACSUtilityService.EVENT_DATA_AVAILABLE:
                      Bundle data = msg.getData();
                      byte[] receivedData = data.getByteArray(ACSUtilityService.EXTRA_DATA);
                      userCallback.didPackageReceived(currentPort, receivedData);
                      break;
  
                  case ACSUtilityService.EVENT_HEART_BEAT_DEBUG:
  
                      userCallback.heartbeatDebug();
                      break;
  
                  case ACSUtilityService.EVENT_DATA_SEND_SUCEED:
                      //数据发送成功
                      userCallback.didPackageSended(true);
                      break;
                  case ACSUtilityService.EVENT_DATA_SEND_FAILED:
                      //数据发送失败
                      userCallback.didPackageSended(false);
                      break;
                  default:
                      break;
              }
          }
  
      };
  
      //串口枚举
      public void enumAllPorts(float time) {
          //UUID toFoundUUIDs[] = {ACS_SERVICE_UUID};
          ports = null;//清空缓冲区
          _scanTime = time;
          if (bScanning) {
              Log.e(TAG, "enum in progress,could not execute again");
              return;
          }
          Log.d(TAG, "start scan now");
          mBtAdapter.stopLeScan(mLeScanCallback);
          mBtAdapter.startLeScan(mLeScanCallback);
  
          //UUID []serviceUuids = {ACSUtilityService.ACS_SERVICE_UUID};
          //mBtAdapter.startLeScan(serviceUuids, mLeScanCallback);
          bScanning = true;
          //定时启动
          timerThread = new Thread(new myThread());
          timerThread.start();
  
      }
  
      public void setUserCallback(IACSUtilityCallback userCallback) {
          this.userCallback = userCallback;
      }
  
      public boolean isPortOpen(blePort port) {
  
  		/*if (mService != null && mService.mBluetoothGatt != null) {
              if (bluetoothManager.getConnectionState(port._device, BluetoothProfile.GATT) == BluetoothProfile.STATE_CONNECTED) {
  				
  				return true;
  			}
  		}
  		Log.e(TAG, "mService or mService.mBluetoothGatt is null.We can't know whether the port is opened.");
  		return false;*/
          return (mIsPortOpen && port._device.equals(currentPort._device)) ?
                  true : false;
  
      }
  
      private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
  
          @Override
          public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
              // TODO Auto-generated method stub
              Log.d(TAG, "onScanResult() - deviceName = " + device.getName()
                      + ", rssi=" + rssi + ",lengthOfScanRecord is : "
                      + scanRecord.length + ",address : " + device.getAddress());
  
              if (/* device.getName().equals("BDE_ACS_Module") */true) {
                  // Log.d(tag, "onScanResult() - device=" + device + ", rssi=" +
                  // rssi + ",lengthOfScanRecord is : "+ scanRecord.length);
                  // Log.d(tag, "found ACS Module");
                  //if (checkAddressExist(device)) {
                  // 同样设备的多个包
                  // Log.d(tag, "found same ACS Module");
                  //} else {
                  if (ports == null) {
                      ports = new ArrayList<ACSUtility.blePort>();
                  }
  
                  // 添加新端口
                  Log.d(TAG, "==== new Port add here ====");
                  blePort newPort = new blePort(device);
                  ports.add(newPort);
  
  /*                    if (device.getName().equals("BDE_SPP")) {
                          // 断点
                          int i = 0;
                          i++;
                      }*/
  
                  if (userCallback != null) {
                      userCallback.didFoundPort(newPort, rssi);
                  }
  
  					/*// 包解析
  
  					int flag;
  					int recordStart = 0;
  					int length = scanRecord[recordStart++];
  					while (length > 0) {
  						flag = scanRecord[recordStart++];
  						if (flag == 2 && scanRecord[recordStart++] == -80
  								&& scanRecord[recordStart++] == -1) {
  							if (userCallback != null) {
  								userCallback.didFoundPort(newPort);
  							}
  							break;
  						}
  						recordStart += (length - 1);
  						length = scanRecord[recordStart++];
  					}*/
  
                  //}
              }
          }
      };
  
      public void stopEnum() {
          bScanning = false;
          mBtAdapter.stopLeScan(mLeScanCallback);
      }
  
      //串口打开
      public void openPort(blePort port) {
  
          if (mService != null && port != null) {
              currentPort = port;
              mService.connect(port._device.getAddress());
          } else {
              Log.e(TAG, "ACSUtilityService or port is null!");
          }
  
      }
  
      public void closePort() {
          /*if (mBtGatt == null) {
              return;
  		}*/
  
          mService.disconnect();
  
      }
  
      public void configurePort(blePort port, int lenghOfPackage) {
          _lengthOfPackage = lenghOfPackage;
      }
  
      public boolean writePort(byte[] value) {
          if (value != null && mIsPortOpen) {
              return mService.writePort(value);
          }
          Log.e(TAG, "Write port failed...value is null...");
  
          return false;
      }
  
      public void closeACSUtility() {
          //BluetoothGattAdapter.closeProfileProxy(BluetoothGattAdapter.GATT, mBtGatt);
          mService.close();
          //closePort();
          mService.removeEventHandler();
          context.unbindService(conn);
          Intent intent = new Intent();
          intent.setClass(context, ACSUtilityService.class);
          context.stopService(intent);
      }
  
  
      //utility
      private void openPortFailAction() {
          if (userCallback != null) {
              userCallback.didOpenPort(currentPort, false);
          }
      }
  
      private void openPortSuccessAction() {
          if (userCallback != null) {
              userCallback.didOpenPort(currentPort, true);
          }
      }
  
      private String bytesToHexString(byte[] src) {
          StringBuilder stringBuilder = new StringBuilder("");
          if (src == null || src.length <= 0) {
              return null;
          }
          for (int i = 0; i < src.length; i++) {
              int v = src[i] & 0xFF;
              String hv = Integer.toHexString(v);
              if (hv.length() < 2) {
                  stringBuilder.append(0);
              }
              stringBuilder.append(hv);
          }
          stringBuilder.append('\n');
          return stringBuilder.toString();
      }
  
      //回调
      private Boolean checkAddressExist(BluetoothDevice device) {
          if (ports == null) {
              return false;
          }
          for (blePort port : ports) {
              if (port._device.getAddress().equals(device.getAddress())) {
                  return true;
              }
          }
          return false;
      }
  
      private void checkPackageToSend(byte[] newData) {
          if (receivedBuffer != null) {
              //上次接收了的但是没有处理的数据不为null，与这次接收的一块处理
              Log.d(TAG, "checkPachageToSend buffer length is " + receivedBuffer.length);
              int newLength = receivedBuffer.length + newData.length;
              byte[] tempBuffer = new byte[newLength];
              byteCopy(receivedBuffer, tempBuffer, 0, 0, receivedBuffer.length);
              byteCopy(newData, tempBuffer, 0, receivedBuffer.length, newData.length);
              receivedBuffer = null;
              receivedBuffer = tempBuffer;
          } else {
              Log.d(TAG, "checkPachageToSend buffer is null !");
              receivedBuffer = new byte[newData.length];
              byteCopy(newData, receivedBuffer, 0, 0, newData.length);
          }
  
          Log.d(TAG, "buffer lenght now is " + receivedBuffer.length);
          if (receivedBuffer.length >= _lengthOfPackage) {
              //比设定的一个包的长度要长
              byte[] packageToSend = new byte[_lengthOfPackage];
              //剩余内容
              byte[] tempBuffer = new byte[receivedBuffer.length - _lengthOfPackage];
              byteCopy(receivedBuffer, packageToSend, 0, 0, _lengthOfPackage);
              byteCopy(receivedBuffer, tempBuffer, _lengthOfPackage, 0, tempBuffer.length);
              receivedBuffer = null;
              receivedBuffer = tempBuffer;
              userCallback.didPackageReceived(currentPort, packageToSend);
              Log.d(TAG, "left length is " + receivedBuffer.length);
          }
      }
  
      private void byteCopy(byte[] from, byte[] to, int fromIndex, int toIndex, int length) {
          int realLength = (from.length < length) ? from.length : length;
          for (int i = 0; i < realLength; i++) {
              to[i + toIndex] = from[i + fromIndex];
          }
      }
  
  
      //线程定时类
      Handler handler = new Handler() {
          public void handleMessage(Message msg) {
              switch (msg.what) {
                  case ACSUTILITY_SCAN_TIMEOUT_MSG:
                      Log.d(TAG, "scan time out");
                      bScanning = false;
                      mBtAdapter.stopLeScan(mLeScanCallback);
                      if (userCallback != null)
                          userCallback.didFinishedEnumPorts();
                      break;
  
                  default:
                      break;
              }
              super.handleMessage(msg);
          }
      };
  
      private class myThread implements Runnable {
          @Override
          public void run() {
              //while (true) {
              try {
                  Thread.sleep((long) _scanTime * 1000);
                  if (bScanning) {
                      Message msg = new Message();
                      msg.what = ACSUTILITY_SCAN_TIMEOUT_MSG;
                      handler.sendMessage(msg);
                  }
              } catch (InterruptedException e) {
                  // TODO: handle exception
                  e.printStackTrace();
              }
              //}
          }
      }
  
      private void getPermissions(Context context) {
          List<String> permissions = new ArrayList<>();
  
          // 蓝牙权限必须开启ACCESS_COARSE_LOCATIO或ACCESS_FINE_LOCATION权限，用户如果禁止，则每次进入都会申请
          if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
              permissions.add(Manifest.permission.ACCESS_COARSE_LOCATION);
          }
          if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
              permissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
          }
  
          // 读写外设为必须权限，用户如果禁止，则每次进入都会申请
          if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
              permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
          }
          if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
              permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
          }
  
          if (permissions.size() > 0) {
              ActivityCompat.requestPermissions((Activity) context, permissions.toArray(new String[permissions.size()]), 127);
          }
      }
  
      //接口类，用于外部实现与交互
      public interface IACSUtilityCallback {
          public void utilReadyForUse();
  
          //public void utilreadyForUse();
          public void didFoundPort(blePort newPort, int rssi);
  
          public void didFinishedEnumPorts();
  
          public void didOpenPort(blePort port, Boolean bSuccess);
  
          public void didClosePort(blePort port);
  
          public void didPackageSended(boolean succeed);
  
          public void didPackageReceived(blePort port, byte[] packageToSend);
  
          public void heartbeatDebug();
      }
  
      //Port类
      public class blePort implements Serializable {
          public BluetoothDevice _device;
  
          public blePort(BluetoothDevice device) {
              _device = device;
          }
      }
  
      //debug function
      public void printHexString(byte[] b) {
          for (int i = 0; i < b.length; i++) {
              String hex = Integer.toHexString(b[i] & 0xFF);
              if (hex.length() == 1) {
                  hex = '0' + hex;
              }
              Log.d(TAG, hex);
          }
      }
  }
  
  