Full Code of LuoPeiQin/Bluetooth for AI

master 93eb7ea6e843 cached
123 files
435.5 KB
120.6k tokens
805 symbols
1 requests
Download .txt
Showing preview only (486K chars total). Download the full file or copy to clipboard to get everything.
Repository: LuoPeiQin/Bluetooth
Branch: master
Commit: 93eb7ea6e843
Files: 123
Total size: 435.5 KB

Directory structure:
gitextract_042z6ibk/

├── .gitignore
├── .idea/
│   ├── codeStyles/
│   │   └── Project.xml
│   ├── compiler.xml
│   ├── gradle.xml
│   ├── jarRepositories.xml
│   ├── misc.xml
│   └── vcs.xml
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── luo/
│       │               └── bluetooth/
│       │                   └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── luo/
│       │   │           └── bluetooth/
│       │   │               ├── MainActivity.java
│       │   │               ├── MyApplication.java
│       │   │               ├── base/
│       │   │               │   └── BaseActivity.java
│       │   │               ├── common/
│       │   │               │   └── Constants.java
│       │   │               ├── customview/
│       │   │               │   └── searchble/
│       │   │               │       ├── BluetoothDeviceAdapter.java
│       │   │               │       ├── BluetoothDeviceBean.java
│       │   │               │       ├── ColorUtils.java
│       │   │               │       ├── DeviceListActivity.java
│       │   │               │       ├── Effectstype.java
│       │   │               │       ├── NiftyDialogBuilder.java
│       │   │               │       ├── SignalView.java
│       │   │               │       └── effects/
│       │   │               │           ├── BaseEffects.java
│       │   │               │           ├── FadeIn.java
│       │   │               │           ├── Fall.java
│       │   │               │           ├── FlipH.java
│       │   │               │           ├── FlipV.java
│       │   │               │           ├── NewsPaper.java
│       │   │               │           ├── RotateBottom.java
│       │   │               │           ├── RotateLeft.java
│       │   │               │           ├── Shake.java
│       │   │               │           ├── SideFall.java
│       │   │               │           ├── SlideBottom.java
│       │   │               │           ├── SlideLeft.java
│       │   │               │           ├── SlideRight.java
│       │   │               │           ├── SlideTop.java
│       │   │               │           └── Slit.java
│       │   │               ├── encryption/
│       │   │               │   ├── Aes.java
│       │   │               │   └── CRC.java
│       │   │               ├── protocol/
│       │   │               │   ├── CRC16Utils.java
│       │   │               │   ├── CrcUtils.java
│       │   │               │   ├── CustomEventListener.java
│       │   │               │   ├── CustomPacket.java
│       │   │               │   ├── CustomProtocol.java
│       │   │               │   ├── OnTimeoutResult.java
│       │   │               │   ├── WeiCeCode.java
│       │   │               │   └── WeiCeDeviceOperate.java
│       │   │               └── utils/
│       │   │                   ├── ByteUtils.java
│       │   │                   ├── DateUtils.java
│       │   │                   ├── DialogUtils.java
│       │   │                   ├── GpsUtils.java
│       │   │                   ├── GsonUtils.java
│       │   │                   ├── LogUtils.java
│       │   │                   ├── TextUtils.java
│       │   │                   └── ToastUtil.java
│       │   └── res/
│       │       ├── anim/
│       │       │   ├── fade_in.xml
│       │       │   └── fade_out.xml
│       │       ├── drawable/
│       │       │   ├── btn_press.xml
│       │       │   ├── btn_selector.xml
│       │       │   ├── btn_unpress.xml
│       │       │   ├── dialog_bg.xml
│       │       │   ├── ic_launcher_background.xml
│       │       │   └── sel_white_gray.xml
│       │       ├── drawable-v24/
│       │       │   └── ic_launcher_foreground.xml
│       │       ├── layout/
│       │       │   ├── activity_main.xml
│       │       │   ├── activity_search_device_list.xml
│       │       │   ├── dialog_layout.xml
│       │       │   └── item_bluetooth_device_list.xml
│       │       ├── mipmap-anydpi-v26/
│       │       │   ├── ic_launcher.xml
│       │       │   └── ic_launcher_round.xml
│       │       └── values/
│       │           ├── attrs.xml
│       │           ├── colors.xml
│       │           ├── strings.xml
│       │           └── styles.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── luo/
│                       └── bluetooth/
│                           └── ExampleUnitTest.java
├── bluetooth/
│   ├── .gitignore
│   ├── build.gradle
│   ├── libs/
│   │   ├── com.broadcom.bt.jar
│   │   └── samsung_ble_sdk_200.jar
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── stag/
│       │               └── bluetooth/
│       │                   └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── stag/
│       │   │           └── bluetooth/
│       │   │               ├── BluetoothController.java
│       │   │               ├── BluetoothDispatch.java
│       │   │               ├── BluetoothTask.java
│       │   │               ├── BluetoothTransfer.java
│       │   │               ├── OnBluetoothConnectStateChangeListener.java
│       │   │               ├── OnBluetoothScanListener.java
│       │   │               ├── OnBluetoothStateChangeListener.java
│       │   │               ├── OnBluetoothTransmitListener.java
│       │   │               ├── extend/
│       │   │               │   ├── AndroidBle.java
│       │   │               │   ├── BleGattCharacteristic.java
│       │   │               │   ├── BleGattService.java
│       │   │               │   ├── BleRequest.java
│       │   │               │   ├── BleService.java
│       │   │               │   ├── BroadcomBle.java
│       │   │               │   ├── IBle.java
│       │   │               │   ├── IBleRequestHandler.java
│       │   │               │   └── SamsungBle.java
│       │   │               ├── helper/
│       │   │               │   ├── BleHelper.java
│       │   │               │   ├── BluetoothHelper.java
│       │   │               │   ├── MyBluetoothService.java
│       │   │               │   ├── TraditionHelper.java
│       │   │               │   └── TraditionServerHelper.java
│       │   │               ├── packet/
│       │   │               │   └── Packet.java
│       │   │               ├── protocol/
│       │   │               │   ├── OnEventListener.java
│       │   │               │   ├── ParseResult.java
│       │   │               │   ├── Protocol.java
│       │   │               │   └── ResultType.java
│       │   │               └── util/
│       │   │                   ├── ByteUtils.java
│       │   │                   ├── LogUtils.java
│       │   │                   └── Logs.java
│       │   └── res/
│       │       └── values/
│       │           └── strings.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── stag/
│                       └── bluetooth/
│                           └── ExampleUnitTest.java
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx


================================================
FILE: .idea/codeStyles/Project.xml
================================================
<component name="ProjectCodeStyleConfiguration">
  <code_scheme name="Project" version="173">
    <codeStyleSettings language="XML">
      <indentOptions>
        <option name="CONTINUATION_INDENT_SIZE" value="4" />
      </indentOptions>
      <arrangement>
        <rules>
          <section>
            <rule>
              <match>
                <AND>
                  <NAME>xmlns:android</NAME>
                  <XML_ATTRIBUTE />
                  <XML_NAMESPACE>^$</XML_NAMESPACE>
                </AND>
              </match>
            </rule>
          </section>
          <section>
            <rule>
              <match>
                <AND>
                  <NAME>xmlns:.*</NAME>
                  <XML_ATTRIBUTE />
                  <XML_NAMESPACE>^$</XML_NAMESPACE>
                </AND>
              </match>
              <order>BY_NAME</order>
            </rule>
          </section>
          <section>
            <rule>
              <match>
                <AND>
                  <NAME>.*:id</NAME>
                  <XML_ATTRIBUTE />
                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
                </AND>
              </match>
            </rule>
          </section>
          <section>
            <rule>
              <match>
                <AND>
                  <NAME>.*:name</NAME>
                  <XML_ATTRIBUTE />
                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
                </AND>
              </match>
            </rule>
          </section>
          <section>
            <rule>
              <match>
                <AND>
                  <NAME>name</NAME>
                  <XML_ATTRIBUTE />
                  <XML_NAMESPACE>^$</XML_NAMESPACE>
                </AND>
              </match>
            </rule>
          </section>
          <section>
            <rule>
              <match>
                <AND>
                  <NAME>style</NAME>
                  <XML_ATTRIBUTE />
                  <XML_NAMESPACE>^$</XML_NAMESPACE>
                </AND>
              </match>
            </rule>
          </section>
          <section>
            <rule>
              <match>
                <AND>
                  <NAME>.*</NAME>
                  <XML_ATTRIBUTE />
                  <XML_NAMESPACE>^$</XML_NAMESPACE>
                </AND>
              </match>
              <order>BY_NAME</order>
            </rule>
          </section>
          <section>
            <rule>
              <match>
                <AND>
                  <NAME>.*</NAME>
                  <XML_ATTRIBUTE />
                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
                </AND>
              </match>
              <order>ANDROID_ATTRIBUTE_ORDER</order>
            </rule>
          </section>
          <section>
            <rule>
              <match>
                <AND>
                  <NAME>.*</NAME>
                  <XML_ATTRIBUTE />
                  <XML_NAMESPACE>.*</XML_NAMESPACE>
                </AND>
              </match>
              <order>BY_NAME</order>
            </rule>
          </section>
        </rules>
      </arrangement>
    </codeStyleSettings>
  </code_scheme>
</component>

================================================
FILE: .idea/compiler.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="CompilerConfiguration">
    <annotationProcessing>
      <profile default="true" name="Default" enabled="true" />
    </annotationProcessing>
    <bytecodeTargetLevel target="1.8" />
  </component>
</project>

================================================
FILE: .idea/gradle.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="GradleMigrationSettings" migrationVersion="1" />
  <component name="GradleSettings">
    <option name="linkedExternalProjectsSettings">
      <GradleProjectSettings>
        <option name="testRunner" value="GRADLE" />
        <option name="distributionType" value="DEFAULT_WRAPPED" />
        <option name="externalProjectPath" value="$PROJECT_DIR$" />
        <option name="modules">
          <set>
            <option value="$PROJECT_DIR$" />
            <option value="$PROJECT_DIR$/app" />
            <option value="$PROJECT_DIR$/bluetooth" />
          </set>
        </option>
        <option name="resolveModulePerSourceSet" value="false" />
      </GradleProjectSettings>
    </option>
  </component>
</project>

================================================
FILE: .idea/jarRepositories.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="RemoteRepositoriesConfiguration">
    <remote-repository>
      <option name="id" value="central" />
      <option name="name" value="Maven Central repository" />
      <option name="url" value="https://repo1.maven.org/maven2" />
    </remote-repository>
    <remote-repository>
      <option name="id" value="jboss.community" />
      <option name="name" value="JBoss Community repository" />
      <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
    </remote-repository>
    <remote-repository>
      <option name="id" value="BintrayJCenter" />
      <option name="name" value="BintrayJCenter" />
      <option name="url" value="https://jcenter.bintray.com/" />
    </remote-repository>
    <remote-repository>
      <option name="id" value="Google" />
      <option name="name" value="Google" />
      <option name="url" value="https://dl.google.com/dl/android/maven2/" />
    </remote-repository>
  </component>
</project>

================================================
FILE: .idea/misc.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
    <output url="file://$PROJECT_DIR$/build/classes" />
  </component>
  <component name="ProjectType">
    <option name="id" value="Android" />
  </component>
</project>

================================================
FILE: .idea/vcs.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="VcsDirectoryMappings">
    <mapping directory="$PROJECT_DIR$" vcs="Git" />
  </component>
</project>

================================================
FILE: README.md
================================================
<img src="https://github.com/LuoPeiQin/Bluetooth/blob/master/app/src/main/res/mipmap-xhdpi/logo.png" width="20%">

# Bluetooth
## 该库的特点

1. 内部集成了多种蓝牙芯片的操作,能兼容几乎市面上所有的蓝牙设备;
2. 支持低功耗蓝牙和传统蓝牙;
3. 支持设置低功耗蓝牙的高速传输模式;
4. 实现了蓝牙的重发机制;
5. 实现了蓝牙的同异步发送数据;
6. 实现了协议基类封装,开发者可以快速扩展自己的协议;

**注意:部分Android6.0以上的手机需要定位权限才能正常使用蓝牙功能**

## 库地址
[ ![Download](https://api.bintray.com/packages/luopeiqin/maven/bluetooth/images/download.svg?version=1.0.2) ](https://bintray.com/luopeiqin/maven/bluetooth/1.0.2/link)
```
implementation 'com.stag:bluetooth:1.0.2'
```
## 蓝牙搜索自定义View
项目中增加了蓝牙搜素的自定义View,方便你快速的实现项目
### 自定义View包含的内容
1. 根据蓝牙的信号强度排序和显示;
2. 有搜素或连接的历史记录功能(做小部分配置即可实现);
<img src="https://github.com/LuoPeiQin/Bluetooth/blob/master/%E7%A4%BA%E4%BE%8B1.jpg" width="50%">

## 蓝牙基本操作相关接口说明

> **调用的类为com.stag.bluetooth.BluetoothControl.java**

### 获取单例对象

```java
BluetoothController mController = BluetoothController.getController(this);
```

### 注册蓝牙状态监听

```java
mController.registerBluetoothStateChangeListener(new OnBluetoothStateChangeListener() {
    @Override
    public void onBluetoothOpen() {
	LogUtils.i(TAG + "lpq", "onBluetoothOpen: 蓝牙打开");
    }

    @Override
    public void onBluetoothClose() {
	LogUtils.i(TAG + "lpq", "onBluetoothClose: 蓝牙关闭");
    }
});
```

### 注册蓝牙连接状态变化监听

```java
mController.registerConnectStateChangeListener(new OnBluetoothConnectStateChangeListener() {
    @Override
    public void onBluetoothConnect(BluetoothDevice device, boolean isSuccess) {
	if (isSuccess) {
	    LogUtils.i(TAG + "lpq", "onBluetoothConnect: 蓝牙已连接");
	} else {
	    LogUtils.i(TAG + "lpq", "onBluetoothConnect: 蓝牙连接失败");
	}
    }

    @Override
    public void onBluetoothDisconnect(BluetoothDevice device) {
	LogUtils.i(TAG + "lpq", "onBluetoothDisconnect: 蓝牙已断开");
    }
});
```

### 切换蓝牙类型

```java
mController.setBluetoothType(BluetoothType.BLE); // 低功耗蓝牙
mController.setBluetoothType(BluetoothType.TRADITION); // 传统蓝牙
```

### 搜索蓝牙

```java
mController.startScan(new OnBluetoothScanListener() {
    @Override
    public void onBluetoothScanFindDevice(BluetoothDevice device, int rssi) {
	LogUtils.i(TAG + "lpq", "onBluetoothScanFindDevice: " + device.getAddress());
    }

    @Override
    public void onBluetoothScanFinish() {
	LogUtils.i(TAG + "lpq", "onBluetoothScanFinish: ");
    }
});
```

### 停止搜索蓝牙

```java
mController.stopScan();
```

### 连接蓝牙与断开蓝牙连接

```java
mController.connect("0C:B2:B7:3E:23:60");	//连接蓝牙,参数为蓝牙MAC地址
mController.disconnect();	//断开连接
```

### 低功耗蓝牙时开启高速模式

```java
mController.setBleHighSpeedMode(true);
```

不一定100%成功,由蓝牙设备与App设备蓝牙的最低MTU决定。

### 取消注册监听回调

```java
@Override
protected void onDestroy() {
	super.onDestroy();
	if (mController != null) {
	    mController.unregisterBluetoothStateChangeListener();
	    mController.unregisterConnectStateChangeListener();
	}
}
```

## 蓝牙收发数据重点说明

### 方式一:继承蓝牙内置协议

```java
public abstract class Protocol<E extends Packet, T extends OnEventListener> {
    public final static int BLE_MAX_SEND_INTERVAL = 500;
    protected Context mContext;
    private T mEventListener;
    private Object mData;
    private int mMaxBleSendInterval = BLE_MAX_SEND_INTERVAL;

    /**
     * 协议所特有的主动事件监听
     */
    protected Protocol(Context context) {
        this(context, null);
    }

    /**
     * 协议所特有的主动事件监听
     */
    protected Protocol(Context context, T listener) {
        mContext = context.getApplicationContext();
        mEventListener = listener;
    }

    /**
     * 发送包处理成最终要发送的字节数据
     */
    public abstract byte[] packetToBytes(E packet);

    /**
     * 解析收到的字节处理成结果
     */
    public abstract ParseResult parse(byte[] data);

    /**
     * 获取协议类型
     * */
    public abstract int getType();

    /**
     * 是否设置了主动事件监听
     * */
    protected boolean haveSetEventListener(){
        return mEventListener!=null;
    }
	······
}
```

#### 内置协议简要说明

上述抽象类中屏蔽了部分内容,我们主要看几个重点:

1. **packetToBytes** 和 **parse**是用户层面发送数据的最终端和接收数据的最初端,您可以根据自己蓝牙协议的需要来重写方法,创建自己的协议类;
2. **getType**是用来支持App需要同时支持多个蓝牙协议的情况的;
3. **mEventListener**用于接收蓝牙设备主动上报的一些状态;

#### 设置蓝牙传输协议

> 该方法是与蓝牙设备操作相关的方法,而且必须在连接蓝牙设备之前设置

```java
mController.setProtocol(new Protocol(this, this));
```

#### 创建异步发送数据任务

```java
BluetoothTask task = new BluetoothTask(new Packet(cmd, data), new BluetoothTask.OnDataResultListener() {
            @Override
            public void onResult(boolean isTimeout, byte[] data) {
                //数据接收回调,异步时使用
            }
        });       
task.setTimeout(2000);	//设置超时时间
task.setTryCount(1);	//设置重发次数
task.send(); 	//异步发送数据
```

#### 创建同步发送数据任务

```java
BluetoothTask task = new BluetoothTask(new Packet(cmd, data));
task.setTimeout(2000);	//设置超时时间
task.setTryCount(1);	//设置重发次数
byte[] result = task.sendBySync2();	//同步发送数据
```

### 方式二:原始数据收发

如果方式一没有办法满足你的要求,那么我也提供方式二来供你选择

#### 设置原始数据收发监听

```java
    mController.registerTransmitListener(new OnBluetoothTransmitListener() {
        @Override
        public void onBluetoothSendData(byte[] data) {
            // 发送数据
        }

        @Override
        public void onBluetoothRecvData(byte[] data) {
            // 接收数据
        }
    });
```

#### 发送数据

```java
mController.sendData(new byte[]{});
```


================================================
FILE: app/.gitignore
================================================
/build


================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'
apply plugin: 'bugly'

bugly {
    appId = '4efc7ff5d2' // 注册时分配的App ID
    appKey = '' // 注册时分配的App Key
}

android {
    signingConfigs {
        release {
        }
    }
    compileSdkVersion 29
    buildToolsVersion "29.0.3"

    defaultConfig {
        applicationId "com.luo.bluetooth"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 3
        versionName "1.0.2"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled true // 启用混淆
            zipAlignEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
        }
    }

    compileOptions{
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    android.applicationVariants.all { variant ->
        variant.outputs.all {
            outputFileName = "Bluetooth_${defaultConfig.versionName}.apk"
        }
    }
}

repositories{
    flatDir{
        dirs 'libs'
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation project(path: ':bluetooth')

    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    // 注解类
    implementation 'org.projectlombok:lombok:1.18.12'
    android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true
    // UI
    implementation 'com.github.f0ris.sweetalert:library:1.5.1'
    implementation 'androidx.cardview:cardview:1.0.0'
    // 网络
    implementation 'com.squareup.retrofit2:converter-gson:2.8.0'
    implementation 'com.squareup.retrofit2:retrofit:2.8.1'
    implementation 'com.squareup.okhttp3:logging-interceptor:3.14.1'
    // 工具类
    implementation 'com.blankj:utilcodex:1.28.0'
    // Bugly
    implementation 'com.tencent.bugly:crashreport_upgrade:latest.release'
}


================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
# 代码混淆压缩比,在0~7之间,默认为5,一般不做修改
-optimizationpasses 5

# 混合时不使用大小写混合,混合后的类名为小写
-dontusemixedcaseclassnames

# 指定不去忽略非公共库的类
-dontskipnonpubliclibraryclasses

# 指定不去忽略非公共库的类成员
-dontskipnonpubliclibraryclassmembers

# 这句话能够使我们的项目混淆后产生映射文件
# 包含有类名->混淆后类名的映射关系
-verbose

# 不做预校验,preverify是proguard的四个步骤之一,Android不需要preverify,去掉这一步能够加快混淆速度。
-dontpreverify

# 保留Annotation不混淆 这在JSON实体映射时非常重要,比如fastJson
-keepattributes *Annotation*,InnerClasses

# 避免混淆泛型
-keepattributes Signature

# 抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable

# 指定混淆是采用的算法,后面的参数是一个过滤器
# 这个过滤器是谷歌推荐的算法,一般不做更改
-optimizations !code/simplification/cast,!field/*,!class/merging/*

# 忽略警告
-ignorewarnings

# 设置是否允许改变作用域
-allowaccessmodification

# 把混淆类中的方法名也混淆了
-useuniqueclassmembernames

# apk 包内所有 class 的内部结构
-dump class_files.txt

# 未混淆的类和成员
#-printseeds seeds_txt

# 列出从apk中删除的代码
#-printusage unused.txt

#保持源码的行号、源文件信息不被混淆 方便在崩溃日志中查看
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable

# 四大组件不能混淆,四大组件必须在 manifest 中注册声明
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgent
-keep public class * extends android.preference.Preference
-keep public class * extends android.support.v4.app.Fragment
-keep public class * extends android.app.Fragment
-keep public class * extends android.view.view
-keep public class com.android.vending.licensing.ILicensingService

# 不能混淆枚举中的value和valueOf方法
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# 不混淆bean类
-keep class com.luo.bluetooth.blebean.** {*;}
-keep class com.luo.bluetooth.netbean.** {*;}

# gson
-keep class com.google.gson.** {*;}
-keep class sun.misc.Unsafe {*;}
-keep class com.google.gson.stream.** {*;}
-keep class com.google.gson.examples.android.model.** {*;}
-keep class com.google.** {
    <fields>;
    <methods>;
}
-dontwarn com.google.gson.**

# Bugly
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
-keep class android.support.**{*;}

#ddi
    -keep class com.xinguodu.ddiinterface.**{*;}
    #SmartPOSJni
        -keep class com.nexgo.oaf.smartpos.jni.SmartPOSJni{*;}
    #API
        -keep class com.nexgo.oaf.smartpos.CardAPI {*;}
        -keep class com.nexgo.oaf.smartpos.DeviceAPI {*;}
        -keep class com.nexgo.oaf.smartpos.KeyAPI {*;}
        -keep class com.nexgo.oaf.smartpos.OtherAPI {*;}
        -keep class com.nexgo.oaf.smartpos.PeripheralAPI {*;}
    #DeviceEngineImpl
        -keep class com.nexgo.oaf.smartpos.apiv3.DeviceEngineImpl {*;}
        -keep class com.nexgo.oaf.apiv3.DeviceInfo {*;}

-keep class cn.pedant.** { *; }


================================================
FILE: app/src/androidTest/java/com/luo/bluetooth/ExampleInstrumentedTest.java
================================================
package com.luo.bluetooth;

import android.content.Context;

import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.*;

/**
 * Instrumented test, which will execute on an Android device.
 *
 * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
 */
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
    @Test
    public void useAppContext() {
        // Context of the app under test.
        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();

        assertEquals("com.luo.bluetooth", appContext.getPackageName());
    }
}


================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.luo.bluetooth">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <!-- If your app targets Android 9 or lower, you can declare
         ACCESS_COARSE_LOCATION instead. -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

    <!--  Bugly权限  -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.READ_LOGS" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

    <application
        android:name="com.luo.bluetooth.MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/logo"
        android:label="@string/app_name"
        android:supportsRtl="true"
        tools:replace="android:icon"
        android:theme="@style/AppTheme">
        <activity android:name="com.luo.bluetooth.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.luo.bluetooth.customview.searchble.DeviceListActivity"
            android:launchMode="singleTask"
            android:theme="@style/DialogTheme.TransparentNoTitle" />
        <activity
            android:name="com.tencent.bugly.beta.ui.BetaActivity"
            android:configChanges="keyboardHidden|orientation|screenSize|locale"
            android:theme="@android:style/Theme.Translucent" />

    </application>

</manifest>

================================================
FILE: app/src/main/java/com/luo/bluetooth/MainActivity.java
================================================
package com.luo.bluetooth;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import com.luo.bluetooth.customview.searchble.BluetoothDeviceBean;
import com.luo.bluetooth.customview.searchble.DeviceListActivity;
import com.luo.bluetooth.protocol.CustomPacket;
import com.luo.bluetooth.protocol.CustomProtocol;
import com.luo.bluetooth.protocol.OnTimeoutResult;
import com.luo.bluetooth.protocol.WeiCeCode;
import com.luo.bluetooth.protocol.WeiCeDeviceOperate;
import com.luo.bluetooth.utils.ByteUtils;
import com.luo.bluetooth.utils.DialogUtils;
import com.luo.bluetooth.utils.GpsUtils;
import com.luo.bluetooth.utils.LogUtils;
import com.luo.bluetooth.utils.ToastUtil;
import com.stag.bluetooth.BluetoothController;
import com.stag.bluetooth.OnBluetoothConnectStateChangeListener;
import com.stag.bluetooth.OnBluetoothStateChangeListener;

import java.nio.charset.StandardCharsets;

import cn.pedant.SweetAlert.SweetAlertDialog;

public class MainActivity extends AppCompatActivity implements OnBluetoothStateChangeListener, OnBluetoothConnectStateChangeListener {
    private static final String TAG = "MainActivity";
    private static final int QUEST_BLUETOOTH_DEVICE = 1;

    private TextView appVersion;
    private TextView bleStatus;
    private TextView bleConnectStatus;
    // 蓝牙相关
    public static BluetoothDeviceBean mDeviceModel;
    public BluetoothController mBluetoothController;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initBluetooth();
    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    public void onDestroy() {
        if (mBluetoothController != null) {
            mBluetoothController.setProtocol(null);
            mBluetoothController.unregisterBluetoothStateChangeListener();
            mBluetoothController.unregisterConnectStateChangeListener();
            mBluetoothController.disconnect();
            mBluetoothController.stopScan();
        }
        DialogUtils.dismissDialog();
        super.onDestroy();
    }

    private void initView() {
        appVersion = findViewById(R.id.app_version);
        bleStatus = findViewById(R.id.ble_status);
        bleConnectStatus = findViewById(R.id.ble_connect_status);
        appVersion.setText("" + BuildConfig.VERSION_NAME + " - " + BuildConfig.VERSION_CODE);
    }

    /**
     * 初始化蓝牙框架
     */
    private void initBluetooth() {
        mBluetoothController = BluetoothController.getController(this);
        mBluetoothController.registerBluetoothStateChangeListener(this);
        mBluetoothController.registerConnectStateChangeListener(this);
        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (bluetoothAdapter == null) {
            LogUtils.d(TAG + "lpq", "initBluetooth: 该设备不支持蓝牙");
            ToastUtil.showShort(this, "该设备不支持蓝牙!无法正常使用");
            return;
        }
        if (!bluetoothAdapter.isEnabled()) {
            bleStatus.setText("已关闭");
            bluetoothAdapter.enable();
        } else {
            bleStatus.setText("已打开");
        }
        /**
         * 可以选择作为客户端搜索传统蓝牙,低功耗蓝牙
         * 或者作为传统蓝牙服务端
         */
        mBluetoothController.setBluetoothType(BluetoothController.TYPE_BLE);
    }

    /**
     * 搜索和连接蓝牙
     *
     * @param view
     */
    public void btnSearchBle(View view) {
        if (!GpsUtils.isOPen(this)) {
            DialogUtils.showNormalDialog(this, "提示", "为保证初始化功能的正常使用,请开启定位功能", new SweetAlertDialog.OnSweetClickListener() {
                @Override
                public void onClick(SweetAlertDialog sweetAlertDialog) {
                    DialogUtils.dismissDialog();
                    Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                    startActivity(intent);
                }
            });
            return;
        }
        if (mBluetoothController.isConnected()) {
            mBluetoothController.disconnect();
        } else {
            Intent deviceIntent = new Intent(this, DeviceListActivity.class);
            startActivityForResult(deviceIntent, QUEST_BLUETOOTH_DEVICE);
        }
    }

    /**
     * 使用mac地址连接蓝牙
     *
     * @param view
     */
    public void btnMacConnect(View view) {
        mBluetoothController.connect("40:C8:1F:6A:CD:2B", new CustomProtocol(this, null));
    }

    /**
     * 断开蓝牙
     */
    public void btnDisconnectBle(View view) {
        LogUtils.d(TAG + "lpq", "btnDisconnectBle: ");
        if (mBluetoothController.isConnected()) {
            mBluetoothController.disconnect();
        } else {
            mBluetoothController.stopScan();
        }
    }

    /**
     * 蓝牙搜索结果
     *
     * @param requestCode
     * @param resultCode
     * @param data
     */
    @Override
    public void onActivityResult(int requestCode, int resultCode, final Intent data) {
        if (resultCode != RESULT_OK) {
            return;
        }
        mDeviceModel = (BluetoothDeviceBean) data.getSerializableExtra(DeviceListActivity.KEY_SCAN_DEVICE);
        LogUtils.d(TAG + "lpq", "onActivityResult: " + mDeviceModel.toString());
        String deviceName = mDeviceModel.getDeviceName();
        if (deviceName != null) {
            if (mDeviceModel.isBle()) {
                mBluetoothController.setBluetoothType(BluetoothController.TYPE_BLE);
            } else {
                mBluetoothController.setBluetoothType(BluetoothController.TYPE_TRADITION);
            }
            mBluetoothController.setProtocol(new CustomProtocol(this, null));
            mBluetoothController.connect(mDeviceModel.getDeviceAddress());
        } else {
            ToastUtil.showShort(this, "蓝牙名称为空,请重试");
        }
    }

    /********************************* 蓝牙监听回调 *************************************/

    @Override
    public void onBluetoothOpen() {
        LogUtils.d(TAG + "lpq", "onBluetoothOpen: 蓝牙已打开");
        bleStatus.setText("已打开");
    }

    @Override
    public void onBluetoothClose() {
        LogUtils.d(TAG + "lpq", "onBluetoothClose: 蓝牙已关闭");
        bleStatus.setText("已关闭");
    }

    /**
     * 蓝牙连接事件回调
     *
     * @param device    蓝牙设备
     * @param isSuccess 是否成功
     */
    @Override
    public void onBluetoothConnect(BluetoothDevice device, boolean isSuccess) {
        LogUtils.d(TAG + "lpq", "onBluetoothConnect: 蓝牙连接结果:" + isSuccess);
        if (isSuccess) {
            bleConnectStatus.setText("已连接");
            mBluetoothController.setProtocol(new CustomProtocol(this, null));
        } else {
            bleConnectStatus.setText("未连接");
        }
    }

    /**
     * 蓝牙断开连接事件回调
     *
     * @param device 蓝牙设备
     */
    @Override
    public void onBluetoothDisconnect(BluetoothDevice device) {
        bleConnectStatus.setText("未连接");
    }

    /**
     * 协议解析测试
     *
     * @param view
     */
    public void btnProtocolParse(View view) {
        LogUtils.d(TAG + "lpq", "btnProtocolParse: 蓝牙协议解析测试");
        CustomProtocol customProtocol = new CustomProtocol(this, null);
        String a1String = "02413130313139323032303";
        byte[] bytes = ByteUtils.hexStringToBytes(a1String);
        LogUtils.d(TAG + "lpq", "btnProtocolParse: bytes = " + ByteUtils.toString(bytes, ""));
        customProtocol.parse(bytes);
    }

    /**
     * 协议打包测试
     *
     * @param view
     */
    public void btnProtocolPacket(View view) {
        LogUtils.d(TAG + "lpq", "btnProtocolParse: 蓝牙协议解析测试");
        CustomProtocol customProtocol = new CustomProtocol(this, null);
        byte[] sendBytes = "00".getBytes(StandardCharsets.US_ASCII);
        LogUtils.d(TAG + "lpq", "confirm: sendBytes = " + ByteUtils.toString(sendBytes));
        new CustomProtocol(this, null).packetToBytes(new CustomPacket(0x01 /* 命令码 */, sendBytes, WeiCeCode.EXPAND_CODE_READ));
    }

    /**
     * 发送简单数据
     * 这个不会走封装好的协议
     *
     * @param view
     */
    public void btnSendConfirmData(View view) {
        WeiCeDeviceOperate.getSn(new OnTimeoutResult<String>() {
            @Override
            public void onResult(boolean isTimeout, String result) {
                Log.i("lpq", "onResult: isTimeout = " + isTimeout);
                Log.i("lpq", "onResult: sn = " + result);
            }
        }, true);
//        byte[] bytes = new byte[]{0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
//        mBluetoothController.sendData(bytes);
    }

}


================================================
FILE: app/src/main/java/com/luo/bluetooth/MyApplication.java
================================================
package com.luo.bluetooth;

import android.app.Application;

import com.tencent.bugly.Bugly;

public class MyApplication extends Application {
    private static final String TAG = "MyApplication";

    @Override
    public void onCreate() {
        super.onCreate();
        Bugly.init(getApplicationContext(), "4efc7ff5d2", false);
    }

}


================================================
FILE: app/src/main/java/com/luo/bluetooth/base/BaseActivity.java
================================================
package com.luo.bluetooth.base;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import java.lang.ref.WeakReference;

public class BaseActivity extends AppCompatActivity {

    //全局变量
    protected static boolean isConnecting = false;
    protected static boolean isLockConnecting = false;

    public static WeakReference<Context> currentResumeContext;
    protected Context mContext;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = this;
    }


    @Override
    protected void onResume() {
        currentResumeContext = new WeakReference<Context>(this);
        super.onResume();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    public void startToActivity(Class activityClass) {
        Intent intent = new Intent(this, activityClass);
        startActivity(intent);
    }

}


================================================
FILE: app/src/main/java/com/luo/bluetooth/common/Constants.java
================================================
package com.luo.bluetooth.common;

public class Constants {

    /**
     * 蓝牙相关
     */
    //蓝牙连接状态
    public static final int BLUETOOTH_STATUS_INIT = 0;//蓝牙钥匙状态,未连接过
    public static final int BLUETOOTH_STATUS_CONNECTED = 1;//蓝牙钥匙状态,连接过
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/BluetoothDeviceAdapter.java
================================================
package com.luo.bluetooth.customview.searchble;

import android.content.Context;
import android.graphics.Color;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.luo.bluetooth.R;
import com.luo.bluetooth.common.Constants;

import java.util.List;

/**
 * 蓝牙搜索界面适配器
 * Created by Administrator on 2016/7/23 0023.
 */
public class BluetoothDeviceAdapter extends BaseAdapter{
    private Context mContext;
    private List<BluetoothDeviceBean> mModels;

    public BluetoothDeviceAdapter(Context mContext, List<BluetoothDeviceBean> mModels) {
        this.mContext = mContext;
        this.mModels = mModels;
    }

    @Override
    public int getCount() {
        return mModels.size();
    }

    @Override
    public Object getItem(int i) {
        return mModels.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder holder=null;
        if(view==null){
            view= LayoutInflater.from(mContext).inflate(R.layout.item_bluetooth_device_list,null);
            holder=new ViewHolder();
            holder.tvName= (TextView) view.findViewById(R.id.tv_bluetooth_name);
            holder.tvAddress= (TextView) view.findViewById(R.id.tv_bluetooth_address);
            holder.svBluetooth= (SignalView) view.findViewById(R.id.svBluetooth);
            view.setTag(holder);
        }else{
            holder= (ViewHolder) view.getTag();
        }
        initView(i,holder);
        return view;
    }
    public void initView(int i,ViewHolder holder){
        BluetoothDeviceBean device=mModels.get(i);
        StringBuffer buf=new StringBuffer();
        buf.append(device.getDeviceName());
        if(!TextUtils.isEmpty(device.getNickName())){
            buf.append("【"+device.getNickName()+"】");
        }
        holder.tvName.setText(buf.toString());
        if(device.getStatus()== Constants.BLUETOOTH_STATUS_CONNECTED){
            holder.tvAddress.setTextColor(Color.BLUE);
        }else{
            holder.tvAddress.setTextColor(Color.RED);
        }
        holder.tvAddress.setText(device.getDeviceAddress());
        int intensity = (device.getRssi()+100)/12;
        holder.svBluetooth.setIntensity(intensity);
//        Log.d("LPQ3", "name:"+holder.tvAddress.getText()+" rssi:"+device.getRssi()+" intensity:"+intensity);
    }
    private class ViewHolder{
        public TextView tvName;
        public TextView tvAddress;
        public SignalView svBluetooth;
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/BluetoothDeviceBean.java
================================================
package com.luo.bluetooth.customview.searchble;

import java.io.Serializable;

import lombok.Data;

/**
 * Created by Administrator on 2016/7/23 0023.
 */
@Data
public class BluetoothDeviceBean implements Serializable {
    private String deviceName;
    private String deviceAddress;
    private int status;
    private boolean isBle;
    private String nickName;
    private int rssi;

}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/ColorUtils.java
================================================
package com.luo.bluetooth.customview.searchble;

import android.graphics.ColorFilter;
import android.graphics.ColorMatrixColorFilter;

// http://stackoverflow.com/a/11171509/317862
public class ColorUtils {

    public static ColorFilter getColorFilter(int color) {
        ColorMatrixColorFilter colorFilter;
        int red = (color & 0xFF0000) / 0xFFFF;
        int green = (color & 0xFF00) / 0xFF;
        int blue = color & 0xFF;

        float[] matrix = { 0, 0, 0, 0, red
                , 0, 0, 0, 0, green
                , 0, 0, 0, 0, blue
                , 0, 0, 0, 1, 0 };

        colorFilter = new ColorMatrixColorFilter(matrix);

        return colorFilter;
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/DeviceListActivity.java
================================================
package com.luo.bluetooth.customview.searchble;

import android.Manifest;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.stag.bluetooth.BluetoothController;
import com.stag.bluetooth.OnBluetoothScanListener;
import com.luo.bluetooth.R;
import com.luo.bluetooth.base.BaseActivity;
import com.luo.bluetooth.common.Constants;
import com.luo.bluetooth.utils.DialogUtils;
import com.luo.bluetooth.utils.LogUtils;

import java.util.LinkedList;
import java.util.List;

import cn.pedant.SweetAlert.SweetAlertDialog;

import static android.content.pm.PackageManager.PERMISSION_GRANTED;

/**
 * 搜索蓝牙设备界面
 * Created by Administrator on 2016/7/22 0022.
 */
public class DeviceListActivity extends BaseActivity implements View.OnClickListener, AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener, OnBluetoothScanListener {
    private static final String TAG = "DeviceListActivity";
    public static final String KEY_SCAN_DEVICE = "KEY_SCAN_DEVICE";
    private Button btnSearch, btnHistory, btnCancel;
    private ListView lvDevices;
    private TextView tvTitle, tvNoKey;
    private ProgressBar pbScanning;
    private BluetoothDeviceAdapter adapter;
    private List<BluetoothDeviceBean> mDeviceModes = new LinkedList<BluetoothDeviceBean>();
    private BluetoothController mBluetoothController;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LogUtils.d(TAG + ": lpq", "onCreate: ");
        setContentView(R.layout.activity_search_device_list);
        findViews();
        initData();
        bindEvent();
        this.setFinishOnTouchOutside(false);
    }

    @Override
    public void finish() {
        LogUtils.d(TAG + ": lpq", "finish: ");
        super.finish();
        overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
    }

    @Override
    protected void onDestroy() {
        LogUtils.d(TAG + ": lpq", "onDestroy: ");
        mBluetoothController.stopScan();
        super.onDestroy();
    }

    protected void findViews() {
        lvDevices = (ListView) findViewById(R.id.lv_devices);
        tvTitle = (TextView) findViewById(R.id.tvTitle);
        tvNoKey = (TextView) findViewById(R.id.tv_no_key);
        pbScanning = (ProgressBar) findViewById(R.id.pbScanning);
        btnSearch = (Button) findViewById(R.id.btn_search);
        btnHistory = (Button) findViewById(R.id.btn_history);
        btnCancel = (Button) findViewById(R.id.btn_cancel);
    }

    public void initData() {
        mBluetoothController = BluetoothController.getController(this);
        tvTitle.setText("设备列表");
        lvDevices.setEmptyView(tvNoKey);
        adapter = new BluetoothDeviceAdapter(this, mDeviceModes);
        lvDevices.setAdapter(adapter);
        startSearchKey();
        getPermissions();
    }

    /**
     * 获取权限
     */
    private void getPermissions() {
        if (ContextCompat.checkSelfPermission(DeviceListActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            //请求权限
            ActivityCompat.requestPermissions(DeviceListActivity.this,
                    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 1);
            //判断是否需要 向用户解释,为什么要申请该权限
            ActivityCompat.shouldShowRequestPermissionRationale(DeviceListActivity.this,
                    Manifest.permission.READ_CONTACTS);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (grantResults != null && grantResults.length > 0) {
            if (grantResults[0] == PERMISSION_GRANTED) {
                startSearchKey();
            } else {
                DialogUtils.showErrorDialog(mContext, "没有权限无法使用蓝牙", new SweetAlertDialog.OnSweetClickListener() {
                    @Override
                    public void onClick(SweetAlertDialog sweetAlertDialog) {
                        DialogUtils.dismissDialog();
                        finish();
                    }
                });
            }
        }
    }

    private void startSearchKey() {
        LogUtils.d(TAG + ": lpq", "startSearchKey: ");
        tvTitle.setText(R.string.title_device_list_search_key);
        showProgressBar();

        mDeviceModes.clear();
        adapter.notifyDataSetChanged();
        mBluetoothController.startScan(this);
    }

    private void stopSearchKey() {
        LogUtils.d(TAG + ": lpq", "stopSearchKey: ");
        tvTitle.setText(R.string.title_device_list_stop_search);
        hideProgressBar();
        mBluetoothController.stopScan();
    }

    private void showHistory() {
        stopSearchKey();
        tvTitle.setText(R.string.title_device_list_history);
        hideProgressBar();
        mDeviceModes.clear();
        adapter.notifyDataSetChanged();
    }

    protected void bindEvent() {
        btnSearch.setOnClickListener(this);
        btnCancel.setOnClickListener(this);
        btnHistory.setOnClickListener(this);
        lvDevices.setOnItemClickListener(this);
        lvDevices.setOnItemLongClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_search:
                startSearchKey();
                break;
            case R.id.btn_history:
                showHistory();
                break;
            case R.id.btn_cancel:
                stopSearchKey();
                finish();
                break;
            default:
                break;
        }
    }

    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, final int i, long l) {
        BluetoothDeviceBean model = mDeviceModes.get(i);
        model.setStatus(Constants.BLUETOOTH_STATUS_CONNECTED);
        //连接成功之后再保存会好一点
//        model.saveOrUpdate("deviceAddress = ?", model.getDeviceAddress());
        Intent intent = new Intent();
        intent.putExtra(KEY_SCAN_DEVICE, model);
        setResult(RESULT_OK, intent);
        stopSearchKey();
        finish();
    }

    @Override
    public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
        showSetNickNameDialog(this, mDeviceModes.get(i));
        return true;
    }

    public void showSetNickNameDialog(Context context, final BluetoothDeviceBean model) {
        final EditText editText = new EditText(this);
        editText.setText(model.getNickName());
        final NiftyDialogBuilder dialogBuilder = NiftyDialogBuilder.getInstance(context);
        dialogBuilder.withTitle(getResources().getString(R.string.dialog_set_note_name))//.withTitle(null)  no title
                .withMessage(null)
                .withEffect(Effectstype.values()[9])
                .withTitleColor("#FFFFFF")                                  //def
                .withDividerColor("#11000000")                              //def
                .withMessageColor("#FFFFFFFF")                              //def  | withMessageColor(int resid)
                .withDialogColor(getResources().getColor(R.color.colorPrimary))                               //def  | withDialogColor(int resid)
//                .withIcon(context.getResources().getDrawable(R.mipmap.logo))
                .withDuration(700)                                          //def
                //   .withEffect(effect)                                         //def Effectstype.Slidetop
                .withButton1Text(context.getString(R.string.btn_ok))                                    //def gone
                .isCancelableOnTouchOutside(false)                           //def    | isCancelable(true)
                //  .setCustomView(R.layout.custom_view,v.getContext())         //.setCustomView(View or ResId,context)
                .setCustomView(editText, this)
                .setButton1Click(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        model.setNickName(editText.getText().toString());
//                        model.saveOrUpdate("deviceAddress = ?", model.getDeviceAddress());
                        adapter.notifyDataSetChanged();
                        dialogBuilder.dismiss();
                    }
                }).withButton2Text(context.getString(R.string.btn_cancel))
                .setButton2Click(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        dialogBuilder.dismiss();
                    }
                })
                .show();
    }

    @Override
    public void onBluetoothScanFindDevice(BluetoothDevice device, int rssi, boolean isBle) {
        for (BluetoothDeviceBean m : mDeviceModes) {
            if (m.getDeviceAddress().equals(device.getAddress())) {
                return;
            }
        }
        Log.i("lpq", "onBluetoothScanFindDevice: device.name = " + device.getName() + "device.mac = " + device.getAddress());
//        List<BluetoothDeviceBean> deviceBeans = LitePal.where("deviceAddress = ?", device.getAddress()).find(BluetoothDeviceBean.class);
//        BluetoothDeviceBean model = deviceBeans.size() == 0 ? null : deviceBeans.get(0);
        BluetoothDeviceBean model = null;
        if (model == null) {
            model = new BluetoothDeviceBean();
            model.setDeviceAddress(device.getAddress());
            model.setDeviceName(device.getName());
            model.setStatus(Constants.BLUETOOTH_STATUS_INIT);
            model.setBle(isBle);
        } else {
            model.setDeviceName(device.getName());
            //感觉这句话没有什么用
//            model.saveOrUpdate("deviceAddress = ?", model.getDeviceAddress());
//            BluetoothDeviceUtil.saveBluetoothDevice(mContext, model);
        }
        model.setRssi(rssi);
        int index = -1;
        for (int i=0;i<mDeviceModes.size();i++){
            if (mDeviceModes.get(i).getRssi() < rssi) {
                index = i;
                break;
            }
        }
        if (index==-1)
            mDeviceModes.add(model);
        else
            mDeviceModes.add(index, model);
        adapter.notifyDataSetChanged();
    }

    private void showProgressBar(){
        pbScanning.setVisibility(View.VISIBLE);
    }

    private void hideProgressBar(){
        pbScanning.setVisibility(View.GONE);
    }

    @Override
    public void onBluetoothScanFinish() {
        tvTitle.setText(R.string.title_device_list_select_key);
    }
}



================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/Effectstype.java
================================================
package com.luo.bluetooth.customview.searchble;


import com.luo.bluetooth.customview.searchble.effects.BaseEffects;
import com.luo.bluetooth.customview.searchble.effects.FadeIn;
import com.luo.bluetooth.customview.searchble.effects.Fall;
import com.luo.bluetooth.customview.searchble.effects.FlipH;
import com.luo.bluetooth.customview.searchble.effects.FlipV;
import com.luo.bluetooth.customview.searchble.effects.NewsPaper;
import com.luo.bluetooth.customview.searchble.effects.RotateBottom;
import com.luo.bluetooth.customview.searchble.effects.RotateLeft;
import com.luo.bluetooth.customview.searchble.effects.Shake;
import com.luo.bluetooth.customview.searchble.effects.SideFall;
import com.luo.bluetooth.customview.searchble.effects.SlideBottom;
import com.luo.bluetooth.customview.searchble.effects.SlideLeft;
import com.luo.bluetooth.customview.searchble.effects.SlideRight;
import com.luo.bluetooth.customview.searchble.effects.SlideTop;
import com.luo.bluetooth.customview.searchble.effects.Slit;

/*
 * Copyright 2014 litao
 * https://github.com/sd6352051/NiftyDialogEffects
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public enum Effectstype {

    fadein(FadeIn.class),
    slideleft(SlideLeft.class),
    slidetop(SlideTop.class),
    slidebottom(SlideBottom.class),
    slideright(SlideRight.class),
    fall(Fall.class),
    newspager(NewsPaper.class),
    fliph(FlipH.class),
    flipv(FlipV.class),
    rotateBottom(RotateBottom.class),
    rotateLeft(RotateLeft.class),
    slit(Slit.class),
    shake(Shake.class),
    sidefill(SideFall.class);

    private Class<? extends BaseEffects> effectsClazz;

    private Effectstype(Class<? extends BaseEffects> mclass) {
        effectsClazz = mclass;
    }

    public BaseEffects getAnimator() {
        BaseEffects bEffects=null;
	try {
		bEffects = effectsClazz.newInstance();
	} catch (ClassCastException e) {
		throw new Error("Can not init animatorClazz instance");
	} catch (InstantiationException e) {
		// TODO Auto-generated catch block
		throw new Error("Can not init animatorClazz instance");
	} catch (IllegalAccessException e) {
		// TODO Auto-generated catch block
		throw new Error("Can not init animatorClazz instance");
	}
	return bEffects;
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/NiftyDialogBuilder.java
================================================
package com.luo.bluetooth.customview.searchble;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.luo.bluetooth.R;
import com.luo.bluetooth.customview.searchble.effects.BaseEffects;


/*
 * Copyright 2014 litao
 * https://github.com/sd6352051/NiftyDialogEffects
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class NiftyDialogBuilder extends Dialog implements DialogInterface {
    
    private final String defTextColor="#FFFFFFFF";
    
    private final String defDividerColor="#11000000";
    
    private final String defMsgColor="#FFFFFFFF";
    
    private final String defDialogColor="#FFE74C3C";


    private static Context tmpContext;
    
    
    private Effectstype type=null;
    
    private LinearLayout mLinearLayoutView;
    
    private RelativeLayout mRelativeLayoutView;
    
    private LinearLayout mLinearLayoutMsgView;
    
    private LinearLayout mLinearLayoutTopView;
    
    private FrameLayout mFrameLayoutCustomView;
    
    private View mDialogView;
    
    private View mDivider;
    
    private TextView mTitle;
    
    private TextView mMessage;
    
    private ImageView mIcon;
    
    private Button mButton1;
    
    private Button mButton2;
    
    private int mDuration = -1;
    
    private static  int mOrientation=1;
    
    private boolean isCancelable=true;
    
    private static NiftyDialogBuilder instance;
    
    public NiftyDialogBuilder(Context context) {
        super(context);
        init(context);
        
    }
    public NiftyDialogBuilder(Context context, int theme) {
        super(context, theme);
        init(context);
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        WindowManager.LayoutParams params = getWindow().getAttributes();
        params.height = ViewGroup.LayoutParams.MATCH_PARENT;
        params.width  = ViewGroup.LayoutParams.MATCH_PARENT;
        getWindow().setAttributes((WindowManager.LayoutParams) params);
        
    }
    
    public static NiftyDialogBuilder getInstance(Context context) {

        if (instance == null || !tmpContext.equals(context)) {
            synchronized (NiftyDialogBuilder.class) {
                if (instance == null || !tmpContext.equals(context)) {
                    instance = new NiftyDialogBuilder(context,  R.style.dialog_untran);
                }
            }
        }
        tmpContext = context;
        return instance;

    }
    
    private void init(Context context) {
        
        mDialogView = View.inflate(context, R.layout.dialog_layout, null);
        
        mLinearLayoutView=(LinearLayout)mDialogView.findViewById(R.id.parentPanel);
        mRelativeLayoutView=(RelativeLayout)mDialogView.findViewById(R.id.main);
        mLinearLayoutTopView=(LinearLayout)mDialogView.findViewById(R.id.topPanel);
        mLinearLayoutMsgView=(LinearLayout)mDialogView.findViewById(R.id.contentPanel);
        mFrameLayoutCustomView=(FrameLayout)mDialogView.findViewById(R.id.customPanel);
        
        mTitle = (TextView) mDialogView.findViewById(R.id.alertTitle);
        mMessage = (TextView) mDialogView.findViewById(R.id.message);
        mIcon = (ImageView) mDialogView.findViewById(R.id.icon);
        mDivider = mDialogView.findViewById(R.id.titleDivider);
        mButton1=(Button)mDialogView.findViewById(R.id.button1);
        mButton2=(Button)mDialogView.findViewById(R.id.button2);
        
        setContentView(mDialogView);
        
        this.setOnShowListener(new OnShowListener() {
            @Override
            public void onShow(DialogInterface dialogInterface) {
                
                mLinearLayoutView.setVisibility(View.VISIBLE);
                if(type==null){
                    type=Effectstype.slidetop;
                }
                start(type);
                
                
            }
        });
        mRelativeLayoutView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (isCancelable)dismiss();
            }
        });
    }
    
    public void toDefault(){
        mTitle.setTextColor(Color.parseColor(defTextColor));
        mDivider.setBackgroundColor(Color.parseColor(defDividerColor));
        mMessage.setTextColor(Color.parseColor(defMsgColor));
        mLinearLayoutView.setBackgroundColor(Color.parseColor(defDialogColor));
    }
    
    public NiftyDialogBuilder withDividerColor(String colorString) {
        mDivider.setBackgroundColor(Color.parseColor(colorString));
        return this;
    }
    public NiftyDialogBuilder withDividerColor(int color) {
        mDivider.setBackgroundColor(color);
        return this;
    }
    
    
    public NiftyDialogBuilder withTitle(CharSequence title) {
        toggleView(mLinearLayoutTopView,title);
        mTitle.setText(title);
        return this;
    }
    
    public NiftyDialogBuilder withTitleColor(String colorString) {
        mTitle.setTextColor(Color.parseColor(colorString));
        return this;
    }
    
    public NiftyDialogBuilder withTitleColor(int color) {
        mTitle.setTextColor(color);
        return this;
    }
    
    public NiftyDialogBuilder withMessage(int textResId) {
        toggleView(mLinearLayoutMsgView,textResId);
        mMessage.setText(textResId);
        return this;
    }
    
    public NiftyDialogBuilder withMessage(CharSequence msg) {
        toggleView(mLinearLayoutMsgView,msg);
        mMessage.setText(msg);
        return this;
    }
    public NiftyDialogBuilder withMessageColor(String colorString) {
        mMessage.setTextColor(Color.parseColor(colorString));
        return this;
    }
    public NiftyDialogBuilder withMessageColor(int color) {
        mMessage.setTextColor(color);
        return this;
    }
    
    public NiftyDialogBuilder withDialogColor(String colorString) {
        mLinearLayoutView.getBackground().setColorFilter(ColorUtils.getColorFilter(Color.parseColor(colorString)));
        return this;
    }
    
    public NiftyDialogBuilder withDialogColor(int color) {
        mLinearLayoutView.getBackground().setColorFilter(ColorUtils.getColorFilter(color));
        return this;
    }
    
    public NiftyDialogBuilder withIcon(int drawableResId) {
        mIcon.setImageResource(drawableResId);
        return this;
    }
    
    public NiftyDialogBuilder withIcon(Drawable icon) {
        mIcon.setImageDrawable(icon);
        return this;
    }
    
    public NiftyDialogBuilder withDuration(int duration) {
        this.mDuration=duration;
        return this;
    }
    
    public NiftyDialogBuilder withEffect(Effectstype type) {
        this.type=type;
        return this;
    }
    
    public NiftyDialogBuilder withButtonDrawable(int resid) {
        mButton1.setBackgroundResource(resid);
        mButton2.setBackgroundResource(resid);
        return this;
    }
    public NiftyDialogBuilder withButton1Text(CharSequence text) {
        mButton1.setVisibility(View.VISIBLE);
        mButton1.setText(text);
        
        return this;
    }
    public NiftyDialogBuilder withButton2Text(CharSequence text) {
        mButton2.setVisibility(View.VISIBLE);
        mButton2.setText(text);
        return this;
    }
    public NiftyDialogBuilder setButton1Click(View.OnClickListener click) {
        mButton1.setOnClickListener(click);
        return this;
    }
    
    public NiftyDialogBuilder setButton2Click(View.OnClickListener click) {
        mButton2.setOnClickListener(click);
        return this;
    }
    
    
    public NiftyDialogBuilder setCustomView(int resId, Context context) {
        View customView = View.inflate(context, resId, null);
        if (mFrameLayoutCustomView.getChildCount()>0){
            mFrameLayoutCustomView.removeAllViews();
        }
        mFrameLayoutCustomView.addView(customView);
        return this;
    }
    
    public NiftyDialogBuilder setCustomView(View view, Context context) {
        if (mFrameLayoutCustomView.getChildCount()>0){
            mFrameLayoutCustomView.removeAllViews();
        }
        mFrameLayoutCustomView.addView(view);
        
        return this;
    }

    public NiftyDialogBuilder removeAllCustomView(){
        if (mFrameLayoutCustomView.getChildCount()>0){
            mFrameLayoutCustomView.removeAllViews();
        }
        return this;
    }


    public NiftyDialogBuilder isCancelableOnTouchOutside(boolean cancelable) {
        this.isCancelable=cancelable;
        this.setCanceledOnTouchOutside(cancelable);
        return this;
    }
    
    public NiftyDialogBuilder isCancelable(boolean cancelable) {
        this.isCancelable=cancelable;
        this.setCancelable(cancelable);
        return this;
    }
    
    private void toggleView(View view, Object obj){
        if (obj==null){
            view.setVisibility(View.GONE);
        }else {
            view.setVisibility(View.VISIBLE);
        }
    }
    @Override
    public void show() {
        super.show();
    }
    
    private void start(Effectstype type){
        BaseEffects animator = type.getAnimator();
        if(mDuration != -1){
            animator.setDuration(Math.abs(mDuration));
        }
        animator.start(mRelativeLayoutView);
    }
    
    @Override
    public void dismiss() {
        super.dismiss();
        mButton1.setVisibility(View.GONE);
        mButton2.setVisibility(View.GONE);
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/SignalView.java
================================================
package com.luo.bluetooth.customview.searchble;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

import com.luo.bluetooth.R;


/**
 * 强度指示器,等级0-4
 * Created by LPQ on 2017/1/17.
 */

public class SignalView extends View {

    private Paint mPaint;
    private int mWidth, mHeight;
    private float cx, cy, radius;
    private int mNoIntensityColor, mIntensityColor;
    private int mIntensity;

    public SignalView(Context context) {
        this(context, null);
    }

    public SignalView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SignalView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SignalView, defStyleAttr, 0);
        mIntensityColor = typedArray.getColor(R.styleable.SignalView_intensityColor, 0xff6cb1f2);
        mNoIntensityColor = typedArray.getColor(R.styleable.SignalView_noIntensityColor, 0xffbdc3c7);
        typedArray.recycle();
        init();
    }

    private void init(){
//        setWillNotDraw(false);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
    }

    /**
     * 设置强度
     * */
    public void setIntensity(int intensity){
        mIntensity = intensity;
        if (intensity>4)
            mIntensity = 4;
        if (intensity<0)
            mIntensity = 0;
        invalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mWidth = getMeasuredWidth();
        mHeight = getMeasuredHeight();
        cx = mWidth/2.f;
        cy = mHeight*0.7f;
        if (mWidth>mHeight){
            radius = mHeight/12.f;
        }else {
            radius = mWidth/12.f;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(mIntensity>0?mIntensityColor:mNoIntensityColor);
        canvas.drawCircle(cx, cy, radius, mPaint);
        RectF rectF = new RectF(cx-2.5f*radius, cy-2.f*radius, cx+2.5f*radius, cy+4*radius);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(radius*0.8f);
        mPaint.setColor(mIntensity>1?mIntensityColor:mNoIntensityColor);
        canvas.drawArc(rectF, 220, 100, false, mPaint);
        float offest = 1.5f*radius;
        for (int i=2;i<4;i++){
            mPaint.setColor(mIntensity>i?mIntensityColor:mNoIntensityColor);
            rectF.left -= offest;
            rectF.top -= offest;
            rectF.right += offest;
            canvas.drawArc(rectF, 220, 100, false, mPaint);
        }
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/BaseEffects.java
================================================
package com.luo.bluetooth.customview.searchble.effects;

import android.animation.AnimatorSet;
import android.os.Build;
import android.view.View;


/**
 * Modify by lee on 2014/7/30.
 * https://github.com/sd6352051/NiftyDialogEffects
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 daimajia
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Acknowledgements daimajia
 * https://github.com/daimajia
 */
public abstract  class BaseEffects {

    private static final int DURATION = 1 * 700;

    protected long mDuration =DURATION ;

    private AnimatorSet mAnimatorSet;

    {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            mAnimatorSet = new AnimatorSet();
        }
    }

    protected abstract void setupAnimation(View view);

    public void start(View view) {
        reset(view);
        setupAnimation(view);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            mAnimatorSet.start();
        }
    }
    public void reset(View view) {
//        ViewHelper.setPivotX(view, view.getMeasuredWidth() / 2.0f);
//        ViewHelper.setPivotY(view, view.getMeasuredHeight() / 2.0f);
    }


    public AnimatorSet getAnimatorSet() {
        return mAnimatorSet;
    }
    
    public void setDuration(long duration) {
        this.mDuration = duration;
    }

}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/FadeIn.java
================================================
package com.luo.bluetooth.customview.searchble.effects;

import android.animation.ObjectAnimator;
import android.view.View;

/*
 * Copyright 2014 litao
 * https://github.com/sd6352051/NiftyDialogEffects
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class FadeIn extends BaseEffects{

    @Override
    protected void setupAnimation(View view) {
        getAnimatorSet().playTogether(
                ObjectAnimator.ofFloat(view, "alpha", 0, 1).setDuration(mDuration)

        );
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/Fall.java
================================================
package com.luo.bluetooth.customview.searchble.effects;

import android.animation.ObjectAnimator;
import android.view.View;

/*
 * Copyright 2014 litao
 * https://github.com/sd6352051/NiftyDialogEffects
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class Fall extends BaseEffects{

    @Override
    protected void setupAnimation(View view) {
        getAnimatorSet().playTogether(
                ObjectAnimator.ofFloat(view, "scaleX", 2, 1.5f, 1).setDuration(mDuration),
                ObjectAnimator.ofFloat(view,"scaleY",2,1.5f,1).setDuration(mDuration),
                ObjectAnimator.ofFloat(view, "alpha", 0, 1).setDuration(mDuration*3/2)

        );
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/FlipH.java
================================================
package com.luo.bluetooth.customview.searchble.effects;

import android.animation.ObjectAnimator;
import android.view.View;


/*
 * Copyright 2014 litao
 * https://github.com/sd6352051/NiftyDialogEffects
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class FlipH  extends BaseEffects{

    @Override
    protected void setupAnimation(View view) {
        getAnimatorSet().playTogether(
                ObjectAnimator.ofFloat(view, "rotationY", -90, 0).setDuration(mDuration)

        );
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/FlipV.java
================================================
package com.luo.bluetooth.customview.searchble.effects;

import android.animation.ObjectAnimator;
import android.view.View;


/*
 * Copyright 2014 litao
 * https://github.com/sd6352051/NiftyDialogEffects
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class FlipV extends BaseEffects{

    @Override
    protected void setupAnimation(View view) {
        getAnimatorSet().playTogether(
                ObjectAnimator.ofFloat(view, "rotationX", -90, 0).setDuration(mDuration)

        );
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/NewsPaper.java
================================================
package com.luo.bluetooth.customview.searchble.effects;

import android.animation.ObjectAnimator;
import android.view.View;

/*
 * Copyright 2014 litao
 * https://github.com/sd6352051/NiftyDialogEffects
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class NewsPaper extends BaseEffects{

    @Override
    protected void setupAnimation(View view) {
        getAnimatorSet().playTogether(
                ObjectAnimator.ofFloat(view, "rotation", 1080, 720, 360, 0).setDuration(mDuration),
                ObjectAnimator.ofFloat(view, "alpha", 0, 1).setDuration(mDuration*3/2),
                ObjectAnimator.ofFloat(view, "scaleX", 0.1f, 0.5f, 1).setDuration(mDuration),
                ObjectAnimator.ofFloat(view,"scaleY",0.1f,0.5f,1).setDuration(mDuration)

        );
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/RotateBottom.java
================================================
package com.luo.bluetooth.customview.searchble.effects;

import android.animation.ObjectAnimator;
import android.view.View;


/*
 * Copyright 2014 litao
 * https://github.com/sd6352051/NiftyDialogEffects
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class RotateBottom extends BaseEffects{

    @Override
    protected void setupAnimation(View view) {
        getAnimatorSet().playTogether(
                ObjectAnimator.ofFloat(view, "rotationX",90, 0).setDuration(mDuration),
                ObjectAnimator.ofFloat(view, "translationY", 300, 0).setDuration(mDuration),
                ObjectAnimator.ofFloat(view, "alpha", 0, 1).setDuration(mDuration*3/2)

        );
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/RotateLeft.java
================================================
package com.luo.bluetooth.customview.searchble.effects;

import android.animation.ObjectAnimator;
import android.view.View;

/*
 * Copyright 2014 litao
 * https://github.com/sd6352051/NiftyDialogEffects
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class RotateLeft extends BaseEffects{

    @Override
    protected void setupAnimation(View view) {
        getAnimatorSet().playTogether(
                ObjectAnimator.ofFloat(view, "rotationY", 90, 0).setDuration(mDuration),
                ObjectAnimator.ofFloat(view, "translationX", -300, 0).setDuration(mDuration),
                ObjectAnimator.ofFloat(view, "alpha", 0, 1).setDuration(mDuration*3/2)

        );
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/Shake.java
================================================
package com.luo.bluetooth.customview.searchble.effects;

import android.animation.ObjectAnimator;
import android.os.Build;
import android.view.View;


/*
 * Copyright 2014 litao
 * https://github.com/sd6352051/NiftyDialogEffects
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class Shake  extends BaseEffects{

    @Override
    protected void setupAnimation(View view) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            getAnimatorSet().playTogether(
                    ObjectAnimator.ofFloat(view, "translationX", 0, .10f, -25, .26f, 25, .42f, -25, .58f, 25, .74f, -25, .90f, 1, 0).setDuration(mDuration)

            );
        }
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/SideFall.java
================================================
package com.luo.bluetooth.customview.searchble.effects;

import android.animation.ObjectAnimator;
import android.view.View;

/*
 * Copyright 2014 litao
 * https://github.com/sd6352051/NiftyDialogEffects
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class SideFall extends BaseEffects{

    @Override
    protected void setupAnimation(View view) {
        getAnimatorSet().playTogether(
                ObjectAnimator.ofFloat(view, "scaleX", 2, 1.5f, 1).setDuration(mDuration),
                ObjectAnimator.ofFloat(view,"scaleY",2,1.5f,1).setDuration(mDuration),
                ObjectAnimator.ofFloat(view, "rotation", 25,0).setDuration(mDuration),
                ObjectAnimator.ofFloat(view, "translationX",80,0).setDuration(mDuration),
                ObjectAnimator.ofFloat(view, "alpha", 0, 1).setDuration(mDuration*3/2)

        );
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/SlideBottom.java
================================================
package com.luo.bluetooth.customview.searchble.effects;

import android.animation.ObjectAnimator;
import android.os.Build;
import android.view.View;

/*
 * Copyright 2014 litao
 * https://github.com/sd6352051/NiftyDialogEffects
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class SlideBottom extends BaseEffects{

    @Override
    protected void setupAnimation(View view) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            getAnimatorSet().playTogether(
                    ObjectAnimator.ofFloat(view, "translationY", 300, 0).setDuration(mDuration),
                    ObjectAnimator.ofFloat(view, "alpha", 0, 1).setDuration(mDuration*3/2)

            );
        }
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/SlideLeft.java
================================================
package com.luo.bluetooth.customview.searchble.effects;

import android.animation.ObjectAnimator;
import android.view.View;

/*
 * Copyright 2014 litao
 * https://github.com/sd6352051/NiftyDialogEffects
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class SlideLeft extends BaseEffects{

    @Override
    protected void setupAnimation(View view) {
        getAnimatorSet().playTogether(
                ObjectAnimator.ofFloat(view, "translationX", -300, 0).setDuration(mDuration),
                ObjectAnimator.ofFloat(view, "alpha", 0, 1).setDuration(mDuration*3/2)

        );
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/SlideRight.java
================================================
package com.luo.bluetooth.customview.searchble.effects;

import android.animation.ObjectAnimator;
import android.view.View;

/*
 * Copyright 2014 litao
 * https://github.com/sd6352051/NiftyDialogEffects
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class SlideRight extends BaseEffects{

    @Override
    protected void setupAnimation(View view) {
        getAnimatorSet().playTogether(
                ObjectAnimator.ofFloat(view, "translationX", 300, 0).setDuration(mDuration),
                ObjectAnimator.ofFloat(view, "alpha", 0, 1).setDuration(mDuration*3/2)

        );
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/SlideTop.java
================================================
package com.luo.bluetooth.customview.searchble.effects;

import android.animation.ObjectAnimator;
import android.view.View;

/*
 * Copyright 2014 litao
 * https://github.com/sd6352051/NiftyDialogEffects
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class SlideTop extends BaseEffects{

    @Override
    protected void setupAnimation(View view) {
        getAnimatorSet().playTogether(
                ObjectAnimator.ofFloat(view, "translationY", -300, 0).setDuration(mDuration),
                ObjectAnimator.ofFloat(view, "alpha", 0, 1).setDuration(mDuration*3/2)

        );
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/Slit.java
================================================
package com.luo.bluetooth.customview.searchble.effects;

import android.animation.ObjectAnimator;
import android.view.View;


/*
 * Copyright 2014 litao
 * https://github.com/sd6352051/NiftyDialogEffects
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class Slit extends BaseEffects{

    @Override
    protected void setupAnimation(View view) {
        getAnimatorSet().playTogether(
                ObjectAnimator.ofFloat(view, "rotationY", 90, 88, 88, 45, 0).setDuration(mDuration),
                ObjectAnimator.ofFloat(view, "alpha", 0,0.4f,0.8f, 1).setDuration(mDuration*3/2),
                ObjectAnimator.ofFloat(view, "scaleX", 0,0.5f, 0.9f, 0.9f, 1).setDuration(mDuration),
                ObjectAnimator.ofFloat(view,"scaleY",0,0.5f, 0.9f, 0.9f, 1).setDuration(mDuration)
        );
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/encryption/Aes.java
================================================
/*
 * Copyright (c) 2019. stag All rights reserved.
 */

package com.luo.bluetooth.encryption;


import com.stag.bluetooth.util.ByteUtils;

/**
 * AES加密
 */
public class Aes {

    // foreward sbox
    private static final byte sbox[] = {
            //0          1            2           3           4            5           6            7           8            9            A           B            C           D           E            F
            (byte) 0x63, (byte) 0x7c, (byte) 0x77, (byte) 0x7b, (byte) 0xf2, (byte) 0x6b, (byte) 0x6f, (byte) 0xc5, (byte) 0x30, (byte) 0x01, (byte) 0x67, (byte) 0x2b, (byte) 0xfe, (byte) 0xd7, (byte) 0xab, (byte) 0x76, //0
            (byte) 0xca, (byte) 0x82, (byte) 0xc9, (byte) 0x7d, (byte) 0xfa, (byte) 0x59, (byte) 0x47, (byte) 0xf0, (byte) 0xad, (byte) 0xd4, (byte) 0xa2, (byte) 0xaf, (byte) 0x9c, (byte) 0xa4, (byte) 0x72, (byte) 0xc0, //1
            (byte) 0xb7, (byte) 0xfd, (byte) 0x93, (byte) 0x26, (byte) 0x36, (byte) 0x3f, (byte) 0xf7, (byte) 0xcc, (byte) 0x34, (byte) 0xa5, (byte) 0xe5, (byte) 0xf1, (byte) 0x71, (byte) 0xd8, (byte) 0x31, (byte) 0x15, //2
            (byte) 0x04, (byte) 0xc7, (byte) 0x23, (byte) 0xc3, (byte) 0x18, (byte) 0x96, (byte) 0x05, (byte) 0x9a, (byte) 0x07, (byte) 0x12, (byte) 0x80, (byte) 0xe2, (byte) 0xeb, (byte) 0x27, (byte) 0xb2, (byte) 0x75, //3
            (byte) 0x09, (byte) 0x83, (byte) 0x2c, (byte) 0x1a, (byte) 0x1b, (byte) 0x6e, (byte) 0x5a, (byte) 0xa0, (byte) 0x52, (byte) 0x3b, (byte) 0xd6, (byte) 0xb3, (byte) 0x29, (byte) 0xe3, (byte) 0x2f, (byte) 0x84, //4
            (byte) 0x53, (byte) 0xd1, (byte) 0x00, (byte) 0xed, (byte) 0x20, (byte) 0xfc, (byte) 0xb1, (byte) 0x5b, (byte) 0x6a, (byte) 0xcb, (byte) 0xbe, (byte) 0x39, (byte) 0x4a, (byte) 0x4c, (byte) 0x58, (byte) 0xcf, //5
            (byte) 0xd0, (byte) 0xef, (byte) 0xaa, (byte) 0xfb, (byte) 0x43, (byte) 0x4d, (byte) 0x33, (byte) 0x85, (byte) 0x45, (byte) 0xf9, (byte) 0x02, (byte) 0x7f, (byte) 0x50, (byte) 0x3c, (byte) 0x9f, (byte) 0xa8, //6
            (byte) 0x51, (byte) 0xa3, (byte) 0x40, (byte) 0x8f, (byte) 0x92, (byte) 0x9d, (byte) 0x38, (byte) 0xf5, (byte) 0xbc, (byte) 0xb6, (byte) 0xda, (byte) 0x21, (byte) 0x10, (byte) 0xff, (byte) 0xf3, (byte) 0xd2, //7
            (byte) 0xcd, (byte) 0x0c, (byte) 0x13, (byte) 0xec, (byte) 0x5f, (byte) 0x97, (byte) 0x44, (byte) 0x17, (byte) 0xc4, (byte) 0xa7, (byte) 0x7e, (byte) 0x3d, (byte) 0x64, (byte) 0x5d, (byte) 0x19, (byte) 0x73, //8
            (byte) 0x60, (byte) 0x81, (byte) 0x4f, (byte) 0xdc, (byte) 0x22, (byte) 0x2a, (byte) 0x90, (byte) 0x88, (byte) 0x46, (byte) 0xee, (byte) 0xb8, (byte) 0x14, (byte) 0xde, (byte) 0x5e, (byte) 0x0b, (byte) 0xdb, //9
            (byte) 0xe0, (byte) 0x32, (byte) 0x3a, (byte) 0x0a, (byte) 0x49, (byte) 0x06, (byte) 0x24, (byte) 0x5c, (byte) 0xc2, (byte) 0xd3, (byte) 0xac, (byte) 0x62, (byte) 0x91, (byte) 0x95, (byte) 0xe4, (byte) 0x79, //A
            (byte) 0xe7, (byte) 0xc8, (byte) 0x37, (byte) 0x6d, (byte) 0x8d, (byte) 0xd5, (byte) 0x4e, (byte) 0xa9, (byte) 0x6c, (byte) 0x56, (byte) 0xf4, (byte) 0xea, (byte) 0x65, (byte) 0x7a, (byte) 0xae, (byte) 0x08, //B
            (byte) 0xba, (byte) 0x78, (byte) 0x25, (byte) 0x2e, (byte) 0x1c, (byte) 0xa6, (byte) 0xb4, (byte) 0xc6, (byte) 0xe8, (byte) 0xdd, (byte) 0x74, (byte) 0x1f, (byte) 0x4b, (byte) 0xbd, (byte) 0x8b, (byte) 0x8a, //C
            (byte) 0x70, (byte) 0x3e, (byte) 0xb5, (byte) 0x66, (byte) 0x48, (byte) 0x03, (byte) 0xf6, (byte) 0x0e, (byte) 0x61, (byte) 0x35, (byte) 0x57, (byte) 0xb9, (byte) 0x86, (byte) 0xc1, (byte) 0x1d, (byte) 0x9e, //D
            (byte) 0xe1, (byte) 0xf8, (byte) 0x98, (byte) 0x11, (byte) 0x69, (byte) 0xd9, (byte) 0x8e, (byte) 0x94, (byte) 0x9b, (byte) 0x1e, (byte) 0x87, (byte) 0xe9, (byte) 0xce, (byte) 0x55, (byte) 0x28, (byte) 0xdf, //E
            (byte) 0x8c, (byte) 0xa1, (byte) 0x89, (byte) 0x0d, (byte) 0xbf, (byte) 0xe6, (byte) 0x42, (byte) 0x68, (byte) 0x41, (byte) 0x99, (byte) 0x2d, (byte) 0x0f, (byte) 0xb0, (byte) 0x54, (byte) 0xbb, (byte) 0x16}; //F
    // inverse sbox
    private static final byte rsbox[] = {
            (byte) 0x52, (byte) 0x09, (byte) 0x6a, (byte) 0xd5, (byte) 0x30, (byte) 0x36, (byte) 0xa5, (byte) 0x38, (byte) 0xbf, (byte) 0x40, (byte) 0xa3, (byte) 0x9e, (byte) 0x81, (byte) 0xf3, (byte) 0xd7, (byte) 0xfb,
            (byte) 0x7c, (byte) 0xe3, (byte) 0x39, (byte) 0x82, (byte) 0x9b, (byte) 0x2f, (byte) 0xff, (byte) 0x87, (byte) 0x34, (byte) 0x8e, (byte) 0x43, (byte) 0x44, (byte) 0xc4, (byte) 0xde, (byte) 0xe9, (byte) 0xcb,
            (byte) 0x54, (byte) 0x7b, (byte) 0x94, (byte) 0x32, (byte) 0xa6, (byte) 0xc2, (byte) 0x23, (byte) 0x3d, (byte) 0xee, (byte) 0x4c, (byte) 0x95, (byte) 0x0b, (byte) 0x42, (byte) 0xfa, (byte) 0xc3, (byte) 0x4e,
            (byte) 0x08, (byte) 0x2e, (byte) 0xa1, (byte) 0x66, (byte) 0x28, (byte) 0xd9, (byte) 0x24, (byte) 0xb2, (byte) 0x76, (byte) 0x5b, (byte) 0xa2, (byte) 0x49, (byte) 0x6d, (byte) 0x8b, (byte) 0xd1, (byte) 0x25,
            (byte) 0x72, (byte) 0xf8, (byte) 0xf6, (byte) 0x64, (byte) 0x86, (byte) 0x68, (byte) 0x98, (byte) 0x16, (byte) 0xd4, (byte) 0xa4, (byte) 0x5c, (byte) 0xcc, (byte) 0x5d, (byte) 0x65, (byte) 0xb6, (byte) 0x92,
            (byte) 0x6c, (byte) 0x70, (byte) 0x48, (byte) 0x50, (byte) 0xfd, (byte) 0xed, (byte) 0xb9, (byte) 0xda, (byte) 0x5e, (byte) 0x15, (byte) 0x46, (byte) 0x57, (byte) 0xa7, (byte) 0x8d, (byte) 0x9d, (byte) 0x84,
            (byte) 0x90, (byte) 0xd8, (byte) 0xab, (byte) 0x00, (byte) 0x8c, (byte) 0xbc, (byte) 0xd3, (byte) 0x0a, (byte) 0xf7, (byte) 0xe4, (byte) 0x58, (byte) 0x05, (byte) 0xb8, (byte) 0xb3, (byte) 0x45, (byte) 0x06,
            (byte) 0xd0, (byte) 0x2c, (byte) 0x1e, (byte) 0x8f, (byte) 0xca, (byte) 0x3f, (byte) 0x0f, (byte) 0x02, (byte) 0xc1, (byte) 0xaf, (byte) 0xbd, (byte) 0x03, (byte) 0x01, (byte) 0x13, (byte) 0x8a, (byte) 0x6b,
            (byte) 0x3a, (byte) 0x91, (byte) 0x11, (byte) 0x41, (byte) 0x4f, (byte) 0x67, (byte) 0xdc, (byte) 0xea, (byte) 0x97, (byte) 0xf2, (byte) 0xcf, (byte) 0xce, (byte) 0xf0, (byte) 0xb4, (byte) 0xe6, (byte) 0x73,
            (byte) 0x96, (byte) 0xac, (byte) 0x74, (byte) 0x22, (byte) 0xe7, (byte) 0xad, (byte) 0x35, (byte) 0x85, (byte) 0xe2, (byte) 0xf9, (byte) 0x37, (byte) 0xe8, (byte) 0x1c, (byte) 0x75, (byte) 0xdf, (byte) 0x6e,
            (byte) 0x47, (byte) 0xf1, (byte) 0x1a, (byte) 0x71, (byte) 0x1d, (byte) 0x29, (byte) 0xc5, (byte) 0x89, (byte) 0x6f, (byte) 0xb7, (byte) 0x62, (byte) 0x0e, (byte) 0xaa, (byte) 0x18, (byte) 0xbe, (byte) 0x1b,
            (byte) 0xfc, (byte) 0x56, (byte) 0x3e, (byte) 0x4b, (byte) 0xc6, (byte) 0xd2, (byte) 0x79, (byte) 0x20, (byte) 0x9a, (byte) 0xdb, (byte) 0xc0, (byte) 0xfe, (byte) 0x78, (byte) 0xcd, (byte) 0x5a, (byte) 0xf4,
            (byte) 0x1f, (byte) 0xdd, (byte) 0xa8, (byte) 0x33, (byte) 0x88, (byte) 0x07, (byte) 0xc7, (byte) 0x31, (byte) 0xb1, (byte) 0x12, (byte) 0x10, (byte) 0x59, (byte) 0x27, (byte) 0x80, (byte) 0xec, (byte) 0x5f,
            (byte) 0x60, (byte) 0x51, (byte) 0x7f, (byte) 0xa9, (byte) 0x19, (byte) 0xb5, (byte) 0x4a, (byte) 0x0d, (byte) 0x2d, (byte) 0xe5, (byte) 0x7a, (byte) 0x9f, (byte) 0x93, (byte) 0xc9, (byte) 0x9c, (byte) 0xef,
            (byte) 0xa0, (byte) 0xe0, (byte) 0x3b, (byte) 0x4d, (byte) 0xae, (byte) 0x2a, (byte) 0xf5, (byte) 0xb0, (byte) 0xc8, (byte) 0xeb, (byte) 0xbb, (byte) 0x3c, (byte) 0x83, (byte) 0x53, (byte) 0x99, (byte) 0x61,
            (byte) 0x17, (byte) 0x2b, (byte) 0x04, (byte) 0x7e, (byte) 0xba, (byte) 0x77, (byte) 0xd6, (byte) 0x26, (byte) 0xe1, (byte) 0x69, (byte) 0x14, (byte) 0x63, (byte) 0x55, (byte) 0x21, (byte) 0x0c, (byte) 0x7d};
    // round constant
    private static final byte Rcon[] = {
            (byte) 0x8d, (byte) 0x01, (byte) 0x02, (byte) 0x04, (byte) 0x08, (byte) 0x10, (byte) 0x20, (byte) 0x40, (byte) 0x80, (byte) 0x1b, (byte) 0x36};

    // expand the key
    private static byte[] expandKey(byte[] key) {
        byte[] expandedKey = new byte[176];
        int ii, buf1;
        for (ii = 0; ii < 16; ii++)
            expandedKey[ii] = key[ii];
        for (ii = 1; ii < 11; ii++) {
            buf1 = expandedKey[ii * 16 - 4];
            expandedKey[ii * 16 + 0] = (byte) ((sbox[expandedKey[ii * 16 - 3] & 0xff] ^ expandedKey[(ii - 1) * 16 + 0] ^ Rcon[ii]) & 0xff);
            expandedKey[ii * 16 + 1] = (byte) ((sbox[expandedKey[ii * 16 - 2] & 0xff] ^ expandedKey[(ii - 1) * 16 + 1]) & 0xff);
            expandedKey[ii * 16 + 2] = (byte) ((sbox[expandedKey[ii * 16 - 1] & 0xff] ^ expandedKey[(ii - 1) * 16 + 2]) & 0xff);
            expandedKey[ii * 16 + 3] = (byte) ((sbox[buf1 & 0xff] ^ expandedKey[(ii - 1) * 16 + 3]) & 0xff);
            expandedKey[ii * 16 + 4] = (byte) ((expandedKey[(ii - 1) * 16 + 4] ^ expandedKey[ii * 16 + 0]) & 0xff);
            expandedKey[ii * 16 + 5] = (byte) ((expandedKey[(ii - 1) * 16 + 5] ^ expandedKey[ii * 16 + 1]) & 0xff);
            expandedKey[ii * 16 + 6] = (byte) ((expandedKey[(ii - 1) * 16 + 6] ^ expandedKey[ii * 16 + 2]) & 0xff);
            expandedKey[ii * 16 + 7] = (byte) ((expandedKey[(ii - 1) * 16 + 7] ^ expandedKey[ii * 16 + 3]) & 0xff);
            expandedKey[ii * 16 + 8] = (byte) ((expandedKey[(ii - 1) * 16 + 8] ^ expandedKey[ii * 16 + 4]) & 0xff);
            expandedKey[ii * 16 + 9] = (byte) ((expandedKey[(ii - 1) * 16 + 9] ^ expandedKey[ii * 16 + 5]) & 0xff);
            expandedKey[ii * 16 + 10] = (byte) ((expandedKey[(ii - 1) * 16 + 10] ^ expandedKey[ii * 16 + 6]) & 0xff);
            expandedKey[ii * 16 + 11] = (byte) ((expandedKey[(ii - 1) * 16 + 11] ^ expandedKey[ii * 16 + 7]) & 0xff);
            expandedKey[ii * 16 + 12] = (byte) ((expandedKey[(ii - 1) * 16 + 12] ^ expandedKey[ii * 16 + 8]) & 0xff);
            expandedKey[ii * 16 + 13] = (byte) ((expandedKey[(ii - 1) * 16 + 13] ^ expandedKey[ii * 16 + 9]) & 0xff);
            expandedKey[ii * 16 + 14] = (byte) ((expandedKey[(ii - 1) * 16 + 14] ^ expandedKey[ii * 16 + 10]) & 0xff);
            expandedKey[ii * 16 + 15] = (byte) ((expandedKey[(ii - 1) * 16 + 15] ^ expandedKey[ii * 16 + 11]) & 0xff);
        }
        return expandedKey;
    }

    // multiply by 2 in the galois field
    private static byte galois_mul2(byte value) {
        if (value >> 7 != 0x00) {
            value = (byte) ((value << 1) & 0xff);
            return (byte) ((value ^ 0x1b) & 0xff);
        } else {
            return (byte) ((value << 1) & 0xff);
        }
    }

    // straight foreward aes encryption implementation
//   first the group of operations
//     - addroundkey
//     - subbytes
//     - shiftrows
//     - mixcolums
//   is executed 9 times, after this addroundkey to finish the 9th round,
//   after that the 10th round without mixcolums
//   no further subfunctions to save cycles for function calls
//   no structuring with "for (....)" to save cycles
    private static byte[] aes_encr(byte[] input, byte[] expandedKey) {
        byte buf1, buf2, buf3, round;
        byte[] state = new byte[input.length];
        for (int i = 0; i < input.length; i++) {
            state[i] = input[i];
        }
        for (round = 0; round < 9; round++) {
            // addroundkey, sbox and shiftrows
            // row 0
            state[0] = sbox[(state[0] ^ expandedKey[(round * 16)]) & 0xff];
            state[4] = sbox[(state[4] ^ expandedKey[(round * 16) + 4]) & 0xff];
            state[8] = sbox[(state[8] ^ expandedKey[(round * 16) + 8]) & 0xff];
            state[12] = sbox[(state[12] ^ expandedKey[(round * 16) + 12]) & 0xff];
            // row 1
            buf1 = (byte) ((state[1] ^ expandedKey[(round * 16) + 1]) & 0xff);
            state[1] = sbox[(state[5] ^ expandedKey[(round * 16) + 5]) & 0xff];
            state[5] = sbox[(state[9] ^ expandedKey[(round * 16) + 9]) & 0xff];
            state[9] = sbox[(state[13] ^ expandedKey[(round * 16) + 13]) & 0xff];
            state[13] = sbox[buf1 & 0xff];
            // row 2
            buf1 = (byte) ((state[2] ^ expandedKey[(round * 16) + 2]) & 0xff);
            buf2 = (byte) ((state[6] ^ expandedKey[(round * 16) + 6]) & 0xff);
            state[2] = sbox[(state[10] ^ expandedKey[(round * 16) + 10]) & 0xff];
            state[6] = sbox[(state[14] ^ expandedKey[(round * 16) + 14]) & 0xff];
            state[10] = sbox[buf1 & 0xff];
            state[14] = sbox[buf2 & 0xff];
            // row 3
            buf1 = (byte) ((state[15] ^ expandedKey[(round * 16) + 15]) & 0xff);
            state[15] = sbox[(state[11] ^ expandedKey[(round * 16) + 11]) & 0xff];
            state[11] = sbox[(state[7] ^ expandedKey[(round * 16) + 7]) & 0xff];
            state[7] = sbox[(state[3] ^ expandedKey[(round * 16) + 3]) & 0xff];
            state[3] = sbox[buf1 & 0xff];
            // mixcolums //////////
            // col1
            buf1 = (byte) ((state[0] ^ state[1] ^ state[2] ^ state[3]) & 0xff);
            buf2 = state[0];
            buf3 = (byte) ((state[0] ^ state[1]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[0] = (byte) ((state[0] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[1] ^ state[2]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[1] = (byte) ((state[1] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[2] ^ state[3]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[2] = (byte) ((state[2] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[3] ^ buf2) & 0xff);
            buf3 = galois_mul2(buf3);
            state[3] = (byte) ((state[3] ^ buf3 ^ buf1) & 0xff);
            // col2
            buf1 = (byte) ((state[4] ^ state[5] ^ state[6] ^ state[7]) & 0xff);
            buf2 = state[4];
            buf3 = (byte) ((state[4] ^ state[5]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[4] = (byte) ((state[4] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[5] ^ state[6]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[5] = (byte) ((state[5] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[6] ^ state[7]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[6] = (byte) ((state[6] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[7] ^ buf2) & 0xff);
            buf3 = galois_mul2(buf3);
            state[7] = (byte) ((state[7] ^ buf3 ^ buf1) & 0xff);
            // col3
            buf1 = (byte) ((state[8] ^ state[9] ^ state[10] ^ state[11]) & 0xff);
            buf2 = state[8];
            buf3 = (byte) ((state[8] ^ state[9]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[8] = (byte) ((state[8] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[9] ^ state[10]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[9] = (byte) ((state[9] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[10] ^ state[11]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[10] = (byte) ((state[10] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[11] ^ buf2) & 0xff);
            buf3 = galois_mul2(buf3);
            state[11] = (byte) ((state[11] ^ buf3 ^ buf1) & 0xff);
            // col4
            buf1 = (byte) ((state[12] ^ state[13] ^ state[14] ^ state[15]) & 0xff);
            buf2 = state[12];
            buf3 = (byte) ((state[12] ^ state[13]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[12] = (byte) ((state[12] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[13] ^ state[14]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[13] = (byte) ((state[13] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[14] ^ state[15]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[14] = (byte) ((state[14] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[15] ^ buf2) & 0xff);
            buf3 = galois_mul2(buf3);
            state[15] = (byte) ((state[15] ^ buf3 ^ buf1) & 0xff);
        }
        // 10th round without mixcols
        state[0] = sbox[(state[0] ^ expandedKey[(round * 16)]) & 0xff];
        state[4] = sbox[(state[4] ^ expandedKey[(round * 16) + 4]) & 0xff];
        state[8] = sbox[(state[8] ^ expandedKey[(round * 16) + 8]) & 0xff];
        state[12] = sbox[(state[12] ^ expandedKey[(round * 16) + 12]) & 0xff];
        // row 1
        buf1 = (byte) ((state[1] ^ expandedKey[(round * 16) + 1]) & 0xff);
        state[1] = sbox[(state[5] ^ expandedKey[(round * 16) + 5]) & 0xff];
        state[5] = sbox[(state[9] ^ expandedKey[(round * 16) + 9]) & 0xff];
        state[9] = sbox[(state[13] ^ expandedKey[(round * 16) + 13]) & 0xff];
        state[13] = sbox[buf1 & 0xff];
        // row 2
        buf1 = (byte) ((state[2] ^ expandedKey[(round * 16) + 2]) & 0xff);
        buf2 = (byte) ((state[6] ^ expandedKey[(round * 16) + 6]) & 0xff);
        state[2] = sbox[(state[10] ^ expandedKey[(round * 16) + 10]) & 0xff];
        state[6] = sbox[(state[14] ^ expandedKey[(round * 16) + 14]) & 0xff];
        state[10] = sbox[buf1 & 0xff];
        state[14] = sbox[buf2 & 0xff];
        // row 3
        buf1 = (byte) ((state[15] ^ expandedKey[(round * 16) + 15]) & 0xff);
        state[15] = sbox[(state[11] ^ expandedKey[(round * 16) + 11]) & 0xff];
        state[11] = sbox[(state[7] ^ expandedKey[(round * 16) + 7]) & 0xff];
        state[7] = sbox[(state[3] ^ expandedKey[(round * 16) + 3]) & 0xff];
        state[3] = sbox[buf1 & 0xff];
        // last addroundkey
        state[0] ^= expandedKey[160];
        state[1] ^= expandedKey[161];
        state[2] ^= expandedKey[162];
        state[3] ^= expandedKey[163];
        state[4] ^= expandedKey[164];
        state[5] ^= expandedKey[165];
        state[6] ^= expandedKey[166];
        state[7] ^= expandedKey[167];
        state[8] ^= expandedKey[168];
        state[9] ^= expandedKey[169];
        state[10] ^= expandedKey[170];
        state[11] ^= expandedKey[171];
        state[12] ^= expandedKey[172];
        state[13] ^= expandedKey[173];
        state[14] ^= expandedKey[174];
        state[15] ^= expandedKey[175];
        return state;
    }

    // straight foreward aes decryption implementation
//   the order of substeps is the exact reverse of decryption
//   inverse functions:
//       - addRoundKey is its own inverse
//       - rsbox is inverse of sbox
//       - rightshift instead of leftshift
//       - invMixColumns = barreto + mixColumns
//   no further subfunctions to save cycles for function calls
//   no structuring with "for (....)" to save cycles
    private static byte[] aes_decr(byte[] input, byte[] expandedKey) {
        byte buf1, buf2, buf3;
        byte round;
        round = 9;
        byte[] state = new byte[input.length];
        for (int i = 0; i < input.length; i++) {
            state[i] = input[i];
        }
        // initial addroundkey
        state[0] ^= expandedKey[160];
        state[1] ^= expandedKey[161];
        state[2] ^= expandedKey[162];
        state[3] ^= expandedKey[163];
        state[4] ^= expandedKey[164];
        state[5] ^= expandedKey[165];
        state[6] ^= expandedKey[166];
        state[7] ^= expandedKey[167];
        state[8] ^= expandedKey[168];
        state[9] ^= expandedKey[169];
        state[10] ^= expandedKey[170];
        state[11] ^= expandedKey[171];
        state[12] ^= expandedKey[172];
        state[13] ^= expandedKey[173];
        state[14] ^= expandedKey[174];
        state[15] ^= expandedKey[175];

        // 10th round without mixcols
        state[0] = (byte) ((rsbox[state[0] & 0xff] ^ expandedKey[(round * 16)]) & 0xff);
        state[4] = (byte) ((rsbox[state[4] & 0xff] ^ expandedKey[(round * 16) + 4]) & 0xff);
        state[8] = (byte) ((rsbox[state[8] & 0xff] ^ expandedKey[(round * 16) + 8]) & 0xff);
        state[12] = (byte) ((rsbox[state[12] & 0xff] ^ expandedKey[(round * 16) + 12]) & 0xff);
        // row 1
        buf1 = (byte) ((rsbox[state[13] & 0xff] ^ expandedKey[(round * 16) + 1]) & 0xff);
        state[13] = (byte) ((rsbox[state[9] & 0xff] ^ expandedKey[(round * 16) + 13]) & 0xff);
        state[9] = (byte) ((rsbox[state[5] & 0xff] ^ expandedKey[(round * 16) + 9]) & 0xff);
        state[5] = (byte) ((rsbox[state[1] & 0xff] ^ expandedKey[(round * 16) + 5]) & 0xff);
        state[1] = buf1;
        // row 2
        buf1 = (byte) ((rsbox[state[2] & 0xff] ^ expandedKey[(round * 16) + 10]) & 0xff);
        buf2 = (byte) ((rsbox[state[6] & 0xff] ^ expandedKey[(round * 16) + 14]) & 0xff);
        state[2] = (byte) ((rsbox[state[10] & 0xff] ^ expandedKey[(round * 16) + 2]) & 0xff);
        state[6] = (byte) ((rsbox[state[14] & 0xff] ^ expandedKey[(round * 16) + 6]) & 0xff);
        state[10] = buf1;
        state[14] = buf2;
        // row 3
        buf1 = (byte) ((rsbox[state[3] & 0xff] ^ expandedKey[(round * 16) + 15]) & 0xff);
        state[3] = (byte) ((rsbox[state[7] & 0xff] ^ expandedKey[(round * 16) + 3]) & 0xff);
        state[7] = (byte) ((rsbox[state[11] & 0xff] ^ expandedKey[(round * 16) + 7]) & 0xff);
        state[11] = (byte) ((rsbox[state[15] & 0xff] ^ expandedKey[(round * 16) + 11]) & 0xff);
        state[15] = buf1;

        for (round = 8; round >= 0; round--) {
            // barreto
            //col1
            buf1 = galois_mul2(galois_mul2((byte) ((state[0] ^ state[2]) & 0xff)));
            buf2 = galois_mul2(galois_mul2((byte) ((state[1] ^ state[3]) & 0xff)));
            state[0] ^= buf1;
            state[1] ^= buf2;
            state[2] ^= buf1;
            state[3] ^= buf2;
            //col2
            buf1 = galois_mul2(galois_mul2((byte) ((state[4] ^ state[6]) & 0xff)));
            buf2 = galois_mul2(galois_mul2((byte) ((state[5] ^ state[7]) & 0xff)));
            state[4] ^= buf1;
            state[5] ^= buf2;
            state[6] ^= buf1;
            state[7] ^= buf2;
            //col3
            buf1 = galois_mul2(galois_mul2((byte) ((state[8] ^ state[10]) & 0xff)));
            buf2 = galois_mul2(galois_mul2((byte) ((state[9] ^ state[11]) & 0xff)));
            state[8] ^= buf1;
            state[9] ^= buf2;
            state[10] ^= buf1;
            state[11] ^= buf2;
            //col4
            buf1 = galois_mul2(galois_mul2((byte) ((state[12] ^ state[14]) & 0xff)));
            buf2 = galois_mul2(galois_mul2((byte) ((state[13] ^ state[15]) & 0xff)));
            state[12] ^= buf1;
            state[13] ^= buf2;
            state[14] ^= buf1;
            state[15] ^= buf2;
            // mixcolums //////////
            // col1
            buf1 = (byte) ((state[0] ^ state[1] ^ state[2] ^ state[3]) & 0xff);
            buf2 = state[0];
            buf3 = (byte) ((state[0] ^ state[1]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[0] = (byte) ((state[0] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[1] ^ state[2]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[1] = (byte) ((state[1] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[2] ^ state[3]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[2] = (byte) ((state[2] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[3] ^ buf2) & 0xff);
            buf3 = galois_mul2(buf3);
            state[3] = (byte) ((state[3] ^ buf3 ^ buf1) & 0xff);
            // col2
            buf1 = (byte) ((state[4] ^ state[5] ^ state[6] ^ state[7]) & 0xff);
            buf2 = state[4];
            buf3 = (byte) ((state[4] ^ state[5]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[4] = (byte) ((state[4] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[5] ^ state[6]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[5] = (byte) ((state[5] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[6] ^ state[7]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[6] = (byte) ((state[6] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[7] ^ buf2) & 0xff);
            buf3 = galois_mul2(buf3);
            state[7] = (byte) ((state[7] ^ buf3 ^ buf1) & 0xff);
            // col3
            buf1 = (byte) ((state[8] ^ state[9] ^ state[10] ^ state[11]) & 0xff);
            buf2 = state[8];
            buf3 = (byte) ((state[8] ^ state[9]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[8] = (byte) ((state[8] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[9] ^ state[10]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[9] = (byte) ((state[9] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[10] ^ state[11]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[10] = (byte) ((state[10] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[11] ^ buf2) & 0xff);
            buf3 = galois_mul2(buf3);
            state[11] = (byte) ((state[11] ^ buf3 ^ buf1) & 0xff);
            // col4
            buf1 = (byte) ((state[12] ^ state[13] ^ state[14] ^ state[15]) & 0xff);
            buf2 = state[12];
            buf3 = (byte) ((state[12] ^ state[13]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[12] = (byte) ((state[12] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[13] ^ state[14]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[13] = (byte) ((state[13] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[14] ^ state[15]) & 0xff);
            buf3 = galois_mul2(buf3);
            state[14] = (byte) ((state[14] ^ buf3 ^ buf1) & 0xff);
            buf3 = (byte) ((state[15] ^ buf2) & 0xff);
            buf3 = galois_mul2(buf3);
            state[15] = (byte) ((state[15] ^ buf3 ^ buf1) & 0xff);
            // addroundkey, rsbox and shiftrows
            // row 0
            state[0] = (byte) ((rsbox[state[0] & 0xff] ^ expandedKey[(round * 16)]) & 0xff);
            state[4] = (byte) ((rsbox[state[4] & 0xff] ^ expandedKey[(round * 16) + 4]) & 0xff);
            state[8] = (byte) ((rsbox[state[8] & 0xff] ^ expandedKey[(round * 16) + 8]) & 0xff);
            state[12] = (byte) ((rsbox[state[12] & 0xff] ^ expandedKey[(round * 16) + 12]) & 0xff);
            // row 1
            buf1 = (byte) ((rsbox[state[13] & 0xff] ^ expandedKey[(round * 16) + 1]) & 0xff);
            state[13] = (byte) ((rsbox[state[9] & 0xff] ^ expandedKey[(round * 16) + 13]) & 0xff);
            state[9] = (byte) ((rsbox[state[5] & 0xff] ^ expandedKey[(round * 16) + 9]) & 0xff);
            state[5] = (byte) ((rsbox[state[1] & 0xff] ^ expandedKey[(round * 16) + 5]) & 0xff);
            state[1] = buf1;
            // row 2
            buf1 = (byte) ((rsbox[state[2] & 0xff] ^ expandedKey[(round * 16) + 10]) & 0xff);
            buf2 = (byte) ((rsbox[state[6] & 0xff] ^ expandedKey[(round * 16) + 14]) & 0xff);
            state[2] = (byte) ((rsbox[state[10] & 0xff] ^ expandedKey[(round * 16) + 2]) & 0xff);
            state[6] = (byte) ((rsbox[state[14] & 0xff] ^ expandedKey[(round * 16) + 6]) & 0xff);
            state[10] = buf1;
            state[14] = buf2;
            // row 3
            buf1 = (byte) ((rsbox[state[3] & 0xff] ^ expandedKey[(round * 16) + 15]) & 0xff);
            state[3] = (byte) ((rsbox[state[7] & 0xff] ^ expandedKey[(round * 16) + 3]) & 0xff);
            state[7] = (byte) ((rsbox[state[11] & 0xff] ^ expandedKey[(round * 16) + 7]) & 0xff);
            state[11] = (byte) ((rsbox[state[15] & 0xff] ^ expandedKey[(round * 16) + 11]) & 0xff);
            state[15] = buf1;
        }
        return state;
    }

    public static byte[] decode16(byte[] data, byte[] key) {
        byte[] expandedKey = expandKey(key);
        return aes_decr(data, expandedKey);
    }

    public static byte[] encode16(byte[] data, byte[] key) {
        byte[] expandedKey = expandKey(key);
        return aes_encr(data, expandedKey);
    }

    public static byte[] decode(byte[] data, byte[] key) {
        byte[] result = new byte[0];
        for (int i = 0; i < data.length / 16; i++) {
            byte[] temp = ByteUtils.subBytes(data, i * 16, 16);
            result = ByteUtils.combineByteArray(result, decode16(temp, key));
        }
        return result;
    }

    public static byte[] encode(byte[] data, byte[] key) {
        byte[] result = new byte[0];
        for (int i = 0; i < data.length / 16; i++) {
            byte[] temp = ByteUtils.subBytes(data, i * 16, 16);
            result = ByteUtils.combineByteArray(result, encode16(temp, key));
        }
        return result;
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/encryption/CRC.java
================================================
package com.luo.bluetooth.encryption;

public class CRC {
    static byte[] crc8_tab = { (byte) 0, (byte) 94, (byte) 188, (byte) 226, (byte) 97, (byte) 63, (byte) 221, (byte) 131, (byte) 194, (byte) 156, (byte) 126, (byte) 32, (byte) 163, (byte) 253, (byte) 31, (byte) 65, (byte) 157, (byte) 195, (byte) 33, (byte) 127, (byte) 252, (byte) 162, (byte) 64, (byte) 30, (byte) 95, (byte) 1, (byte) 227, (byte) 189, (byte) 62, (byte) 96, (byte) 130, (byte) 220, (byte) 35, (byte) 125, (byte) 159, (byte) 193, (byte) 66, (byte) 28, (byte) 254, (byte) 160, (byte) 225, (byte) 191, (byte) 93, (byte) 3, (byte) 128, (byte) 222, (byte) 60, (byte) 98, (byte) 190, (byte) 224, (byte) 2, (byte) 92, (byte) 223, (byte) 129, (byte) 99, (byte) 61, (byte) 124, (byte) 34, (byte) 192, (byte) 158, (byte) 29, (byte) 67, (byte) 161, (byte) 255, (byte) 70, (byte) 24,
            (byte) 250, (byte) 164, (byte) 39, (byte) 121, (byte) 155, (byte) 197, (byte) 132, (byte) 218, (byte) 56, (byte) 102, (byte) 229, (byte) 187, (byte) 89, (byte) 7, (byte) 219, (byte) 133, (byte) 103, (byte) 57, (byte) 186, (byte) 228, (byte) 6, (byte) 88, (byte) 25, (byte) 71, (byte) 165, (byte) 251, (byte) 120, (byte) 38, (byte) 196, (byte) 154, (byte) 101, (byte) 59, (byte) 217, (byte) 135, (byte) 4, (byte) 90, (byte) 184, (byte) 230, (byte) 167, (byte) 249, (byte) 27, (byte) 69, (byte) 198, (byte) 152, (byte) 122, (byte) 36, (byte) 248, (byte) 166, (byte) 68, (byte) 26, (byte) 153, (byte) 199, (byte) 37, (byte) 123, (byte) 58, (byte) 100, (byte) 134, (byte) 216, (byte) 91, (byte) 5, (byte) 231, (byte) 185, (byte) 140, (byte) 210, (byte) 48, (byte) 110, (byte) 237,
            (byte) 179, (byte) 81, (byte) 15, (byte) 78, (byte) 16, (byte) 242, (byte) 172, (byte) 47, (byte) 113, (byte) 147, (byte) 205, (byte) 17, (byte) 79, (byte) 173, (byte) 243, (byte) 112, (byte) 46, (byte) 204, (byte) 146, (byte) 211, (byte) 141, (byte) 111, (byte) 49, (byte) 178, (byte) 236, (byte) 14, (byte) 80, (byte) 175, (byte) 241, (byte) 19, (byte) 77, (byte) 206, (byte) 144, (byte) 114, (byte) 44, (byte) 109, (byte) 51, (byte) 209, (byte) 143, (byte) 12, (byte) 82, (byte) 176, (byte) 238, (byte) 50, (byte) 108, (byte) 142, (byte) 208, (byte) 83, (byte) 13, (byte) 239, (byte) 177, (byte) 240, (byte) 174, (byte) 76, (byte) 18, (byte) 145, (byte) 207, (byte) 45, (byte) 115, (byte) 202, (byte) 148, (byte) 118, (byte) 40, (byte) 171, (byte) 245, (byte) 23, (byte) 73, (byte) 8,
            (byte) 86, (byte) 180, (byte) 234, (byte) 105, (byte) 55, (byte) 213, (byte) 139, (byte) 87, (byte) 9, (byte) 235, (byte) 181, (byte) 54, (byte) 104, (byte) 138, (byte) 212, (byte) 149, (byte) 203, (byte) 41, (byte) 119, (byte) 244, (byte) 170, (byte) 72, (byte) 22, (byte) 233, (byte) 183, (byte) 85, (byte) 11, (byte) 136, (byte) 214, (byte) 52, (byte) 106, (byte) 43, (byte) 117, (byte) 151, (byte) 201, (byte) 74, (byte) 20, (byte) 246, (byte) 168, (byte) 116, (byte) 42, (byte) 200, (byte) 150, (byte) 21, (byte) 75, (byte) 169, (byte) 247, (byte) 182, (byte) 232, (byte) 10, (byte) 84, (byte) 215, (byte) 137, (byte) 107, 53 };

    /**
     * 计算数组的CRC8校验值
     *
     * @param data
     *            需要计算的数组
     * @return CRC8校验值
     */
    public static byte calcCrc(byte[] data) {
        return calcCrc8(data, 0, data.length, (byte) 0);
    }

    /**
     * 计算CRC8校验值
     *
     * @param data
     *            数据
     * @param offset
     *            起始位置
     * @param len
     *            长度
     * @return 校验值
     */
    public static byte calcCrc8(byte[] data, int offset, int len) {
        byte result = data[0];
        for (int i = 1; i < len; i++) {
            result ^= data[i];
        }
        return result;
//        return calcCrc8(data, offset, len, (byte) 0);
    }

    /**
     * 计算CRC8校验值
     *
     * @param data
     *            数据
     * @param offset
     *            起始位置
     * @param len
     *            长度
     * @param preval
     *            之前的校验值
     * @return 校验值
     */
    public static byte calcCrc8(byte[] data, int offset, int len, byte preval) {
        byte ret = preval;
        for (int i = offset; i < (offset + len); ++i) {
            ret = crc8_tab[(0x00ff & (ret ^ data[i]))];
        }
        return ret;
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/protocol/CRC16Utils.java
================================================
/**
 * Copyright (C), 2007-2021, 未来穿戴有限公司
 * FileName: CRC16Utils
 * Author: Antier
 * Date: 2021/7/16 11:46
 * Description: 用一句话描述下
 */
package com.luo.bluetooth.protocol;

import android.util.Log;

/**
 * @ProjectName: SKG
 * @Package: com.king.bluetooth.protocol.neck.util
 * @ClassName: CRC16Utils
 * @Description: 用一句话描述下
 * @Author: Aniter
 * @CreateDate: 2021/7/16 11:46
 */
class CRC16Utils {
    static byte[] crc16_tab_h = {(byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0,
            (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1,
            (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
            (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
            (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40};

    static byte[] crc16_tab_l = {(byte) 0x00, (byte) 0xC0, (byte) 0xC1, (byte) 0x01, (byte) 0xC3, (byte) 0x03, (byte) 0x02, (byte) 0xC2, (byte) 0xC6, (byte) 0x06, (byte) 0x07, (byte) 0xC7, (byte) 0x05, (byte) 0xC5, (byte) 0xC4, (byte) 0x04, (byte) 0xCC, (byte) 0x0C, (byte) 0x0D, (byte) 0xCD, (byte) 0x0F, (byte) 0xCF, (byte) 0xCE, (byte) 0x0E, (byte) 0x0A, (byte) 0xCA, (byte) 0xCB, (byte) 0x0B, (byte) 0xC9, (byte) 0x09, (byte) 0x08, (byte) 0xC8, (byte) 0xD8, (byte) 0x18, (byte) 0x19, (byte) 0xD9, (byte) 0x1B, (byte) 0xDB, (byte) 0xDA, (byte) 0x1A, (byte) 0x1E, (byte) 0xDE, (byte) 0xDF, (byte) 0x1F, (byte) 0xDD, (byte) 0x1D, (byte) 0x1C, (byte) 0xDC, (byte) 0x14, (byte) 0xD4, (byte) 0xD5, (byte) 0x15, (byte) 0xD7, (byte) 0x17, (byte) 0x16, (byte) 0xD6, (byte) 0xD2, (byte) 0x12,
            (byte) 0x13, (byte) 0xD3, (byte) 0x11, (byte) 0xD1, (byte) 0xD0, (byte) 0x10, (byte) 0xF0, (byte) 0x30, (byte) 0x31, (byte) 0xF1, (byte) 0x33, (byte) 0xF3, (byte) 0xF2, (byte) 0x32, (byte) 0x36, (byte) 0xF6, (byte) 0xF7, (byte) 0x37, (byte) 0xF5, (byte) 0x35, (byte) 0x34, (byte) 0xF4, (byte) 0x3C, (byte) 0xFC, (byte) 0xFD, (byte) 0x3D, (byte) 0xFF, (byte) 0x3F, (byte) 0x3E, (byte) 0xFE, (byte) 0xFA, (byte) 0x3A, (byte) 0x3B, (byte) 0xFB, (byte) 0x39, (byte) 0xF9, (byte) 0xF8, (byte) 0x38, (byte) 0x28, (byte) 0xE8, (byte) 0xE9, (byte) 0x29, (byte) 0xEB, (byte) 0x2B, (byte) 0x2A, (byte) 0xEA, (byte) 0xEE, (byte) 0x2E, (byte) 0x2F, (byte) 0xEF, (byte) 0x2D, (byte) 0xED, (byte) 0xEC, (byte) 0x2C, (byte) 0xE4, (byte) 0x24, (byte) 0x25, (byte) 0xE5, (byte) 0x27, (byte) 0xE7,
            (byte) 0xE6, (byte) 0x26, (byte) 0x22, (byte) 0xE2, (byte) 0xE3, (byte) 0x23, (byte) 0xE1, (byte) 0x21, (byte) 0x20, (byte) 0xE0, (byte) 0xA0, (byte) 0x60, (byte) 0x61, (byte) 0xA1, (byte) 0x63, (byte) 0xA3, (byte) 0xA2, (byte) 0x62, (byte) 0x66, (byte) 0xA6, (byte) 0xA7, (byte) 0x67, (byte) 0xA5, (byte) 0x65, (byte) 0x64, (byte) 0xA4, (byte) 0x6C, (byte) 0xAC, (byte) 0xAD, (byte) 0x6D, (byte) 0xAF, (byte) 0x6F, (byte) 0x6E, (byte) 0xAE, (byte) 0xAA, (byte) 0x6A, (byte) 0x6B, (byte) 0xAB, (byte) 0x69, (byte) 0xA9, (byte) 0xA8, (byte) 0x68, (byte) 0x78, (byte) 0xB8, (byte) 0xB9, (byte) 0x79, (byte) 0xBB, (byte) 0x7B, (byte) 0x7A, (byte) 0xBA, (byte) 0xBE, (byte) 0x7E, (byte) 0x7F, (byte) 0xBF, (byte) 0x7D, (byte) 0xBD, (byte) 0xBC, (byte) 0x7C, (byte) 0xB4, (byte) 0x74,
            (byte) 0x75, (byte) 0xB5, (byte) 0x77, (byte) 0xB7, (byte) 0xB6, (byte) 0x76, (byte) 0x72, (byte) 0xB2, (byte) 0xB3, (byte) 0x73, (byte) 0xB1, (byte) 0x71, (byte) 0x70, (byte) 0xB0, (byte) 0x50, (byte) 0x90, (byte) 0x91, (byte) 0x51, (byte) 0x93, (byte) 0x53, (byte) 0x52, (byte) 0x92, (byte) 0x96, (byte) 0x56, (byte) 0x57, (byte) 0x97, (byte) 0x55, (byte) 0x95, (byte) 0x94, (byte) 0x54, (byte) 0x9C, (byte) 0x5C, (byte) 0x5D, (byte) 0x9D, (byte) 0x5F, (byte) 0x9F, (byte) 0x9E, (byte) 0x5E, (byte) 0x5A, (byte) 0x9A, (byte) 0x9B, (byte) 0x5B, (byte) 0x99, (byte) 0x59, (byte) 0x58, (byte) 0x98, (byte) 0x88, (byte) 0x48, (byte) 0x49, (byte) 0x89, (byte) 0x4B, (byte) 0x8B, (byte) 0x8A, (byte) 0x4A, (byte) 0x4E, (byte) 0x8E, (byte) 0x8F, (byte) 0x4F, (byte) 0x8D, (byte) 0x4D,
            (byte) 0x4C, (byte) 0x8C, (byte) 0x44, (byte) 0x84, (byte) 0x85, (byte) 0x45, (byte) 0x87, (byte) 0x47, (byte) 0x46, (byte) 0x86, (byte) 0x82, (byte) 0x42, (byte) 0x43, (byte) 0x83, (byte) 0x41, (byte) 0x81, (byte) 0x80, (byte) 0x40};

    /**
     * 计算CRC16校验  对外的接口
     *
     * @param data 需要计算的数组
     * @return CRC16校验值
     */
    public static int calcCrc16(byte[] data) {
        return calcCrc16(data, 0, data.length);
    }

    /**
     * 计算CRC16校验
     *
     * @param data   需要计算的数组
     * @param offset 起始位置
     * @param len    长度
     * @return CRC16校验值
     */
    public static int calcCrc16(byte[] data, int offset, int len) {
        return calcCrc16(data, offset, len, 0xffff);
    }

    /**
     * 计算CRC16校验
     *
     * @param data   需要计算的数组
     * @param offset 起始位置
     * @param len    长度
     * @param preval 之前的校验值
     * @return CRC16校验值
     */
    public static int calcCrc16(byte[] data, int offset, int len, int preval) {
        int ucCRCHi = (preval & 0xff00) >> 8;
        int ucCRCLo = preval & 0x00ff;
        int iIndex;
        for (int i = 0; i < len; ++i) {
            iIndex = (ucCRCLo ^ data[offset + i]) & 0x00ff;
            ucCRCLo = ucCRCHi ^ crc16_tab_h[iIndex];
            ucCRCHi = crc16_tab_l[iIndex];
        }
        return ((ucCRCHi & 0x00ff) << 8) | (ucCRCLo & 0x00ff) & 0xffff;
    }

    /**
     * 将计算的CRC值 转换为加空格的  比如  : crc值为 A30A -> A3 0A
     *
     * @param res
     * @return
     */
    public static String getCrc(int res) {
        String format = String.format("%04x", res);
        String substring = format.substring(0, 2);
        String substring1 = format.substring(2, 4);
        Log.i("BLUEDATA", "crc ---- : " + substring + "  " + substring1);
        return substring.concat(" ").concat(substring1).concat(" ");
    }
}

================================================
FILE: app/src/main/java/com/luo/bluetooth/protocol/CrcUtils.java
================================================
/**
 * Copyright (C), 2007-2022, 未来穿戴有限公司
 * FileName: CrcUtils
 * Author: lpq
 * Date: 2022/3/11 17:23
 * Description: 用一句话描述下
 */
package com.luo.bluetooth.protocol;

/**
 *
 * @ProjectName: Bluetooth
 * @Package: com.luo.bluetooth.protocol
 * @ClassName: CrcUtils
 * @Description: 用一句话描述下
 * @Author: lpq
 * @CreateDate: 2022/3/11 17:23
 */
public class CrcUtils {
    /**
     * crc校验
     */
    public static int Crc16Ccitt(int crc, byte[] data) {
        for (int i = 0; i < data.length; ++i) {
            crc = (crc >> 8) ^ s_tabCrc16CCITT[(crc ^ (data[i])) & 0xff];
        }
        return crc;
    }

    /*
     * CRC table for the CRC-16-CCITT. The poly is 0x8408 (x^16 + x^12 + x^5 + 1)
     */
    static int[] s_tabCrc16CCITT = new int[]{
            0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
            0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
            0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
            0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
            0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
            0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
            0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
            0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
            0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
            0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
            0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
            0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
            0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
            0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
            0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
            0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
            0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
            0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
            0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
            0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
            0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
            0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
            0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
            0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
            0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
            0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
            0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
            0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
            0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
            0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
            0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
            0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
    };
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/protocol/CustomEventListener.java
================================================
package com.luo.bluetooth.protocol;

import com.stag.bluetooth.protocol.OnEventListener;

/**
 * 一些由设备端主动发起的蓝牙事件的监听
 */
public interface CustomEventListener extends OnEventListener {
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/protocol/CustomPacket.java
================================================
package com.luo.bluetooth.protocol;

import com.stag.bluetooth.packet.Packet;

public class CustomPacket extends Packet {
    private byte expandCode; // 扩展码:0x55->读;0x66->写;0xAA->读回应;0x99->写回应

    public CustomPacket(int cmd, byte expandCode) {
        super(cmd);
        this.expandCode = expandCode;
    }

    public CustomPacket(int cmd, byte[] data, byte expandCode) {
        super(cmd, data);
        this.expandCode = expandCode;
    }

    public byte getExpandCode() {
        return expandCode;
    }

    /**
     * 用于判断发送的命令是否已经收到回应,没有收到回应底层会重发一次数据
     * @param recvPacket 接收到的字节数据处理的结果包
     * @return
     */
    @Override
    public boolean match(Packet recvPacket) {
        return super.match(recvPacket);
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/protocol/CustomProtocol.java
================================================
package com.luo.bluetooth.protocol;


import android.content.Context;
import android.util.Log;

import com.luo.bluetooth.utils.ByteUtils;
import com.stag.bluetooth.protocol.ParseResult;
import com.stag.bluetooth.protocol.Protocol;
import com.stag.bluetooth.protocol.ResultType;
import com.stag.bluetooth.util.LogUtils;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class CustomProtocol extends Protocol<CustomPacket, CustomEventListener> {

    private static final String TAG = "DscpProtocol";

    private final Object recvParseLock = null;

    private final byte FRAME_HEADER = 0x7B;  // 帧头
    private final byte DST_PATH_LEN = 0x01;  // 目标路径长度: 多设备拓展长设置,目前只有0x01
    private final byte DEVICE_ADDRESS = 0x10;  // 地址区域:01->血糖仪;0x20->主机设备
    private final byte PHONE_ADDRESS = 0x20;   // 地址区域:01->血糖仪;0x20->主机设备
    private final byte SRC_PATH_LEN = 0x01;  // 源路径长度:多设备拓展长设置,目前只有0x01
    private final byte EXPAND_CODE = 0x55;   // 扩展码:0x55->读;0x66->写;0xAA->读回应;0x99->写回应
    private final byte FRAME_END = 0x7D;     // 帧尾
    private final int BUFFER_SIZE = 256;

    private ByteBuffer recvBuffer;
    private CustomPacket recvPacket;

    protected CustomProtocol(Context context) {
        super(context);
    }

    public CustomProtocol(Context context, CustomEventListener listener) {
        super(context, listener);
    }

    @Override
    public synchronized byte[] packetToBytes(CustomPacket packet) {
        /**
         * 0x7B:帧头
         * 0x01:目标路径长度
         * 0x10:目标地址区域
         * 0x01:源路径长度
         * 0x20:源地址区域
         * 0x77:获取SN信息功能码
         * 0x55:扩展码 read
         * 0x00 0x00:通讯数据长度
         * 0x00 ...0x00:通讯数据
         * 0x01 0x0B 0x0B 0x04:校验码
         * 0x7D:帧尾
         */
        //实际打包
        int cmd = packet.getCmd();
        byte[] cmdData = packet.getData();
        byte expandCode = packet.getExpandCode();
        ArrayList<Byte> byteList = new ArrayList<Byte>();
        // 1、加入目标路径长度,目标地址区域,源路径长度,源地址区域
        byteList.add(DST_PATH_LEN);
        byteList.add(DEVICE_ADDRESS);
        byteList.add(SRC_PATH_LEN);
        byteList.add(PHONE_ADDRESS);
        LogUtils.d(TAG + "lpq", "1、加入基础头部:" + ByteUtils.toString(listToByte(byteList)));
        // 2、加入功能码
        byteList.add((byte) cmd);
        LogUtils.d(TAG + "lpq", "2、加入功能码:" + ByteUtils.toString(listToByte(byteList)));
        // 3、加入扩展码
        byteList.add(expandCode);
        LogUtils.d(TAG + "lpq", "3、加入扩展码:" + ByteUtils.toString(listToByte(byteList)));
        // 4、加入通讯数据
        if (cmdData != null && cmdData.length != 0) {
            byte[] cmdDataLenBytes = ByteUtils.intToBytes2(cmdData.length);
            byteList.add(cmdDataLenBytes[0]);
            byteList.add(cmdDataLenBytes[1]);
            for (byte temp : cmdData) {
                byteList.add(temp);
            }
        } else {
            byteList.add((byte) 0x0);
            byteList.add((byte) 0x0);
        }
        Log.i("lpq", "packetToBytes: 4、加入通讯数据:" + ByteUtils.toString(listToByte(byteList)));
        // 5、加入校验码
        int crcResult = CRC16Utils.calcCrc16(listToByte(byteList));
        byte[] crcBytes = ByteUtils.intToBytes2(crcResult);
        Log.i("lpq", "packetToBytes: 5、校验码原值:" + ByteUtils.toString(crcBytes));
        byteList.add((byte) ((crcBytes[1] >> 4) & 0x0f));
        byteList.add((byte) (crcBytes[1] & 0x0f));
        byteList.add((byte) ((crcBytes[0] >> 4) & 0x0f));
        byteList.add((byte) (crcBytes[0] & 0x0f));
        LogUtils.d(TAG + "lpq", "5、加入校验码后:" + ByteUtils.toString(listToByte(byteList)));

        // 6、加入头尾帧
        byteList.add(0, FRAME_HEADER);
        byteList.add(FRAME_END);
        LogUtils.d(TAG + "lpq", "6、加入头尾帧:" + ByteUtils.toString(listToByte(byteList)));

        return listToByte(byteList);
    }

    @Override
    public ParseResult parse(byte[] data) {
        LogUtils.d(TAG + "lpq", "蓝牙接收到数据:data = " + ByteUtils.toString(data));
        recvPacket = null;
        final ParseResult result = new ParseResult();
        if (recvBuffer.position() > 0) {
            if (recvBuffer.get(0) != FRAME_HEADER) {
                recvBuffer.clear();
            }
        }
        recvBuffer.put(data);
        LogUtils.d(TAG + "lpq", "parse: " + ByteUtils.toString(recvBuffer.array()));
        LogUtils.d(TAG + "lpq", "parse: position = " + recvBuffer.position());
        if (recvBuffer.get(recvBuffer.position() - 1) != FRAME_END) {
            result.setType(ResultType.INCOMPLETE);
            return result;
        }
        synchronized (recvParseLock) {
            byte[] temp = ByteUtils.subBytes(recvBuffer.array(), 0, recvBuffer.position());
            List<Byte> byteList = byteToList(temp);

            //开始解包
            // 1、去掉包头包尾
            byteList.remove(0);
            byteList.remove(byteList.size() - 1);
            LogUtils.d(TAG + "lpq", "1、去掉包头包尾后:" + ByteUtils.toString(listToByte(byteList)));

            // 2、CRC校验
            // 获取校验码
            byte[] crcOrigin = new byte[4];
            crcOrigin[3] = byteList.remove(byteList.size() - 1);
            crcOrigin[2] = byteList.remove(byteList.size() - 1);
            crcOrigin[1] = byteList.remove(byteList.size() - 1);
            crcOrigin[0] = byteList.remove(byteList.size() - 1);
            // 计算校验码
            int crcResult = CRC16Utils.calcCrc16(listToByte(byteList));
            byte[] crcBytes = ByteUtils.intToBytes2(crcResult);
            Log.i("lpq", "packetToBytes: 2、校验码原值:" + ByteUtils.toString(crcOrigin));
            byte[] crcCount = new byte[4];
            crcCount[0] = ((byte) ((crcBytes[1] >> 4) & 0x0f));
            crcCount[1] = ((byte) (crcBytes[1] & 0x0f));
            crcCount[2] = ((byte) ((crcBytes[0] >> 4) & 0x0f));
            crcCount[3] = ((byte) (crcBytes[0] & 0x0f));
            Log.i("lpq", "packetToBytes: 2、校验码计算值:" + ByteUtils.toString(crcCount));
            if (crcOrigin[0] == crcCount[0] && crcOrigin[1] == crcCount[1]
                    && crcOrigin[2] == crcCount[2] && crcOrigin[3] == crcCount[3]) {
                Log.i("lpq", "parse: 校验成功");
            } else {
                Log.i("lpq", "parse: 校验失败");
            }

            // 3、去除目标路径长度,目标地址区域,源路径长度,源地址区域
            byteList.remove(0);
            byteList.remove(0);
            byteList.remove(0);
            byteList.remove(0);
            LogUtils.d(TAG + "lpq", "3、去除基础头部:" + ByteUtils.toString(listToByte(byteList)));

            // 4、获取功能码
            int cmd = byteList.remove(0);
            byte expandCode = byteList.remove(0);
            LogUtils.d(TAG + "lpq", "4、获取功能码:" + ByteUtils.toString(listToByte(byteList)));

            // 5、获取通讯数据
            byte[] lenBytes = new byte[2];
            lenBytes[0] = byteList.remove(0);
            lenBytes[1] = byteList.remove(0);
            int cmdDataLen = ByteUtils.bytesToInt(lenBytes);
            byte[] cmdData = listToByte(byteList);
            LogUtils.d(TAG + "lpq", "5、获取通讯数据:" + ByteUtils.toString(listToByte(byteList)));

            recvPacket = new CustomPacket(cmd, cmdData, expandCode);
            LogUtils.d(TAG + "lpq", "parse: " + recvPacket.toString());
        }
        result.setPacket(recvPacket);
        switch (recvPacket.getCmd()) {
            // 设备主动上传设备状态
//                if (haveSetEventListener()) {
//                    result.setCallback(new BluetoothDispatch.Callback() {
//                        @Override
//                        public void callback() {
//                            getEventListener().onRecvDeviceStatus(recvPacket.getData());
//                        }
//                    });
//                }
//                result.setType(ACTIVE);
            default://理论上都是待响应事件
                result.setType(ResultType.RESPOND);
                break;
        }

        recvBuffer.clear();
        return result;
    }

    /**
     * list转换成byte
     */
    private byte[] listToByte(List<Byte> byteList) {
        if (null == byteList || byteList.size() == 0) {
            return null;
        }
        byte[] bytes = new byte[byteList.size()];
        for (int i = 0; i < byteList.size(); ++i) {
            bytes[i] = byteList.get(i);
        }
        return bytes;
    }

    private List<Byte> byteToList(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        List<Byte> byteList = new ArrayList<Byte>();
        for (int i = 0; i < bytes.length; ++i) {
            byteList.add(bytes[i]);
        }
        return byteList;
    }

    private void addBytes(ArrayList<Byte> byteList, byte[] encodeBytes) {
        for (int i = 0; i < encodeBytes.length; i++) {
            byteList.add(encodeBytes[i]);
        }
    }

    /**
     * 协议类型,用于支持多协议时的区别
     *
     * @return
     */
    @Override
    public int getType() {
        return 0;
    }

    @Override
    public UUID getServiceUUID() {
        return UUID.fromString("0003CDD0-0000-1000-8000-00805F9B0131");
    }

    @Override
    public UUID getSendTunnelUUID() {
        return UUID.fromString("0003CDD2-0000-1000-8000-00805F9B0131");
    }

    @Override
    public UUID getRecvTunnelUUID() {
        return UUID.fromString("0003CDD1-0000-1000-8000-00805F9B0131");
    }

}


================================================
FILE: app/src/main/java/com/luo/bluetooth/protocol/OnTimeoutResult.java
================================================
/*
 * Copyright (c) 2019. stag All rights reserved.
 */

package com.luo.bluetooth.protocol;

/**
 * 蓝牙任务回调
 */
public interface OnTimeoutResult<T> {

    void onResult(boolean isTimeout, T result);
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/protocol/WeiCeCode.java
================================================
/**
 * Copyright (C), 2007-2022, 未来穿戴有限公司
 * FileName: WeiCeCode
 * Author: lpq
 * Date: 2022/3/11 16:27
 * Description: 用一句话描述下
 */
package com.luo.bluetooth.protocol;

/**
 *
 * @ProjectName: Bluetooth
 * @Package: com.luo.bluetooth.protocol
 * @ClassName: WeiCeCode
 * @Description: 用一句话描述下
 * @Author: lpq
 * @CreateDate: 2022/3/11 16:27
 */
public class WeiCeCode {
    /**
     * ExpandCode
     */
    public static final byte EXPAND_CODE_READ = 0x55;
    public static final byte EXPAND_CODE_WRITE = 0x66;
    public static final byte EXPAND_CODE_READ_RESPONSE = (byte) 0xAA;
    public static final byte EXPAND_CODE_WRITE_RESPONSE = (byte) 0x99;

    /**
     * 获取SN
     */
    public static final int GET_SN = 0x77;

}


================================================
FILE: app/src/main/java/com/luo/bluetooth/protocol/WeiCeDeviceOperate.java
================================================


/*
 * Copyright (c) 2019. stag All rights reserved.
 */

package com.luo.bluetooth.protocol;

import android.util.Log;

import com.stag.bluetooth.BluetoothTask;
import com.stag.bluetooth.util.ByteUtils;

import java.nio.ByteBuffer;

public class WeiCeDeviceOperate {
    private static final String TAG = "DncpDeviceOperate";
    public static int ERASE_TIMEOUT = 3000;
    public static int ERASE_TRY_COUNT = 2;

    public static void getSn(final OnTimeoutResult<String> obtainResult, boolean callbackInMainThread) {
        BluetoothTask task = new BluetoothTask(new CustomPacket(WeiCeCode.GET_SN, WeiCeCode.EXPAND_CODE_READ),
                callbackInMainThread,
                new BluetoothTask.OnDataResultListener() {
                    @Override
                    public void onResult(boolean isTimeout, byte[] data) {
                        Log.i("lpq", "onResult: data = " + ByteUtils.toString(data));
                        String sn = null;
                        if (!isTimeout && data != null) {
                            ByteBuffer byteBuffer = ByteBuffer.wrap(data);
                            sn = new String(byteBuffer.array()).replaceAll("[^\u4E00-\u9FA5a-zA-Z0-9-_]+", "");
                        }
                        Log.i("lpq", "onResult: sn = " + sn);
                        obtainResult.onResult(isTimeout, sn);
                    }
                });
        task.setTimeout(ERASE_TIMEOUT);
        task.send();
    }


//    public String getTypeBySync() {
//        byte[] data = new BluetoothTask(new DncpPacket(DeviceInfoCode.DSCP_CMD_DII_GET_TYPE, address)).sendBySync2();
//        String type = null;
//        if (data != null) {
//            ByteBuffer byteBuffer = ByteBuffer.wrap(data);
//            type = new String(byteBuffer.array()).replaceAll("[^\u4E00-\u9FA5a-zA-Z0-9-_]+", "");
//        }
//        return type;
//    }


//    public void setType(String type, final OnTimeoutResult<Boolean> obtainResult, boolean callbackInMainThread) {
//        new BluetoothTask(new DncpPacket(DeviceInfoCode.DSCP_CMD_DII_SET_TYPE,
//                ByteUtils.wrapData(type.getBytes(), 16),
//                address),
//                callbackInMainThread,
//                obtainResult == null ? null : new BluetoothTask.OnDataResultListener() {
//                    @Override
//                    public void onResult(boolean isTimeout, byte[] data) {
//                        Boolean res = Boolean.FALSE;
//                        if (!isTimeout && data != null) {
//                            res = ByteUtils.bytesToShort(data) == DSCPCode.DSCP_OK;
//                        }
//                        obtainResult.onResult(isTimeout, res);
//                    }
//                }).send();
//    }
//
//
//    public void getModelNumber(@NonNull final OnTimeoutResult<String> obtainResult, boolean callbackInMainThread) {
//        new BluetoothTask(new DncpPacket(DeviceInfoCode.DSCP_CMD_DII_GET_MODEL, address),
//                callbackInMainThread,
//                new BluetoothTask.OnDataResultListener() {
//                    @Override
//                    public void onResult(boolean isTimeout, byte[] data) {
//                        String modelNumber = null;
//                        if (!isTimeout && data != null) {
//                            ByteBuffer byteBuffer = ByteBuffer.wrap(data);
//                            modelNumber = new String(byteBuffer.array()).replaceAll("[^\u4E00-\u9FA5a-zA-Z0-9-_]+", "");
//                        }
//                        obtainResult.onResult(isTimeout, modelNumber);
//                    }
//                }).send();
//    }
//
//
//    public void setModelNumber(String model, final OnTimeoutResult<Boolean> obtainResult, boolean callbackInMainThread) {
//        new BluetoothTask(new DncpPacket(DeviceInfoCode.DSCP_CMD_DII_SET_MODEL,
//                ByteUtils.wrapData(model.getBytes(), 16),
//                address),
//                callbackInMainThread,
//                obtainResult == null ? null : new BluetoothTask.OnDataResultListener() {
//                    @Override
//                    public void onResult(boolean isTimeout, byte[] data) {
//                        Boolean res = Boolean.FALSE;
//                        if (!isTimeout && data != null) {
//                            res = ByteUtils.bytesToShort(data) == DSCPCode.DSCP_OK;
//                        }
//                        obtainResult.onResult(isTimeout, res);
//                    }
//                }).send();
//    }
//
//
//    public void getManufacturer(@NonNull final OnTimeoutResult<String> obtainResult, boolean callbackInMainThread) {
//        new BluetoothTask(new DncpPacket(DeviceInfoCode.DSCP_CMD_DII_GET_MANUFACTURER, address),
//                callbackInMainThread,
//                new BluetoothTask.OnDataResultListener() {
//                    @Override
//                    public void onResult(boolean isTimeout, byte[] data) {
//                        String manufacturer = null;
//                        if (!isTimeout && data != null) {
//                            ByteBuffer byteBuffer = ByteBuffer.wrap(data);
//                            manufacturer = new String(byteBuffer.array()).replace("\0", "");
//                            //manufacturer = new String(byteBuffer.array()).replaceAll("[^\u4E00-\u9FA5a-zA-Z0-9-_]+", "");
//                        }
//                        obtainResult.onResult(isTimeout, manufacturer);
//                    }
//                }).send();
//    }
//
//
//    public void setManufacturer(String manufacturer, final OnTimeoutResult<Boolean> obtainResult, boolean callbackInMainThread) {
//        new BluetoothTask(new DncpPacket(DeviceInfoCode.DSCP_CMD_DII_SET_MANUFACTURER,
//                ByteUtils.wrapData(manufacturer.getBytes(), 20),
//                address),
//                callbackInMainThread,
//                obtainResult == null ? null : new BluetoothTask.OnDataResultListener() {
//                    @Override
//                    public void onResult(boolean isTimeout, byte[] data) {
//                        Boolean res = Boolean.FALSE;
//                        if (!isTimeout && data != null) {
//                            res = ByteUtils.bytesToShort(data) == DSCPCode.DSCP_OK;
//                        }
//                        obtainResult.onResult(isTimeout, res);
//                    }
//                }).send();
//    }
//
//
//    public void getHardWareVersion(@NonNull final OnTimeoutResult<Version> obtainResult, boolean callbackInMainThread) {
//        new BluetoothTask(new DncpPacket(DeviceInfoCode.DSCP_CMD_DII_GET_HARDWARE_VERSION, address),
//                callbackInMainThread,
//                new BluetoothTask.OnDataResultListener() {
//                    @Override
//                    public void onResult(boolean isTimeout, byte[] data) {
////                        Log.e("软件/硬件版本号", "硬件版本号:" + (data == null ? "是个空" : StringUtils.byteArrayToHexString(data)));
//
//                        Version version = null;
//                        if (!isTimeout && data != null) {
//                            version = Version.getVersion(data);
//                        }
//                        obtainResult.onResult(isTimeout, version);
//                    }
//                }).send();
//    }
//
//
//    public void getSoftWareVersion(@NonNull final OnTimeoutResult<Version> obtainResult, boolean callbackInMainThread) {
//        new BluetoothTask(new DncpPacket(DeviceInfoCode.DSCP_CMD_DII_GET_SOFT_VERSION, address),
//                callbackInMainThread,
//                new BluetoothTask.OnDataResultListener() {
//                    @Override
//                    public void onResult(boolean isTimeout, byte[] data) {
//                        Version version = null;
//                        if (!isTimeout && data != null) {
//                            version = Version.getVersion(data);
//                        }
//                        obtainResult.onResult(isTimeout, version);
//                    }
//                }).send();
//    }
//
//
//    public Version getSoftWareVersionBySync() {
//        BluetoothTask task = new BluetoothTask(new DncpPacket(DeviceInfoCode.DSCP_CMD_DII_GET_SOFT_VERSION, address));
//        task.setTimeout(1500);
//        task.setTryCount(2);
//        byte[] data = task.sendBySync2();
//        Version version = null;
//        if (data != null) {
//            version = Version.getVersion(data);
//        }
//        return version;
//    }
//
//
//    public void getSerialNumber(@NonNull final OnTimeoutResult<String> obtainResult, boolean callbackInMainThread) {
//        new BluetoothTask(new DncpPacket(DeviceInfoCode.DSCP_CMD_DII_GET_SN, address),
//                callbackInMainThread,
//                new BluetoothTask.OnDataResultListener() {
//                    @Override
//                    public void onResult(boolean isTimeout, byte[] data) {
//                        String serialNumber = null;
//                        if (!isTimeout && data != null) {
//                            ByteBuffer byteBuffer = ByteBuffer.wrap(data);
//                            serialNumber = new String(byteBuffer.array()).replaceAll("[^\u4E00-\u9FA5a-zA-Z0-9-_]+", "");
//                        }
//                        obtainResult.onResult(isTimeout, serialNumber);
//                    }
//                }).send();
//    }
//
//
//    public void getRunMode(@NonNull final OnTimeoutResult<DeviceRunMode> obtainResult, boolean callbackInMainThread) {
//        new BluetoothTask(new DncpPacket(DeviceUpdateCode.DSCP_CMD_DUI_GET_RUN_MODE, address),
//                callbackInMainThread,
//                new BluetoothTask.OnDataResultListener() {
//                    @Override
//                    public void onResult(boolean isTimeout, byte[] data) {
//                        DeviceRunMode mode = null;
//                        if (!isTimeout && data != null) {
//                            mode = DeviceRunMode.getDeviceRunMode(data[0]);
//                        }
//                        obtainResult.onResult(isTimeout, mode);
//                    }
//                }).send();
//    }
//
//
//    public DeviceRunMode getRunModeBySync() {
//        byte[] data = new BluetoothTask(new DncpPacket(DeviceUpdateCode.DSCP_CMD_DUI_GET_RUN_MODE, address))
//                .setTimeout(500)
//                .sendBySync2();
//        DeviceRunMode mode = null;
//        if (data != null) {
//            mode = DeviceRunMode.getDeviceRunMode(data[0]);
//        }
//        return mode;
//    }
//
//
//    public void getVersion(@NonNull final OnTimeoutResult<Version> obtainResult, boolean callbackInMainThread) {
//        new BluetoothTask(new DncpPacket(DeviceUpdateCode.DSCP_CMD_DUI_GET_VERSION, address),
//                callbackInMainThread,
//                new BluetoothTask.OnDataResultListener() {
//                    @Override
//                    public void onResult(boolean isTimeout, byte[] data) {
//                        Version version = null;
//                        if (!isTimeout && data != null) {
//                            version = Version.getVersion(data);
//                        }
//                        obtainResult.onResult(isTimeout, version);
//                    }
//                }).send();
//    }
//
//
//    public void getMaxFragmentSize(@NonNull final OnTimeoutResult<Short> obtainResult, boolean callbackInMainThread) {
//        new BluetoothTask(new DncpPacket(DeviceUpdateCode.DSCP_CMD_DUI_GET_MAX_FRAGMENT_SIZE, address),
//                callbackInMainThread,
//                new BluetoothTask.OnDataResultListener() {
//                    @Override
//                    public void onResult(boolean isTimeout, byte[] data) {
//                        Short res = null;
//                        if (!isTimeout && data != null) {
//                            res = Short.valueOf(ByteUtils.bytesToShort(data));
//                        }
//                        obtainResult.onResult(isTimeout, res);
//                    }
//                }).send();
//    }
//
//
//    public short getMaxFragmentSizeBySync() {
//        byte[] data = new BluetoothTask(new DncpPacket(DeviceUpdateCode.DSCP_CMD_DUI_GET_MAX_FRAGMENT_SIZE, address)).sendBySync2();
//        short res = 0;
//        if (data != null) {
//            res = ByteUtils.bytesToShort(data);
//        }
//        return res;
//    }
//
//
//    public void enterUpdater() {
//        new BluetoothTask(new DncpPacket(DeviceUpdateCode.DSCP_CMD_DUI_ENTER_UPDATER, address)).send();
//    }
//
//
//    public void enterApp() {
//        new BluetoothTask(new DncpPacket(DeviceUpdateCode.DSCP_CMD_DUI_ENTER_APPLICATION, address)).send();
//    }
//
//
//    public void erase(int address, int size, final OnTimeoutResult<Boolean> obtainResult, boolean callbackInMainThread) {
//        byte[] data = ByteUtils.wrapData(ByteUtils.combineByteArray(ByteUtils.intToBytes(address), ByteUtils.intToBytes(size)), 8);
//        new BluetoothTask(new DncpPacket(DeviceUpdateCode.DSCP_CMD_DUI_ERASE, data, this.address),
//                callbackInMainThread,
//                obtainResult == null ? null : new BluetoothTask.OnDataResultListener() {
//                    @Override
//                    public void onResult(boolean isTimeout, byte[] data) {
//                        Boolean res = Boolean.FALSE;
//                        if (!isTimeout && data != null) {
//                            res = ByteUtils.bytesToShort(data) == DSCPCode.DSCP_OK;
//                        }
//                        obtainResult.onResult(isTimeout, res);
//                    }
//                }).setTimeout(ERASE_TIMEOUT).setTryCount(ERASE_TRY_COUNT).send();
//    }
//
//
//    public void writeProgram(int address, int seq, int length, byte[] data,
//                             final OnTimeoutResult<WriteProgramResult> obtainResult, boolean callbackInMainThread) {
//        byte[] temp = ByteUtils.wrapData(ByteUtils.combineByteArray(ByteUtils.intToBytes(address),
//                ByteUtils.shortToBytes((short) (length & 0xffff)), ByteUtils.shortToBytes((short) (seq & 0xffff)), data), length + 8);
//        BluetoothTask task = new BluetoothTask(new DncpPacket(DeviceUpdateCode.DSCP_CMD_DUI_WRITE_PROGRAM, temp, this.address),
//                callbackInMainThread,
//                obtainResult == null ? null : new BluetoothTask.OnDataResultListener() {
//                    @Override
//                    public void onResult(boolean isTimeout, byte[] data) {
//                        WriteProgramResult res = null;
//                        if (!isTimeout && data != null) {
//                            res = WriteProgramResult.getWriteProgramResult(data);
//                        }
//                        obtainResult.onResult(isTimeout, res);
//                    }
//                });
//        task.setTimeout(2000);
//        task.setTryCount(1);
//        task.send();
//    }
//
//    public WriteProgramResult writeProgramBySync(int address, int seq, int length, byte[] data) {
//        byte[] temp = ByteUtils.wrapData(ByteUtils.combineByteArray(ByteUtils.intToBytes(address),
//                ByteUtils.shortToBytes((short) (length & 0xffff)), ByteUtils.shortToBytes((short) (seq & 0xffff)), data), length + 8);
//        BluetoothTask task = new BluetoothTask(new DncpPacket(DeviceUpdateCode.DSCP_CMD_DUI_WRITE_PROGRAM, temp, this.address));
//        task.setTimeout(2000);
//        task.setTryCount(1);
//        byte[] d = task.sendBySync2();
//        WriteProgramResult res = null;
//        if (d != null) {
//            res = WriteProgramResult.getWriteProgramResult(d);
//        }
//        return res;
//    }
//
//
//    public void checkIntegrity(int checksum, @NonNull final OnTimeoutResult<Boolean> obtainResult, boolean callbackInMainThread) {
//        new BluetoothTask(new DncpPacket(DeviceUpdateCode.DSCP_CMD_DUI_CHECK_INTEGRITY, ByteUtils.intToBytes2SmallDian(checksum), address),
//                callbackInMainThread,
//                new BluetoothTask.OnDataResultListener() {
//                    @Override
//                    public void onResult(boolean isTimeout, byte[] data) {
//                        Boolean res = Boolean.FALSE;
//                        if (!isTimeout && data != null) {
//                            res = ByteUtils.bytes2ToInt2(data) == DSCPCode.DSCP_OK;
//                        }
//                        obtainResult.onResult(isTimeout, res);
//                    }
//                }).send();
//    }

}


================================================
FILE: app/src/main/java/com/luo/bluetooth/utils/ByteUtils.java
================================================
package com.luo.bluetooth.utils;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.UUID;

import lombok.NonNull;

/**
 * Created by Administrator on 2016/7/25 0025.
 */
public class ByteUtils {
    final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();

    public static String bytesToHex(byte[] bytes) {
        StringBuilder r = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            r.append(hexArray[(b >> 4) & 0xF]);
            r.append(hexArray[(b & 0xF)]);
        }
        return r.toString();

    }

    /**
     * 缺失部分有效数字
     * UUID型转成4字节byte 大端模式,UUID如果不足处于后补零,有效数字在前
     *
     * @param u
     * @return
     */
    public static byte[] uuidToByte5BigEndian2(UUID u) {
        long l = u.getMostSignificantBits();
        byte[] b = new byte[5];
        b[4] = (byte) ((l >> 24) & 0xf000000fL);
        b[3] = (byte) ((l >> 32) & 0xff00000000L);
        b[2] = (byte) ((l >> 40) & 0xff0000000000L);
        b[1] = (byte) ((l >> 48) & 0xff000000000000L);
        b[0] = (byte) ((l >> 56) & 0xff00000000000000L);
        return b;
    }

    /**
     * 4字节byte转化成UUID 大端模式,UUID如果不足处于后补零,有效数字在前
     *
     * @param b
     * @return
     */
    public static UUID byte5ToUuidBigEndian2(byte[] b) {
        long l = ((long) b[4] << 24) & 0xff000000L;
        l |= ((long) b[3] << 32) & 0xff00000000L;
        l |= ((long) b[2] << 40) & 0xff0000000000L;
        l |= ((long) b[1] << 48) & 0xff000000000000L;
        l |= ((long) b[0] << 56) & 0xff00000000000000L;
        return new UUID(l, 0);
    }

    /**
     * 缺失部分有效数字
     * UUID型转成4字节byte 大端模式
     *
     * @param u
     * @return
     */
    public static byte[] uuidToByte5BigEndian(UUID u) {
        long l = u.getLeastSignificantBits();
        byte[] b = new byte[5];
        b[4] = (byte) (l & 0xffL);
        b[3] = (byte) ((l >> 8) & 0xff00L);
        b[2] = (byte) ((l >> 16) & 0xff0000L);
        b[1] = (byte) ((l >> 24) & 0xff000000L);
        b[0] = (byte) ((l >> 32) & 0xff00000000L);
        return b;
    }

    /**
     * 4字节byte转化成UUID 大端模式
     *
     * @param b
     * @return
     */
    public static UUID byte5ToUuidBigEndian(byte[] b) {
        long l = b[4] & 0xffL;
        l |= (b[3] << 8) & 0xff00L;
        l |= (b[2] << 16) & 0xff0000L;
        l |= (b[1] << 24) & 0xff000000L;
        l |= (b[0] << 32) & 0xff00000000L;
        return new UUID(0, l);
    }

    /**
     * 大端模式将3个字节的Byte转成int型
     *
     * @param b
     * @return
     */
    public static long byte3ToLongBigEndian(byte[] b) {
        long i = (long) b[2] & 0xffL;
        i |= (((long) b[1] << 8) & 0xff00L);
        i |= (((long) b[1] << 16) & 0xff0000L);
        return i;
    }

    /**
     * 大端模式将int型转成3个字节的Byte
     *
     * @param i
     * @return
     */
    public static byte[] longToByte3BigEndian(long i) {
        byte[] res = new byte[3];
        res[2] = (byte) (i & 0xffL);
        res[1] = (byte) ((i >> 8) & 0xffL);
        res[0] = (byte) ((i >> 16) & 0xffL);
        return res;
    }

    /**
     * 比较两个byte数组
     *
     * @param first
     * @param second
     * @return
     */
    public static boolean compareBytes(byte[] first, byte[] second) {
        for (int i = 0; i < (first.length < second.length ? first.length : second.length); i++) {
            if (first[i] != second[i]) {
                return false;
            }
        }
        return true && first.length == second.length;
    }

    /**
     * 缺失部分有效数字
     * UUID型转成4字节byte 大端模式
     *
     * @param u
     * @return
     */
    public static byte[] uuidToByte4BigEndian(UUID u) {
        long l = u.getLeastSignificantBits();
        byte[] b = new byte[4];
        b[3] = (byte) (l & 0xffL);
        b[2] = (byte) ((l >> 8) & 0xff00L);
        b[1] = (byte) ((l >> 16) & 0xff0000L);
        b[0] = (byte) ((l >> 24) & 0xff000000L);
        return b;
    }

    /**
     * 4字节byte转化成UUID 大端模式
     *
     * @param b
     * @return
     */
    public static UUID byte4ToUuidBigEndian(byte[] b) {
        long l = (long) b[3] & 0xffL;
        l |= ((long) b[2] << 8) & 0xff00L;
        l |= ((long) b[1] << 16) & 0xff0000L;
        l |= ((long) b[0] << 24) & 0xff000000L;
        return new UUID(0, l);
    }


    /**
     * 4字节byte转化成UUID 大端模式
     *
     * @param b
     * @return
     */
    public static UUID byte4ToUuidBigEndian2(byte[] b) {
        long l = ((long) b[3] << 32) & 0xff00000000L;
        l |= ((long) b[2] << 40) & 0xff0000000000L;
        l |= ((long) b[1] << 48) & 0xff000000000000L;
        l |= ((long) b[0] << 56) & 0xff00000000000000L;
        return new UUID(l, 0);
    }

    /**
     * 缺失部分有效数字
     * long型转成4字节byte 大端模式
     *
     * @param l
     * @return
     */
    public static byte[] longToByte4BigEndian(long l) {
        byte[] b = new byte[4];
        b[3] = (byte) (l & 0xffL);
        b[2] = (byte) ((l >> 8) & 0xff00L);
        b[1] = (byte) ((l >> 16) & 0xff0000L);
        b[0] = (byte) ((l >> 24) & 0xff000000L);
        return b;
    }

    /**
     * 4字节byte转化成Long 大端模式
     *
     * @param b
     * @return
     */
    public static long byte4ToLongBigEndian(byte[] b) {
        long l = (long) b[3] & 0xffL;
        l |= ((long) b[2] << 8) & 0xff00L;
        l |= ((long) b[1] << 16) & 0xff0000L;
        l |= ((long) b[0] << 24) & 0xff000000L;
        return l;
    }

    /**
     * 16个字节转化UUID 大端模式
     *
     * @param b
     * @return
     */
    public static UUID byte16ToUuidBigEndian(byte[] b) {
        return new UUID(byte8ToLongBigEndian(subBytes(b, 0, 8)), byte8ToLongBigEndian(subBytes(b, 8, 8)));
    }

    /**
     * UUID转化成16个字节 大端模式
     *
     * @param uuid
     * @return
     */
    public static byte[] uuidToByte16BigEndian(UUID uuid) {
        long l = uuid.getLeastSignificantBits();
        long l2 = uuid.getMostSignificantBits();
        return combineByteArray(longToByte8BigEndian(l2), longToByte8BigEndian(l));
    }

    /**
     * 8个字节转化UUID 大端模式
     *
     * @param b
     * @return
     */
    public static UUID byte8ToUuidBigEndian(byte[] b) {
        return new UUID(0, byte8ToLongBigEndian(b));
    }

    /**
     * UUID转化成8个字节 大端模式
     *
     * @param uuid
     * @return
     */
    public static byte[] uuidToByte8BigEndian(UUID uuid) {
        long l = uuid.getLeastSignificantBits();
        return longToByte8BigEndian(l);
    }

    /**
     * 8个字节转化成long型 大端模式
     *
     * @param b
     * @return
     */
    public static long byte8ToLongBigEndian(byte[] b) {
        long l = (long) b[7] & 0xffL;
        l |= ((long) b[6] << 8) & 0xff00L;
        l |= ((long) b[5] << 16) & 0xff0000L;
        l |= ((long) b[4] << 24) & 0xff000000L;
        l |= ((long) b[3] << 32) & 0xff00000000L;
        l |= ((long) b[2] << 40) & 0xff0000000000L;
        l |= ((long) b[1] << 48) & 0xff000000000000L;
        l |= ((long) b[0] << 56) & 0xff00000000000000L;
        return l;
    }

    /**
     * long型转成8个字节 大端模式
     *
     * @param l
     * @return
     */
    public static byte[] longToByte8BigEndian(long l) {
        byte[] b = new byte[8];
        b[7] = (byte) (l & 0xffL);
        b[6] = (byte) ((l >> 8) & 0xffL);
        b[5] = (byte) ((l >> 16) & 0xffL);
        b[4] = (byte) ((l >> 24) & 0xffL);
        b[3] = (byte) ((l >> 32) & 0xffL);
        b[2] = (byte) ((l >> 40) & 0xffL);
        b[1] = (byte) ((l >> 48) & 0xffL);
        b[0] = (byte) ((l >> 56) & 0xffL);
        return b;
    }

    /**
     * 六个字节的byte转化成UUID,有效数字在前,于后补零
     *
     * @param b
     * @return
     */
    public static UUID byte6ToUuidBigEndian2(byte[] b) {
        long l = ((long) b[5] << 16) & 0xff0000L;
        l |= ((long) b[4] << 24) & 0xff000000L;
        l |= ((long) b[3] << 32) & 0xff00000000L;
        l |= ((long) b[2] << 40) & 0xff0000000000L;
        l |= ((long) b[1] << 48) & 0xff000000000000L;
        l |= ((long) b[0] << 56) & 0xff00000000000000L;
        return new UUID(l, 0);
    }

    /**
     * 将UUID转成六个字节的Byte,有效数字在前,于后补零
     *
     * @param uuid
     * @return
     */
    public static byte[] uuidToByte6BigEndian2(UUID uuid) {
        long l = uuid.getMostSignificantBits();
        byte[] b = new byte[6];
        b[5] = (byte) ((l >> 16) & 0xffL);
        b[4] = (byte) ((l >> 24) & 0xffL);
        b[3] = (byte) ((l >> 32) & 0xffL);
        b[2] = (byte) ((l >> 40) & 0xffL);
        b[1] = (byte) ((l >> 48) & 0xffL);
        b[0] = (byte) ((l >> 56) & 0xffL);
        return b;
    }

    /**
     * 六个字节的byte转化成UUID
     *
     * @param b
     * @return
     */
    public static UUID byte6ToUuidBigEndian(byte[] b) {
        long l = (long) b[5] & 0xffL;
        l |= ((long) b[4] << 8) & 0xff00L;
        l |= ((long) b[3] << 16) & 0xff0000L;
        l |= ((long) b[2] << 24) & 0xff000000L;
        l |= ((long) b[1] << 32) & 0xff00000000L;
        l |= ((long) b[0] << 40) & 0xff0000000000L;
        return new UUID(0, l);
    }

    /**
     * 将UUID转成六个字节的Byte
     *
     * @param uuid
     * @return
     */
    public static byte[] uuidToByte6BigEndian(UUID uuid) {
        long l = uuid.getLeastSignificantBits();
        byte[] b = new byte[6];
        b[5] = (byte) (l & 0xffL);
        b[4] = (byte) ((l >> 8) & 0xffL);
        b[3] = (byte) ((l >> 16) & 0xffL);
        b[2] = (byte) ((l >> 24) & 0xffL);
        b[1] = (byte) ((l >> 32) & 0xffL);
        b[0] = (byte) ((l >> 40) & 0xffL);
        return b;
    }

    /**
     * 大端模式将4个字节的Byte转成int型
     *
     * @param b
     * @return
     */
    public static int byte4ToIntBigEndian(byte[] b) {
        int i = b[3] & 0xff;
        i |= ((b[2] << 8) & 0xff00);
        i |= ((b[1] << 16) & 0xff0000);
        i |= ((b[0] << 24) & 0xff000000);
        return i;
    }

    /**
     * 大端模式将int型转成4个字节的Byte
     *
     * @param i
     * @return
     */
    public static byte[] intToByte4BigEndian(int i) {
        byte[] res = new byte[4];
        res[3] = (byte) (i & 0xff);
        res[2] = (byte) ((i >> 8) & 0xff);
        res[1] = (byte) ((i >> 16) & 0xff);
        res[0] = (byte) ((i >> 24) & 0xff);
        return res;
    }

    /**
     * 大端模式将3个字节的Byte转成int型
     *
     * @param b
     * @return
     */
    public static int byte3ToIntBigEndian(byte[] b) {
        int i = b[2] & 0xff;
        i |= ((b[1] << 8) & 0xff00);
        i |= ((b[1] << 16) & 0xff0000);
        return i;
    }

    /**
     * 大端模式将int型转成3个字节的Byte
     *
     * @param i
     * @return
     */
    public static byte[] intToByte3BigEndian(int i) {
        byte[] res = new byte[3];
        res[2] = (byte) (i & 0xff);
        res[1] = (byte) ((i >> 8) & 0xff);
        res[0] = (byte) ((i >> 16) & 0xff);
        return res;
    }

    public static String toString(byte[] data) {
        return toString(data, " ");
    }

    public static String toString(byte[] data, String interval) {
        if (data == null) {
            return null;
        }
        String iStr = interval == null ? "" : interval;
        StringBuilder buffer = new StringBuilder();
        for (byte b : data) {
            String d = Integer.toHexString(b & 0xff);
            if (d.length() > 1) {
                buffer.append(d).append(iStr);
            } else {
                buffer.append("0").append(d).append(iStr);
            }
        }
        return buffer.toString();
    }

    public static byte[] subBytes(byte[] data, int start, int len) {
        byte[] res = new byte[len];
        for (int i = 0; i < len; i++) {
            res[i] = data[start + i];
        }
        return res;
    }

    public static byte[] subBytes(byte[] data, int start) {
        int len = data.length - start;
        return subBytes(data, start, len);
    }

    /**
     * 将字节数组转化成Long
     *
     * @param b
     * @return
     */
    public static long bytesToLong(byte[] b) {
        long l = ((long) b[0] << 56) & 0xFF00000000000000L;
        // 如果不强制转换为long,那么默认会当作int,导致最高32位丢失
        l |= ((long) b[1] << 48) & 0xFF000000000000L;
        l |= ((long) b[2] << 40) & 0xFF0000000000L;
        l |= ((long) b[3] << 32) & 0xFF00000000L;
        l |= ((long) b[4] << 24) & 0xFF000000L;
        l |= ((long) b[5] << 16) & 0xFF0000L;
        l |= ((long) b[6] << 8) & 0xFF00L;
        l |= b[7] & 0xFFL;
        return l;
    }

    /**
     * 将Long转化成字节数组
     *
     * @param l
     * @return
     */
    public static byte[] longToBytes(long l) {
        byte[] b = new byte[8];
        b[0] = (byte) (l >>> 56);
        b[1] = (byte) (l >>> 48);
        b[2] = (byte) (l >>> 40);
        b[3] = (byte) (l >>> 32);
        b[4] = (byte) (l >>> 24);
        b[5] = (byte) (l >>> 16);
        b[6] = (byte) (l >>> 8);
        b[7] = (byte) (l);
        return b;
    }

    /**
     * 合并Byte数组
     *
     * @param bytes
     * @return
     */
    public static byte[] combineByteArray(byte[]... bytes) {
        int len = 0;
        for (byte[] bs : bytes) {
            if (bs != null) {
                len += bs.length;
            }
        }
        byte[] res = new byte[len];
        int pos = 0;
        for (byte[] bs : bytes) {
            if (bs != null) {
                for (byte b : bs) {
                    res[pos++] = b;
                }
            }
        }
        return res;
    }

    /**
     * 将UUID转化成Byte数组
     *
     * @param uuid
     * @return
     */
    public static byte[] uuidToBytes(UUID uuid) {
        return combineByteArray(longToBytes(uuid.getMostSignificantBits()), longToBytes(uuid.getLeastSignificantBits()));
    }

    /**
     * 将Byte数组转化成UUID
     *
     * @param data
     * @return
     */
    public static UUID bytesToUuid(byte[] data) {
        if (data == null || data.length < 16)
            return null;
        byte[] bMost = subBytes(data, 0, 8);
        byte[] bLeast = subBytes(data, 8, 8);
        return new UUID(bytesToLong(bMost), bytesToLong(bLeast));
    }

    /**
     * 将Int转化为Byte数组
     *
     * @param i
     * @return
     */
    public static byte[] intToBytes2(int i) {
        byte[] res = new byte[2];
        res[1] = (byte) (i & 0xFF);
        res[0] = (byte) (i >> 8 & 0xFF);
        return res;
    }

    public static byte[] intToBytes2SmallDian(int i) {
        byte[] res = new byte[2];
        res[0] = (byte) (i & 0xFF);
        res[1] = (byte) (i >> 8 & 0xFF);
        return res;
    }

    /**
     * 将Byte数组转化为int,取第一二个字节
     *
     * @param b
     * @return
     */
    public static int bytes2ToInt(byte[] b) {
        int c = (int) ((b[0] << 8) & 0xFF00L);
        c |= (int) (b[1] & 0xFFL);
        return c;
    }

    /**
     * 将Byte数组转化为int,取第一二个字节,小端模式
     *
     * @param b
     * @return
     */
    public static int bytesS2ToInt(byte[] b) {
        int c = (int) ((b[1] << 8) & 0xFF00L);
        c |= (int) (b[0] & 0xFFL);
        return c;
    }

    /**
     * 将Byte数组转化为int,取第一三个字节
     *
     * @param b
     * @return
     */
    public static int bytes2ToInt2(byte[] b) {
        int c = (int) ((b[1] << 16) & 0xFFFFFF00L);
        c |= (int) (b[0]);
        return c;
    }

    /**
     * 将Byte数组转化为int
     *
     * @param b
     * @return
     */
    public static int bytesToIntBigEndian(byte[] b) {
        int res = (int) ((b[0] << 24) & 0xFF000000L);
        res |= (b[1] << 16 & 0xFF0000L);
        res |= (b[2] << 8 & 0xFF00L);
        res |= (b[3] & 0xFFL);
        return res;
    }

    /**
     * 将Byte数组转化为int
     *
     * @param b
     * @return
     */
    public static int bytesToIntSmallEndian(byte[] b) {
        int res = (int) ((b[3] << 24) & 0xFF000000L);
        res |= (b[2] << 16 & 0xFF0000L);
        res |= (b[1] << 8 & 0xFF00L);
        res |= (b[0] & 0xFFL);
        return res;
    }

    /**
     * 将Int转化成Byte数组
     *
     * @param i
     * @return
     */
    public static byte[] intToBytesBigEndian(int i) {
        byte[] res = new byte[4];
        res[0] = (byte) ((i >> 24) & 0xFFL);
        res[1] = (byte) ((i >> 16) & 0xFFL);
        res[2] = (byte) ((i >> 8) & 0xFFL);
        res[3] = (byte) (i & 0xFFL);
        return res;
    }

    /**
     * 将Byte数组转化为int
     *
     * @param b
     * @return
     */
    public static int bytesToInt(byte[] b) {
        int res = (int) ((b[3] << 24) & 0xFF000000L);
        res |= (b[2] << 16 & 0xFF0000L);
        res |= (b[1] << 8 & 0xFF00L);
        res |= (b[0] & 0xFFL);
        return res;
    }

    /**
     * 将Int转化成Byte数组
     *
     * @param i
     * @return
     */
    public static byte[] intToBytes(int i) {
        byte[] res = new byte[4];
        res[3] = (byte) ((i >> 24) & 0xFFL);
        res[2] = (byte) ((i >> 16) & 0xFFL);
        res[1] = (byte) ((i >> 8) & 0xFFL);
        res[0] = (byte) (i & 0xFFL);
        return res;
    }

    /**
     * 将Byte数组转化成short
     *
     * @param b
     * @return
     */
    public static short bytesToShort(byte[] b) {
        short res = (short) ((b[1] << 8) & 0xFF00l);
        res |= (b[0] & 0xFFl);
        return res;
    }

    /**
     * 将Short转化为Byte数组
     *
     * @param i
     * @return
     */
    public static byte[] shortToBytes(short i) {
        byte[] res = new byte[2];
        res[1] = (byte) ((i >> 8) & 0xFFL);
        res[0] = (byte) (i & 0xFFL);
        return res;
    }

    /**
     * 大端序
     * 将Byte数组转化成short
     *
     * @param b
     * @return
     */
    public static short bytesToShortBigEndian(byte[] b) {
        short res = (short) ((b[0] << 8) & 0xFF00L);
        res |= (b[1] & 0xFFL);
        return res;
    }

    /**
     * 大端序
     * 将Short转化为Byte数组
     *
     * @param i
     * @return
     */
    public static byte[] shortToBytesBigEndian(short i) {
        byte[] res = new byte[2];
        res[0] = (byte) ((i >> 8) & 0xFFL);
        res[1] = (byte) (i & 0xFFL);
        return res;
    }

    /**
     * 填充数据至长度为N的数组
     *
     * @param data
     * @param len
     * @return
     */
    public static byte[] wrapData(byte[] data, int len) {
        byte[] res = new byte[len];
        for (int i = 0; i < len; i++) {
            if (i < data.length) {
                res[i] = data[i];
            } else {
                res[i] = 0;
            }
        }
        return res;
    }

    /**
     * 取出一字节中每一位的数值
     *
     * @param data
     * @return
     */
    public static byte[] getByteBits(byte data) {
        byte[] result = new byte[8];
        for (int i = 0; i < 8; i++) {
            result[i] = (byte) (data >> i & 0x01);
        }
        return result;
    }

    public static byte[] getBytesWithBuffer(ByteBuffer buffer) {
        if (buffer == null)
            return null;
        byte[] bytes = new byte[buffer.position()];
        for (int i = 0; i < buffer.position(); i++)
            bytes[i] = buffer.array()[i];
        return bytes;
    }

    public static boolean equal(byte[] data1, byte[] data2) {
        return compare(data1, data2) == 0;
    }

    public static int compare(byte[] bytes1, byte[] bytes2) {
        if (bytes1.length > bytes2.length) {
            return 1;
        }
        if (bytes1.length < bytes2.length) {
            return -1;
        }

        for (int i = 0; i < bytes1.length; i++) {
            int result = (bytes1[i] & 0xFF) - (bytes2[i] & 0xFF);
            if (result > 0) {
                return 1;
            }
            if (result < 0) {
                return -1;
            }
        }
        return 0;

    }

    public static byte getXor(byte[] data) {
        return getXor(data, 0, data.length);
    }

    public static byte getXor(byte[] data, int start, int len) {
        byte xor = 0;
        for (int i = start; i < len + start; i++)
            xor ^= data[i];
        return xor;
    }

    /**
     * bytes 转Ascii码字符串
     */
    public static String bytesToAscii(byte[] bytes, int offset, int dateLen) {
        if ((bytes == null) || (bytes.length == 0) || (offset < 0) || (dateLen <= 0)) {
            return null;
        }
        if ((offset >= bytes.length) || (bytes.length - offset < dateLen)) {
            return null;
        }

        String asciiStr = null;
        byte[] data = new byte[dateLen];
        System.arraycopy(bytes, offset, data, 0, dateLen);
        asciiStr = new String(data, StandardCharsets.US_ASCII);
        return asciiStr;
    }

    public static String bytesToAscii(byte[] bytes, int dateLen) {
        return bytesToAscii(bytes, 0, dateLen);
    }

    public static String bytesToAscii(byte[] bytes) {
        return bytesToAscii(bytes, 0, bytes.length);
    }

    public static byte[] asciiToBytes(String string) {
        if (string == null) {
            return null;
        }
        return string.getBytes(StandardCharsets.US_ASCII);
    }

    /**
     * 16 进制字符串转bytes数据
     */
    public static byte[] hexStringToBytes(@NonNull String hexString) {
        byte[] result = new byte[hexString.length() / 2];
        for (int i = 0; i < hexString.length() / 2; ++i) {
            String temp = hexString.substring(2 * i, 2 * (i + 1));
            result[i] = (byte) Integer.parseInt(temp, 16);
        }
        return result;
    }

    public static String addSpaceToString(String origin, int strLength) {
        if (origin == null) {
            origin = "";
        }
        String result = origin;
        if (origin.length() < strLength) {
            StringBuilder sb = new StringBuilder();
            sb.append(origin);// 左补0
            while (sb.length() < strLength) {
                sb.append(" ");
            }
            result = sb.toString();
        }
        return result;
    }
}


================================================
FILE: app/src/main/java/com/luo/bluetooth/utils/DateUtils.java
================================================
package com.luo.bluetooth.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * 日期工具类
 *
 * @author jingle1267@163.com
 */
public final class DateUtils {

    /**
     * 日期类型 *
     */
    public static final String yyyyMMDD = "yyyy-MM-dd";
    public static final String yyyyMMddHHmmss = "yyyy-MM-dd HH:mm:ss";
    public static final String HH_mm_ss = "HH:mm:ss";
    public static final String HHmmss = "HHmmss";
    public static final String yyMMddHHmm = "yyMMddHHmm";
    public static final String ddHHmmss = "ddHHmmss";
    public static final String hhmmss = "HH:mm:ss";
    public static final String HH_mm_ss_SSS = "HH:mm:ss.SSS";
    public static final String LOCALE_DATE_FORMAT = "yyyy年M月d日 HH:mm:ss";
    public static final String DB_DATA_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String NEWS_ITEM_DATE_FORMAT = "hh:mm M月d日 yyyy";
    public static final String COMMON_TYPE = "yyyyMMddHHmmss";
    public static final String MMddHHmmss = "MM月dd日HH时mm分ss秒";
    public static final long SECOND = 1000;//1000毫秒
    public static final long MINUTE = 60 * SECOND;
    public static final long HOUR = 60 * MINUTE;
    public static final long DAY = 24 * HOUR;

    public static String getCurrentDateString() {
    	return formatDate(new Date(), yyyyMMddHHmmss);
    }

    /**
     * 在原基础上加N个小时
     *
     * @param date
     * @param hour
     * @return
     */
    public static Date dateAddHours(Date date, int hour) {
        long timestamp = date.getTime() + hour * 60 * 60 * 1000;
        return new Date(timestamp);
    }

    public static String dateToString(long time, String pattern)
            throws Exception {
        return dateToString(new Date(time), pattern);
    }

    public static String dateToString(Date date, String pattern)
            throws Exception {
        return new SimpleDateFormat(pattern).format(date);
    }

    public static Date stringToDate(String dateStr, String pattern)
            throws Exception {
        return new SimpleDateFormat(pattern).parse(dateStr);
    }

    public static String formatDate(long time, String type) {
        return formatDate(new Date(time), type);
    }

    public static String formatDate(Date date) {
    	return formatDate(date, yyyyMMddHHmmss);
    }
    /**
     * 将Date类型转换为日期字符串
     *
     * @param date Date对象
     * @param type 需要的日期格式
     * @return 按照需求格式的日期字符串
     */
    public static String formatDate(Date date, String type) {
        try {
            SimpleDateFormat df = new SimpleDateFormat(type);
            return df.format(date);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将日期字符串转换为Date类型
     *
     * @param dateStr 日期字符串
     * @param type    日期字符串格式
     * @return Date对象
     */
    public static Date parseDate(String dateStr, String type) {
        SimpleDateFormat df = new SimpleDateFormat(type);
        Date date = null;
        try {
            date = df.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;

    }

    /**
     * 得到年
     *
     * @param date Date对象
     * @return 年
     */
    public static int getYear(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.YEAR);
    }


    /**
     * 得到月
     *
     * @param date Date对象
     * @return 月
     */
    public static int getMonth(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.MONTH) + 1;

    }

    /**
     * 得到日
     *
     * @param date Date对象
     * @return 日
     */
    public static int getDay(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.DAY_OF_MONTH);
    }



    public static int getHour(Date date){
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.HOUR_OF_DAY);
    }

    public static int getMinute(Date date){
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.MINUTE);
    }

    public static int getSecond(Date date){
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.SECOND);
    }


    /**
     * 转换日期 将日期转为今天, 昨天, 前天, XXXX-XX-XX, ...
     *
     * @param time 时间
     * @return 当前日期转换为更容易理解的方式
     */
    public static String translateDate(Long time) {
        long oneDay = 24 * 60 * 60 * 1000;
        Calendar current = Calendar.getInstance();
        Calendar today = Calendar.getInstance();    //今天

        today.set(Calendar.YEAR, current.get(Calendar.YEAR));
        today.set(Calendar.MONTH, current.get(Calendar.MONTH));
        today.set(Calendar.DAY_OF_MONTH, current.get(Calendar.DAY_OF_MONTH));
        //  Calendar.HOUR——12小时制的小时数 Calendar.HOUR_OF_DAY——24小时制的小时数
        today.set(Calendar.HOUR_OF_DAY, 0);
        today.set(Calendar.MINUTE, 0);
        today.set(Calendar.SECOND, 0);

        long todayStartTime = today.getTimeInMillis();

        if (time >= todayStartTime && time < todayStartTime + oneDay) { // today
            return "今天";
        } else if (time >= todayStartTime - oneDay && time < todayStartTime) { // yesterday
            return "昨天";
        } else if (time >= todayStartTime - oneDay * 2 && time < todayStartTime - oneDay) { // the day before yesterday
            return "前天";
        } else if (time > todayStartTime + oneDay) { // future
            return "将来某一天";
        } else {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            Date date = new Date(time);
            return dateFormat.format(date);
        }
    }

    /**
     * 转换日期 转换为更为人性化的时间
     *
     * @param time 时间
     * @return
     */
    private String translateDate(long time, long curTime) {
        long oneDay = 24 * 60 * 60;
        Calendar today = Calendar.getInstance();    //今天
        today.setTimeInMillis(curTime * 1000);
        today.set(Calendar.HOUR_OF_DAY, 0);
        today.set(Calendar.MINUTE, 0);
        today.set(Calendar.SECOND, 0);
        long todayStartTime = today.getTimeInMillis() / 1000;
        if (time >= todayStartTime) {
            long d = curTime - time;
            if (d <= 60) {
                return "1分钟前";
            } else if (d <= 60 * 60) {
                long m = d / 60;
                if (m <= 0) {
                    m = 1;
                }
                return m + "分钟前";
            } else {
                SimpleDateFormat dateFormat = new SimpleDateFormat("今天 HH:mm");
                Date date = new Date(time * 1000);
                String dateStr = dateFormat.format(date);
                if (!TextUtils.isEmpty(dateStr) && dateStr.contains(" 0")) {
                    dateStr = dateStr.replace(" 0", " ");
                }
                return dateStr;
            }
        } else {
            if (time < todayStartTime && time > todayStartTime - oneDay) {
                SimpleDateFormat dateFormat = new SimpleDateFormat("昨天 HH:mm");
                Date date = new Date(time * 1000);
                String dateStr = dateFormat.format(date);
                if (!TextUtils.isEmpty(dateStr) && dateStr.contains(" 0")) {

                    dateStr = dateStr.replace(" 0", " ");
                }
                return dateStr;
            } else if (time < todayStartTime - oneDay && time > todayStartTime - 2 * oneDay) {
                SimpleDateFormat dateFormat = new SimpleDateFormat("前天 HH:mm");
                Date date = new Date(time * 1000);
                String dateStr = dateFormat.format(date);
                if (!TextUtils.isEmpty(dateStr) && dateStr.contains(" 0")) {
                    dateStr = dateStr.replace(" 0", " ");
                }
                return dateStr;
            } else {
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
                Date date = new Date(time * 1000);
                String dateStr = dateFormat.format(date);
                if (!TextUtils.isEmpty(dateStr) && dateStr.contains(" 0")) {
                    dateStr = dateStr.replace(" 0", " ");
                }
                return dateStr;
            }
        }
    }

    /**
     * 计算剩余时间
     *
     * @param time
     * @param curTime
     * @return
     */
    public static String leftTime(long time, long curTime) {
        StringBuffer buf = new StringBuffer();
        long leftTime = time - curTime;
        if (leftTime < 0) {
            buf.append("Expired");
        } else if (leftTime >= 0 && leftTime < 1000) {
            buf.append("Expired");
        } else {
            if (leftTime / DAY > 0) {
                buf.append((leftTime / DAY) + "Day(s)");
                leftTime %= DAY;
            }
            if (leftTime / HOUR > 0) {
                buf.append((leftTime / HOUR) + "Hour(s)");
                leftTime %= HOUR;
            }
            if (leftTime / MINUTE > 0) {
                buf.append((leftTime / MINUTE) + "Minute(s)");
                leftTime %= MINUTE;
            }
            if (leftTime / SECOND > 0) {
                buf.append((leftTime / SECOND) + "Second(s)");
                leftTime %= SECOND;
            }
        }
        return buf.toString();
    }

}


================================================
FILE: app/src/main/java/com/luo/bluetooth/utils/DialogUtils.java
================================================
package com.luo.bluetooth.utils;

import android.app.Dialog;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.DialogInterface;
import android.os.Handler;
import android.view.View;

import com.luo.bluetooth.R;
import com.luo.bluetooth.customview.searchble.Effectstype;
import com.luo.bluetooth.customview.searchble.NiftyDialogBuilder;

import cn.pedant.SweetAlert.SweetAlertDialog;


/**
 * Created by Bruce on 2017/4/12 0012.
 */
public class DialogUtils {
    private static final short DIALOG_SHOW_TIME_SHORT = 1500;
    private static final short DIALOG_SHOW_TIME_LONG = 2500;
    private static NiftyDialogBuilder dialogBuilder;
    private static SweetAlertDialog dialog;

    public static void showProgressbarDialog(Context context) {
        showProgressbarDialog(context, null);
    }

    public static void showProgressbarDialog(Context context, int titleId) {
        showProgressbarDialog(context, context.getString(titleId));
    }

    public static void showProgressbarDialog(Context context, String title) {
        if (!checkReuseable(context, SweetAlertDialog.PROGRESS_TYPE)){
            dialog = new SweetAlertDialog(context, SweetAlertDialog.PROGRESS_TYPE);
        }
        dialog.setTitleText(title);
        dialog.setCancelable(false);
        dialog.setCanceledOnTouchOutside(false);
        dialog.show();
    }


    public static void showNormalDialog(Context context, int text) {
        showNormalDialog(context, context.getString(text));
    }

    public static void showNormalDialog(Context context, String text) {
        showNormalDialog(context, text, new SweetAlertDialog.OnSweetClickListener() {
            @Override
            public void onClick(SweetAlertDialog sweetAlertDialog) {
                dismissDialog(true);
            }
        });
    }

    public static void showNormalDialog(Context context, String text, SweetAlertDialog.OnSweetClickListener listener) {
        if (!checkReuseable(context, SweetAlertDialog.NORMAL_TYPE)){
            dialog = new SweetAlertDialog(context, SweetAlertDialog.NORMAL_TYPE);
        }
        dialog.setContentText(text)
                .setTitleText(null)
                .setConfirmClickListener(listener)
                .show();
    }

    public static SweetAlertDialog showNormalDialog(Context context, String text,
                                                    SweetAlertDialog.OnSweetClickListener listener,
                                                    SweetAlertDialog.OnSweetClickListener cancelListener) {
        if (!checkReuseable(context, SweetAlertDialog.NORMAL_TYPE)){
            dialog = new SweetAlertDialog(context, SweetAlertDialog.NORMAL_TYPE);
        }
        dialog.setContentText(text)
                .setTitleText(null)
                .setConfirmClickListener(listener)
                .setCancelClickListener(cancelListener)
                .show();
        return dialog;
    }

    public static void showNormalDialog(Context context, String title, String text, SweetAlertDialog.OnSweetClickListener listener) {
        if (!checkReuseable(context, SweetAlertDialog.NORMAL_TYPE)){
            dialog = new SweetAlertDialog(context, SweetAlertDialog.NORMAL_TYPE);
        }
        dialog.setContentText(text)
                .setTitleText(title)
                .setConfirmClickListener(listener)
                .show();
    }

    public static SweetAlertDialog showNormalDialog(Context context, String title, String text,
                                                    String confirmText,
                                                    SweetAlertDialog.OnSweetClickListener listener,
                                                    String cancelText,
                                                    SweetAlertDialog.OnSweetClickListener cancelListener) {
        if (!checkReuseable(context, SweetAlertDialog.NORMAL_TYPE)){
            dialog = new SweetAlertDialog(context, SweetAlertDialog.NORMAL_TYPE);
        }
        dialog.setContentText(text)
                .setTitleText(title)
                .setConfirmText(confirmText)
                .setConfirmClickListener(listener)
                .setCancelText(cancelText)
                .setCancelClickListener(cancelListener)
                .show();
        return dialog;
    }

    public static SweetAlertDialog showNormalDialog(Context context, String title,
                                                    String confirmText,
                                                    SweetAlertDialog.OnSweetClickListener listener,
                                                    String cancelText,
                                                    SweetAlertDialog.OnSweetClickListener cancelListener) {
        if (!checkReuseable(context, SweetAlertDialog.NORMAL_TYPE)){
            dialog = new SweetAlertDialog(context, SweetAlertDialog.NORMAL_TYPE);
        }
        dialog.setTitleText(title)
                .setConfirmText(confirmText)
                .setConfirmClickListener(listener)
                .setCancelText(cancelText)
                .setCancelClickListener(cancelListener)
                .show();
        return dialog;
    }

    public static void showLongErrorDialog(final Context context, String title) {
        showLongErrorDialog(context, title, new SweetAlertDialog.OnSweetClickListener() {
            @Override
            public void onClick(SweetAlertDialog sweetAlertDialog) {
                dismissDialog(true);
            }
        });
    }

    public static void showLongErrorDialog(Context context, String title, SweetAlertDialog.OnSweetClickListener listener) {
        showErrorDialog(context, title, DIALOG_SHOW_TIME_LONG, listener);
    }

    public static void showShortErrorDialog(final Context context, int title) {
        showShortErrorDialog(context, context.getString(title));
    }

    public static void showShortErrorDialog(final Context context, String title) {
        showShortErrorDialog(context, title, new SweetAlertDialog.OnSweetClickListener() {
            @Override
            public void onClick(SweetAlertDialog sweetAlertDialog) {
                dismissDialog(true);
            }
        });
    }

    public static void showShortErrorDialog(Context context, String title, SweetAlertDialog.OnSweetClickListener listener) {
        showErrorDialog(context, title, DIALOG_SHOW_TIME_SHORT, listener);
    }

    public static void showErrorDialog(Context context, int title) {
        showErrorDialog(context, context.getString(title));
    }

    public static void showErrorDialog(Context context, String title) {
        showErrorDialog(context, title, new SweetAlertDialog.OnSweetClickListener() {
            @Override
            public void onClick(SweetAlertDialog sweetAlertDialog) {
                dismissDialog(true);
            }
        });
    }

    public static void showErrorDialog(Context context, String title, short duration, SweetAlertDialog.OnSweetClickListener listener) {
        showErrorDialog(context, title, listener);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                dismissDialog(true);
            }
        }, duration);
    }

    public static void showErrorDialog(Context context, String title, SweetAlertDialog.OnSweetClickListener listener) {
        if (!checkReuseable(context, SweetAlertDialog.ERROR_TYPE)){
            dialog = new SweetAlertDialog(context, SweetAlertDialog.ERROR_TYPE);
        }
        dialog.setCancelable(false);
        dialog.setCanceledOnTouchOutside(false);
        dialog.setTitleText(title).setConfirmClickListener(listener);
        dialog.show();
    }

    public static void showErrorDialog(Context context, String title,String content, Swe
Download .txt
gitextract_042z6ibk/

├── .gitignore
├── .idea/
│   ├── codeStyles/
│   │   └── Project.xml
│   ├── compiler.xml
│   ├── gradle.xml
│   ├── jarRepositories.xml
│   ├── misc.xml
│   └── vcs.xml
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── luo/
│       │               └── bluetooth/
│       │                   └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── luo/
│       │   │           └── bluetooth/
│       │   │               ├── MainActivity.java
│       │   │               ├── MyApplication.java
│       │   │               ├── base/
│       │   │               │   └── BaseActivity.java
│       │   │               ├── common/
│       │   │               │   └── Constants.java
│       │   │               ├── customview/
│       │   │               │   └── searchble/
│       │   │               │       ├── BluetoothDeviceAdapter.java
│       │   │               │       ├── BluetoothDeviceBean.java
│       │   │               │       ├── ColorUtils.java
│       │   │               │       ├── DeviceListActivity.java
│       │   │               │       ├── Effectstype.java
│       │   │               │       ├── NiftyDialogBuilder.java
│       │   │               │       ├── SignalView.java
│       │   │               │       └── effects/
│       │   │               │           ├── BaseEffects.java
│       │   │               │           ├── FadeIn.java
│       │   │               │           ├── Fall.java
│       │   │               │           ├── FlipH.java
│       │   │               │           ├── FlipV.java
│       │   │               │           ├── NewsPaper.java
│       │   │               │           ├── RotateBottom.java
│       │   │               │           ├── RotateLeft.java
│       │   │               │           ├── Shake.java
│       │   │               │           ├── SideFall.java
│       │   │               │           ├── SlideBottom.java
│       │   │               │           ├── SlideLeft.java
│       │   │               │           ├── SlideRight.java
│       │   │               │           ├── SlideTop.java
│       │   │               │           └── Slit.java
│       │   │               ├── encryption/
│       │   │               │   ├── Aes.java
│       │   │               │   └── CRC.java
│       │   │               ├── protocol/
│       │   │               │   ├── CRC16Utils.java
│       │   │               │   ├── CrcUtils.java
│       │   │               │   ├── CustomEventListener.java
│       │   │               │   ├── CustomPacket.java
│       │   │               │   ├── CustomProtocol.java
│       │   │               │   ├── OnTimeoutResult.java
│       │   │               │   ├── WeiCeCode.java
│       │   │               │   └── WeiCeDeviceOperate.java
│       │   │               └── utils/
│       │   │                   ├── ByteUtils.java
│       │   │                   ├── DateUtils.java
│       │   │                   ├── DialogUtils.java
│       │   │                   ├── GpsUtils.java
│       │   │                   ├── GsonUtils.java
│       │   │                   ├── LogUtils.java
│       │   │                   ├── TextUtils.java
│       │   │                   └── ToastUtil.java
│       │   └── res/
│       │       ├── anim/
│       │       │   ├── fade_in.xml
│       │       │   └── fade_out.xml
│       │       ├── drawable/
│       │       │   ├── btn_press.xml
│       │       │   ├── btn_selector.xml
│       │       │   ├── btn_unpress.xml
│       │       │   ├── dialog_bg.xml
│       │       │   ├── ic_launcher_background.xml
│       │       │   └── sel_white_gray.xml
│       │       ├── drawable-v24/
│       │       │   └── ic_launcher_foreground.xml
│       │       ├── layout/
│       │       │   ├── activity_main.xml
│       │       │   ├── activity_search_device_list.xml
│       │       │   ├── dialog_layout.xml
│       │       │   └── item_bluetooth_device_list.xml
│       │       ├── mipmap-anydpi-v26/
│       │       │   ├── ic_launcher.xml
│       │       │   └── ic_launcher_round.xml
│       │       └── values/
│       │           ├── attrs.xml
│       │           ├── colors.xml
│       │           ├── strings.xml
│       │           └── styles.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── luo/
│                       └── bluetooth/
│                           └── ExampleUnitTest.java
├── bluetooth/
│   ├── .gitignore
│   ├── build.gradle
│   ├── libs/
│   │   ├── com.broadcom.bt.jar
│   │   └── samsung_ble_sdk_200.jar
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── stag/
│       │               └── bluetooth/
│       │                   └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── stag/
│       │   │           └── bluetooth/
│       │   │               ├── BluetoothController.java
│       │   │               ├── BluetoothDispatch.java
│       │   │               ├── BluetoothTask.java
│       │   │               ├── BluetoothTransfer.java
│       │   │               ├── OnBluetoothConnectStateChangeListener.java
│       │   │               ├── OnBluetoothScanListener.java
│       │   │               ├── OnBluetoothStateChangeListener.java
│       │   │               ├── OnBluetoothTransmitListener.java
│       │   │               ├── extend/
│       │   │               │   ├── AndroidBle.java
│       │   │               │   ├── BleGattCharacteristic.java
│       │   │               │   ├── BleGattService.java
│       │   │               │   ├── BleRequest.java
│       │   │               │   ├── BleService.java
│       │   │               │   ├── BroadcomBle.java
│       │   │               │   ├── IBle.java
│       │   │               │   ├── IBleRequestHandler.java
│       │   │               │   └── SamsungBle.java
│       │   │               ├── helper/
│       │   │               │   ├── BleHelper.java
│       │   │               │   ├── BluetoothHelper.java
│       │   │               │   ├── MyBluetoothService.java
│       │   │               │   ├── TraditionHelper.java
│       │   │               │   └── TraditionServerHelper.java
│       │   │               ├── packet/
│       │   │               │   └── Packet.java
│       │   │               ├── protocol/
│       │   │               │   ├── OnEventListener.java
│       │   │               │   ├── ParseResult.java
│       │   │               │   ├── Protocol.java
│       │   │               │   └── ResultType.java
│       │   │               └── util/
│       │   │                   ├── ByteUtils.java
│       │   │                   ├── LogUtils.java
│       │   │                   └── Logs.java
│       │   └── res/
│       │       └── values/
│       │           └── strings.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── stag/
│                       └── bluetooth/
│                           └── ExampleUnitTest.java
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
Download .txt
SYMBOL INDEX (805 symbols across 78 files)

FILE: app/src/androidTest/java/com/luo/bluetooth/ExampleInstrumentedTest.java
  class ExampleInstrumentedTest (line 18) | @RunWith(AndroidJUnit4.class)
    method useAppContext (line 20) | @Test

FILE: app/src/main/java/com/luo/bluetooth/MainActivity.java
  class MainActivity (line 34) | public class MainActivity extends AppCompatActivity implements OnBluetoo...
    method onCreate (line 45) | @Override
    method onStop (line 53) | @Override
    method onDestroy (line 58) | @Override
    method initView (line 71) | private void initView() {
    method initBluetooth (line 81) | private void initBluetooth() {
    method btnSearchBle (line 109) | public void btnSearchBle(View view) {
    method btnMacConnect (line 134) | public void btnMacConnect(View view) {
    method btnDisconnectBle (line 141) | public void btnDisconnectBle(View view) {
    method onActivityResult (line 157) | @Override
    method onBluetoothOpen (line 180) | @Override
    method onBluetoothClose (line 186) | @Override
    method onBluetoothConnect (line 198) | @Override
    method onBluetoothDisconnect (line 214) | @Override
    method btnProtocolParse (line 224) | public void btnProtocolParse(View view) {
    method btnProtocolPacket (line 238) | public void btnProtocolPacket(View view) {
    method btnSendConfirmData (line 252) | public void btnSendConfirmData(View view) {

FILE: app/src/main/java/com/luo/bluetooth/MyApplication.java
  class MyApplication (line 7) | public class MyApplication extends Application {
    method onCreate (line 10) | @Override

FILE: app/src/main/java/com/luo/bluetooth/base/BaseActivity.java
  class BaseActivity (line 12) | public class BaseActivity extends AppCompatActivity {
    method onCreate (line 21) | @Override
    method onResume (line 28) | @Override
    method onDestroy (line 34) | @Override
    method startToActivity (line 39) | public void startToActivity(Class activityClass) {

FILE: app/src/main/java/com/luo/bluetooth/common/Constants.java
  class Constants (line 3) | public class Constants {

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/BluetoothDeviceAdapter.java
  class BluetoothDeviceAdapter (line 21) | public class BluetoothDeviceAdapter extends BaseAdapter{
    method BluetoothDeviceAdapter (line 25) | public BluetoothDeviceAdapter(Context mContext, List<BluetoothDeviceBe...
    method getCount (line 30) | @Override
    method getItem (line 35) | @Override
    method getItemId (line 40) | @Override
    method getView (line 45) | @Override
    method initView (line 61) | public void initView(int i,ViewHolder holder){
    class ViewHolder (line 79) | private class ViewHolder{

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/BluetoothDeviceBean.java
  class BluetoothDeviceBean (line 10) | @Data

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/ColorUtils.java
  class ColorUtils (line 7) | public class ColorUtils {
    method getColorFilter (line 9) | public static ColorFilter getColorFilter(int color) {

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/DeviceListActivity.java
  class DeviceListActivity (line 40) | public class DeviceListActivity extends BaseActivity implements View.OnC...
    method onCreate (line 51) | @Override
    method finish (line 62) | @Override
    method onDestroy (line 69) | @Override
    method findViews (line 76) | protected void findViews() {
    method initData (line 86) | public void initData() {
    method getPermissions (line 99) | private void getPermissions() {
    method onRequestPermissionsResult (line 110) | @Override
    method startSearchKey (line 127) | private void startSearchKey() {
    method stopSearchKey (line 137) | private void stopSearchKey() {
    method showHistory (line 144) | private void showHistory() {
    method bindEvent (line 152) | protected void bindEvent() {
    method onClick (line 160) | @Override
    method onItemClick (line 178) | @Override
    method onItemLongClick (line 191) | @Override
    method showSetNickNameDialog (line 197) | public void showSetNickNameDialog(Context context, final BluetoothDevi...
    method onBluetoothScanFindDevice (line 233) | @Override
    method showProgressBar (line 271) | private void showProgressBar(){
    method hideProgressBar (line 275) | private void hideProgressBar(){
    method onBluetoothScanFinish (line 279) | @Override

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/Effectstype.java
  type Effectstype (line 36) | public enum Effectstype {
    method Effectstype (line 55) | private Effectstype(Class<? extends BaseEffects> mclass) {
    method getAnimator (line 59) | public BaseEffects getAnimator() {

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/NiftyDialogBuilder.java
  class NiftyDialogBuilder (line 39) | public class NiftyDialogBuilder extends Dialog implements DialogInterface {
    method NiftyDialogBuilder (line 87) | public NiftyDialogBuilder(Context context) {
    method NiftyDialogBuilder (line 92) | public NiftyDialogBuilder(Context context, int theme) {
    method onCreate (line 97) | @Override
    method getInstance (line 107) | public static NiftyDialogBuilder getInstance(Context context) {
    method init (line 121) | private void init(Context context) {
    method toDefault (line 161) | public void toDefault(){
    method withDividerColor (line 168) | public NiftyDialogBuilder withDividerColor(String colorString) {
    method withDividerColor (line 172) | public NiftyDialogBuilder withDividerColor(int color) {
    method withTitle (line 178) | public NiftyDialogBuilder withTitle(CharSequence title) {
    method withTitleColor (line 184) | public NiftyDialogBuilder withTitleColor(String colorString) {
    method withTitleColor (line 189) | public NiftyDialogBuilder withTitleColor(int color) {
    method withMessage (line 194) | public NiftyDialogBuilder withMessage(int textResId) {
    method withMessage (line 200) | public NiftyDialogBuilder withMessage(CharSequence msg) {
    method withMessageColor (line 205) | public NiftyDialogBuilder withMessageColor(String colorString) {
    method withMessageColor (line 209) | public NiftyDialogBuilder withMessageColor(int color) {
    method withDialogColor (line 214) | public NiftyDialogBuilder withDialogColor(String colorString) {
    method withDialogColor (line 219) | public NiftyDialogBuilder withDialogColor(int color) {
    method withIcon (line 224) | public NiftyDialogBuilder withIcon(int drawableResId) {
    method withIcon (line 229) | public NiftyDialogBuilder withIcon(Drawable icon) {
    method withDuration (line 234) | public NiftyDialogBuilder withDuration(int duration) {
    method withEffect (line 239) | public NiftyDialogBuilder withEffect(Effectstype type) {
    method withButtonDrawable (line 244) | public NiftyDialogBuilder withButtonDrawable(int resid) {
    method withButton1Text (line 249) | public NiftyDialogBuilder withButton1Text(CharSequence text) {
    method withButton2Text (line 255) | public NiftyDialogBuilder withButton2Text(CharSequence text) {
    method setButton1Click (line 260) | public NiftyDialogBuilder setButton1Click(View.OnClickListener click) {
    method setButton2Click (line 265) | public NiftyDialogBuilder setButton2Click(View.OnClickListener click) {
    method setCustomView (line 271) | public NiftyDialogBuilder setCustomView(int resId, Context context) {
    method setCustomView (line 280) | public NiftyDialogBuilder setCustomView(View view, Context context) {
    method removeAllCustomView (line 289) | public NiftyDialogBuilder removeAllCustomView(){
    method isCancelableOnTouchOutside (line 297) | public NiftyDialogBuilder isCancelableOnTouchOutside(boolean cancelabl...
    method isCancelable (line 303) | public NiftyDialogBuilder isCancelable(boolean cancelable) {
    method toggleView (line 309) | private void toggleView(View view, Object obj){
    method show (line 316) | @Override
    method start (line 321) | private void start(Effectstype type){
    method dismiss (line 329) | @Override

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/SignalView.java
  class SignalView (line 19) | public class SignalView extends View {
    method SignalView (line 27) | public SignalView(Context context) {
    method SignalView (line 31) | public SignalView(Context context, AttributeSet attrs) {
    method SignalView (line 35) | public SignalView(Context context, AttributeSet attrs, int defStyleAtt...
    method init (line 44) | private void init(){
    method setIntensity (line 54) | public void setIntensity(int intensity){
    method onMeasure (line 63) | @Override
    method onDraw (line 77) | @Override

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/BaseEffects.java
  class BaseEffects (line 37) | public abstract  class BaseEffects {
    method setupAnimation (line 51) | protected abstract void setupAnimation(View view);
    method start (line 53) | public void start(View view) {
    method reset (line 60) | public void reset(View view) {
    method getAnimatorSet (line 66) | public AnimatorSet getAnimatorSet() {
    method setDuration (line 70) | public void setDuration(long duration) {

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/FadeIn.java
  class FadeIn (line 22) | public class FadeIn extends BaseEffects{
    method setupAnimation (line 24) | @Override

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/Fall.java
  class Fall (line 22) | public class Fall extends BaseEffects{
    method setupAnimation (line 24) | @Override

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/FlipH.java
  class FlipH (line 23) | public class FlipH  extends BaseEffects{
    method setupAnimation (line 25) | @Override

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/FlipV.java
  class FlipV (line 23) | public class FlipV extends BaseEffects{
    method setupAnimation (line 25) | @Override

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/NewsPaper.java
  class NewsPaper (line 22) | public class NewsPaper extends BaseEffects{
    method setupAnimation (line 24) | @Override

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/RotateBottom.java
  class RotateBottom (line 23) | public class RotateBottom extends BaseEffects{
    method setupAnimation (line 25) | @Override

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/RotateLeft.java
  class RotateLeft (line 22) | public class RotateLeft extends BaseEffects{
    method setupAnimation (line 24) | @Override

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/Shake.java
  class Shake (line 24) | public class Shake  extends BaseEffects{
    method setupAnimation (line 26) | @Override

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/SideFall.java
  class SideFall (line 22) | public class SideFall extends BaseEffects{
    method setupAnimation (line 24) | @Override

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/SlideBottom.java
  class SlideBottom (line 23) | public class SlideBottom extends BaseEffects{
    method setupAnimation (line 25) | @Override

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/SlideLeft.java
  class SlideLeft (line 22) | public class SlideLeft extends BaseEffects{
    method setupAnimation (line 24) | @Override

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/SlideRight.java
  class SlideRight (line 22) | public class SlideRight extends BaseEffects{
    method setupAnimation (line 24) | @Override

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/SlideTop.java
  class SlideTop (line 22) | public class SlideTop extends BaseEffects{
    method setupAnimation (line 24) | @Override

FILE: app/src/main/java/com/luo/bluetooth/customview/searchble/effects/Slit.java
  class Slit (line 23) | public class Slit extends BaseEffects{
    method setupAnimation (line 25) | @Override

FILE: app/src/main/java/com/luo/bluetooth/encryption/Aes.java
  class Aes (line 13) | public class Aes {
    method expandKey (line 57) | private static byte[] expandKey(byte[] key) {
    method galois_mul2 (line 85) | private static byte galois_mul2(byte value) {
    method aes_encr (line 104) | private static byte[] aes_encr(byte[] input, byte[] expandedKey) {
    method aes_decr (line 251) | private static byte[] aes_decr(byte[] input, byte[] expandedKey) {
    method decode16 (line 422) | public static byte[] decode16(byte[] data, byte[] key) {
    method encode16 (line 427) | public static byte[] encode16(byte[] data, byte[] key) {
    method decode (line 432) | public static byte[] decode(byte[] data, byte[] key) {
    method encode (line 441) | public static byte[] encode(byte[] data, byte[] key) {

FILE: app/src/main/java/com/luo/bluetooth/encryption/CRC.java
  class CRC (line 3) | public class CRC {
    method calcCrc (line 16) | public static byte calcCrc(byte[] data) {
    method calcCrc8 (line 31) | public static byte calcCrc8(byte[] data, int offset, int len) {
    method calcCrc8 (line 53) | public static byte calcCrc8(byte[] data, int offset, int len, byte pre...

FILE: app/src/main/java/com/luo/bluetooth/protocol/CRC16Utils.java
  class CRC16Utils (line 20) | class CRC16Utils {
    method calcCrc16 (line 39) | public static int calcCrc16(byte[] data) {
    method calcCrc16 (line 51) | public static int calcCrc16(byte[] data, int offset, int len) {
    method calcCrc16 (line 64) | public static int calcCrc16(byte[] data, int offset, int len, int prev...
    method getCrc (line 82) | public static String getCrc(int res) {

FILE: app/src/main/java/com/luo/bluetooth/protocol/CrcUtils.java
  class CrcUtils (line 19) | public class CrcUtils {
    method Crc16Ccitt (line 23) | public static int Crc16Ccitt(int crc, byte[] data) {

FILE: app/src/main/java/com/luo/bluetooth/protocol/CustomEventListener.java
  type CustomEventListener (line 8) | public interface CustomEventListener extends OnEventListener {

FILE: app/src/main/java/com/luo/bluetooth/protocol/CustomPacket.java
  class CustomPacket (line 5) | public class CustomPacket extends Packet {
    method CustomPacket (line 8) | public CustomPacket(int cmd, byte expandCode) {
    method CustomPacket (line 13) | public CustomPacket(int cmd, byte[] data, byte expandCode) {
    method getExpandCode (line 18) | public byte getExpandCode() {
    method match (line 27) | @Override

FILE: app/src/main/java/com/luo/bluetooth/protocol/CustomProtocol.java
  class CustomProtocol (line 18) | public class CustomProtocol extends Protocol<CustomPacket, CustomEventLi...
    method CustomProtocol (line 36) | protected CustomProtocol(Context context) {
    method CustomProtocol (line 40) | public CustomProtocol(Context context, CustomEventListener listener) {
    method packetToBytes (line 44) | @Override
    method parse (line 107) | @Override
    method listToByte (line 205) | private byte[] listToByte(List<Byte> byteList) {
    method byteToList (line 216) | private List<Byte> byteToList(byte[] bytes) {
    method addBytes (line 227) | private void addBytes(ArrayList<Byte> byteList, byte[] encodeBytes) {
    method getType (line 238) | @Override
    method getServiceUUID (line 243) | @Override
    method getSendTunnelUUID (line 248) | @Override
    method getRecvTunnelUUID (line 253) | @Override

FILE: app/src/main/java/com/luo/bluetooth/protocol/OnTimeoutResult.java
  type OnTimeoutResult (line 10) | public interface OnTimeoutResult<T> {
    method onResult (line 12) | void onResult(boolean isTimeout, T result);

FILE: app/src/main/java/com/luo/bluetooth/protocol/WeiCeCode.java
  class WeiCeCode (line 19) | public class WeiCeCode {

FILE: app/src/main/java/com/luo/bluetooth/protocol/WeiCeDeviceOperate.java
  class WeiCeDeviceOperate (line 16) | public class WeiCeDeviceOperate {
    method getSn (line 21) | public static void getSn(final OnTimeoutResult<String> obtainResult, b...

FILE: app/src/main/java/com/luo/bluetooth/utils/ByteUtils.java
  class ByteUtils (line 12) | public class ByteUtils {
    method bytesToHex (line 15) | public static String bytesToHex(byte[] bytes) {
    method uuidToByte5BigEndian2 (line 32) | public static byte[] uuidToByte5BigEndian2(UUID u) {
    method byte5ToUuidBigEndian2 (line 49) | public static UUID byte5ToUuidBigEndian2(byte[] b) {
    method uuidToByte5BigEndian (line 65) | public static byte[] uuidToByte5BigEndian(UUID u) {
    method byte5ToUuidBigEndian (line 82) | public static UUID byte5ToUuidBigEndian(byte[] b) {
    method byte3ToLongBigEndian (line 97) | public static long byte3ToLongBigEndian(byte[] b) {
    method longToByte3BigEndian (line 110) | public static byte[] longToByte3BigEndian(long i) {
    method compareBytes (line 125) | public static boolean compareBytes(byte[] first, byte[] second) {
    method uuidToByte4BigEndian (line 141) | public static byte[] uuidToByte4BigEndian(UUID u) {
    method byte4ToUuidBigEndian (line 157) | public static UUID byte4ToUuidBigEndian(byte[] b) {
    method byte4ToUuidBigEndian2 (line 172) | public static UUID byte4ToUuidBigEndian2(byte[] b) {
    method longToByte4BigEndian (line 187) | public static byte[] longToByte4BigEndian(long l) {
    method byte4ToLongBigEndian (line 202) | public static long byte4ToLongBigEndian(byte[] b) {
    method byte16ToUuidBigEndian (line 216) | public static UUID byte16ToUuidBigEndian(byte[] b) {
    method uuidToByte16BigEndian (line 226) | public static byte[] uuidToByte16BigEndian(UUID uuid) {
    method byte8ToUuidBigEndian (line 238) | public static UUID byte8ToUuidBigEndian(byte[] b) {
    method uuidToByte8BigEndian (line 248) | public static byte[] uuidToByte8BigEndian(UUID uuid) {
    method byte8ToLongBigEndian (line 259) | public static long byte8ToLongBigEndian(byte[] b) {
    method longToByte8BigEndian (line 277) | public static byte[] longToByte8BigEndian(long l) {
    method byte6ToUuidBigEndian2 (line 296) | public static UUID byte6ToUuidBigEndian2(byte[] b) {
    method uuidToByte6BigEndian2 (line 312) | public static byte[] uuidToByte6BigEndian2(UUID uuid) {
    method byte6ToUuidBigEndian (line 330) | public static UUID byte6ToUuidBigEndian(byte[] b) {
    method uuidToByte6BigEndian (line 346) | public static byte[] uuidToByte6BigEndian(UUID uuid) {
    method byte4ToIntBigEndian (line 364) | public static int byte4ToIntBigEndian(byte[] b) {
    method intToByte4BigEndian (line 378) | public static byte[] intToByte4BigEndian(int i) {
    method byte3ToIntBigEndian (line 393) | public static int byte3ToIntBigEndian(byte[] b) {
    method intToByte3BigEndian (line 406) | public static byte[] intToByte3BigEndian(int i) {
    method toString (line 414) | public static String toString(byte[] data) {
    method toString (line 418) | public static String toString(byte[] data, String interval) {
    method subBytes (line 435) | public static byte[] subBytes(byte[] data, int start, int len) {
    method subBytes (line 443) | public static byte[] subBytes(byte[] data, int start) {
    method bytesToLong (line 454) | public static long bytesToLong(byte[] b) {
    method longToBytes (line 473) | public static byte[] longToBytes(long l) {
    method combineByteArray (line 492) | public static byte[] combineByteArray(byte[]... bytes) {
    method uuidToBytes (line 517) | public static byte[] uuidToBytes(UUID uuid) {
    method bytesToUuid (line 527) | public static UUID bytesToUuid(byte[] data) {
    method intToBytes2 (line 541) | public static byte[] intToBytes2(int i) {
    method intToBytes2SmallDian (line 548) | public static byte[] intToBytes2SmallDian(int i) {
    method bytes2ToInt (line 561) | public static int bytes2ToInt(byte[] b) {
    method bytesS2ToInt (line 573) | public static int bytesS2ToInt(byte[] b) {
    method bytes2ToInt2 (line 585) | public static int bytes2ToInt2(byte[] b) {
    method bytesToIntBigEndian (line 597) | public static int bytesToIntBigEndian(byte[] b) {
    method bytesToIntSmallEndian (line 611) | public static int bytesToIntSmallEndian(byte[] b) {
    method intToBytesBigEndian (line 625) | public static byte[] intToBytesBigEndian(int i) {
    method bytesToInt (line 640) | public static int bytesToInt(byte[] b) {
    method intToBytes (line 654) | public static byte[] intToBytes(int i) {
    method bytesToShort (line 669) | public static short bytesToShort(byte[] b) {
    method shortToBytes (line 681) | public static byte[] shortToBytes(short i) {
    method bytesToShortBigEndian (line 695) | public static short bytesToShortBigEndian(byte[] b) {
    method shortToBytesBigEndian (line 708) | public static byte[] shortToBytesBigEndian(short i) {
    method wrapData (line 722) | public static byte[] wrapData(byte[] data, int len) {
    method getByteBits (line 740) | public static byte[] getByteBits(byte data) {
    method getBytesWithBuffer (line 748) | public static byte[] getBytesWithBuffer(ByteBuffer buffer) {
    method equal (line 757) | public static boolean equal(byte[] data1, byte[] data2) {
    method compare (line 761) | public static int compare(byte[] bytes1, byte[] bytes2) {
    method getXor (line 782) | public static byte getXor(byte[] data) {
    method getXor (line 786) | public static byte getXor(byte[] data, int start, int len) {
    method bytesToAscii (line 796) | public static String bytesToAscii(byte[] bytes, int offset, int dateLe...
    method bytesToAscii (line 811) | public static String bytesToAscii(byte[] bytes, int dateLen) {
    method bytesToAscii (line 815) | public static String bytesToAscii(byte[] bytes) {
    method asciiToBytes (line 819) | public static byte[] asciiToBytes(String string) {
    method hexStringToBytes (line 829) | public static byte[] hexStringToBytes(@NonNull String hexString) {
    method addSpaceToString (line 838) | public static String addSpaceToString(String origin, int strLength) {

FILE: app/src/main/java/com/luo/bluetooth/utils/DateUtils.java
  class DateUtils (line 13) | public final class DateUtils {
    method getCurrentDateString (line 36) | public static String getCurrentDateString() {
    method dateAddHours (line 47) | public static Date dateAddHours(Date date, int hour) {
    method dateToString (line 52) | public static String dateToString(long time, String pattern)
    method dateToString (line 57) | public static String dateToString(Date date, String pattern)
    method stringToDate (line 62) | public static Date stringToDate(String dateStr, String pattern)
    method formatDate (line 67) | public static String formatDate(long time, String type) {
    method formatDate (line 71) | public static String formatDate(Date date) {
    method formatDate (line 81) | public static String formatDate(Date date, String type) {
    method parseDate (line 98) | public static Date parseDate(String dateStr, String type) {
    method getYear (line 116) | public static int getYear(Date date) {
    method getMonth (line 129) | public static int getMonth(Date date) {
    method getDay (line 142) | public static int getDay(Date date) {
    method getHour (line 150) | public static int getHour(Date date){
    method getMinute (line 156) | public static int getMinute(Date date){
    method getSecond (line 162) | public static int getSecond(Date date){
    method translateDate (line 175) | public static String translateDate(Long time) {
    method translateDate (line 211) | private String translateDate(long time, long curTime) {
    method leftTime (line 275) | public static String leftTime(long time, long curTime) {

FILE: app/src/main/java/com/luo/bluetooth/utils/DialogUtils.java
  class DialogUtils (line 20) | public class DialogUtils {
    method showProgressbarDialog (line 26) | public static void showProgressbarDialog(Context context) {
    method showProgressbarDialog (line 30) | public static void showProgressbarDialog(Context context, int titleId) {
    method showProgressbarDialog (line 34) | public static void showProgressbarDialog(Context context, String title) {
    method showNormalDialog (line 45) | public static void showNormalDialog(Context context, int text) {
    method showNormalDialog (line 49) | public static void showNormalDialog(Context context, String text) {
    method showNormalDialog (line 58) | public static void showNormalDialog(Context context, String text, Swee...
    method showNormalDialog (line 68) | public static SweetAlertDialog showNormalDialog(Context context, Strin...
    method showNormalDialog (line 82) | public static void showNormalDialog(Context context, String title, Str...
    method showNormalDialog (line 92) | public static SweetAlertDialog showNormalDialog(Context context, Strin...
    method showNormalDialog (line 110) | public static SweetAlertDialog showNormalDialog(Context context, Strin...
    method showLongErrorDialog (line 127) | public static void showLongErrorDialog(final Context context, String t...
    method showLongErrorDialog (line 136) | public static void showLongErrorDialog(Context context, String title, ...
    method showShortErrorDialog (line 140) | public static void showShortErrorDialog(final Context context, int tit...
    method showShortErrorDialog (line 144) | public static void showShortErrorDialog(final Context context, String ...
    method showShortErrorDialog (line 153) | public static void showShortErrorDialog(Context context, String title,...
    method showErrorDialog (line 157) | public static void showErrorDialog(Context context, int title) {
    method showErrorDialog (line 161) | public static void showErrorDialog(Context context, String title) {
    method showErrorDialog (line 170) | public static void showErrorDialog(Context context, String title, shor...
    method showErrorDialog (line 180) | public static void showErrorDialog(Context context, String title, Swee...
    method showErrorDialog (line 190) | public static void showErrorDialog(Context context, String title,Strin...
    method showShortSuccessDialog (line 200) | public static void showShortSuccessDialog(Context context, int title) {
    method showShortSuccessDialog (line 204) | public static void showShortSuccessDialog(Context context, String titl...
    method showShortSuccessDialog (line 213) | public static void showShortSuccessDialog(Context context, String titl...
    method showSuccessDialog (line 217) | public static void showSuccessDialog(Context context, int title) {
    method showSuccessDialog (line 221) | public static void showSuccessDialog(Context context, String title) {
    method showSuccessDialog (line 230) | public static void showSuccessDialog(Context context, String title, sh...
    method showSuccessDialog (line 240) | public static void showSuccessDialog(Context context, int title, Sweet...
    method showSuccessDialog (line 244) | public static void showSuccessDialog(Context context, String title, Sw...
    method showSuccessDialog (line 255) | public static void showSuccessDialog(Context context, String title, St...
    method showShortWarningDialog (line 267) | public static void showShortWarningDialog(Context context, int title) {
    method showShortWarningDialog (line 271) | public static void showShortWarningDialog(Context context, String titl...
    method showShortWarningDialog (line 280) | public static void showShortWarningDialog(Context context, String titl...
    method showWarningDialog (line 284) | public static void showWarningDialog(Context context, int id) {
    method showWarningDialog (line 288) | public static void showWarningDialog(Context context, String title) {
    method showWarningDialog (line 297) | public static void showWarningDialog(Context context, String title, sh...
    method showWarningDialog (line 307) | public static void showWarningDialog(Context context, String title, Sw...
    method showWarningDialog (line 315) | public static void showWarningDialog(Context context, String title,Str...
    method showWarningDialog (line 323) | public static void showWarningDialog(Context context, String title,Str...
    method showCancelableDialog (line 337) | public static SweetAlertDialog showCancelableDialog(Context context, S...
    method checkReuseable (line 352) | private static boolean checkReuseable(Context context, int dialogType){
    method isMatchingCurrentContext (line 363) | public static boolean isMatchingCurrentContext(Context context){
    method getDialog (line 367) | public static Dialog getDialog(){
    method dismissDialog (line 371) | public static void dismissDialog() {
    method dismissDialog (line 375) | public static void dismissDialog(boolean animate) {
    method dismissMatchCurrentDialog (line 385) | public static void dismissMatchCurrentDialog(Context context){
    method showDialog (line 398) | public static void showDialog(Context context, int titleId, int conten...
    method showNiftyTipDialog (line 404) | public static void showNiftyTipDialog(Context context, String title, S...
    method showNiftyCustonDialog (line 431) | public static void showNiftyCustonDialog(Context context, int title, V...
    method showNiftyCustonDialog (line 435) | public static void showNiftyCustonDialog(Context context, String title...
    method showNiftyCustonDialog (line 439) | public static void showNiftyCustonDialog(Context context, String title...
    method dismissNiftyDialog (line 465) | public static void dismissNiftyDialog() {

FILE: app/src/main/java/com/luo/bluetooth/utils/GpsUtils.java
  class GpsUtils (line 6) | public class GpsUtils {
    method isOPen (line 7) | public static boolean isOPen(final Context context) {

FILE: app/src/main/java/com/luo/bluetooth/utils/GsonUtils.java
  class GsonUtils (line 16) | public class GsonUtils {
    method GsonUtils (line 24) | private GsonUtils() {
    method string2Objects (line 38) | public static <T> List<T> string2Objects(String jsonArray, Class<T> cl...
    method Object2String (line 55) | public static String Object2String(Object obj) {
    method string2Object (line 62) | public static <T> T string2Object(String jsonStr, Class<T> c) {
    method objToJson (line 70) | public static String objToJson(Object obj) {

FILE: app/src/main/java/com/luo/bluetooth/utils/LogUtils.java
  class LogUtils (line 8) | public class LogUtils {
    method LogUtils (line 12) | private LogUtils() {
    method v (line 15) | public static void v(String tag, String msg) {
    method d (line 22) | public static void d(String tag, String msg) {
    method i (line 39) | public static void i(String tag, String msg) {
    method w (line 46) | public static void w(String tag, String msg) {
    method e (line 53) | public static void e(String tag, String msg) {

FILE: app/src/main/java/com/luo/bluetooth/utils/TextUtils.java
  class TextUtils (line 3) | public class TextUtils {
    method isEmpty (line 5) | public static boolean isEmpty(String dateStr) {

FILE: app/src/main/java/com/luo/bluetooth/utils/ToastUtil.java
  class ToastUtil (line 15) | public class ToastUtil {
    method ToastUtil (line 20) | private ToastUtil() {
    method controlShow (line 28) | public static void controlShow(boolean isShowToast){
    method cancelToast (line 35) | public void cancelToast() {
    method showShort (line 47) | public static void showShort(Context context, CharSequence message) {
    method showShort (line 65) | public static void showShort(Context context, int resId) {
    method showLong (line 82) | public static void showLong(Context context, CharSequence message) {
    method showLong (line 99) | public static void showLong(Context context, int resId) {
    method show (line 117) | public static void show(Context context, CharSequence message, int dur...
    method show (line 135) | public static void show(Context context, int resId, int duration) {
    method customToastView (line 153) | public static void customToastView(Context context, CharSequence messa...
    method customToastGravity (line 176) | public static void customToastGravity(Context context, CharSequence me...
    method showToastWithImageAndText (line 198) | public static void showToastWithImageAndText(Context context, CharSequ...
    method customToastAll (line 228) | public static void customToastAll(Context context, CharSequence messag...
    method customToastAll (line 262) | public static void customToastAll(Context context, int resId, int dura...

FILE: app/src/test/java/com/luo/bluetooth/ExampleUnitTest.java
  class ExampleUnitTest (line 12) | public class ExampleUnitTest {
    method addition_isCorrect (line 13) | @Test

FILE: bluetooth/src/androidTest/java/com/stag/bluetooth/ExampleInstrumentedTest.java
  class ExampleInstrumentedTest (line 17) | @RunWith(AndroidJUnit4.class)
    method useAppContext (line 19) | @Test

FILE: bluetooth/src/main/java/com/stag/bluetooth/BluetoothController.java
  class BluetoothController (line 27) | public final class BluetoothController {
    method getController (line 51) | public static BluetoothController getController(Context context) {
    method BluetoothController (line 63) | private BluetoothController(Context context) {
    method getConnectStateChangeListener (line 90) | public OnBluetoothConnectStateChangeListener getConnectStateChangeList...
    method registerConnectStateChangeListener (line 94) | public void registerConnectStateChangeListener(final OnBluetoothConnec...
    method unregisterConnectStateChangeListener (line 98) | public void unregisterConnectStateChangeListener() {
    method getBluetoothStateChangeListener (line 102) | public OnBluetoothStateChangeListener getBluetoothStateChangeListener() {
    method registerBluetoothStateChangeListener (line 106) | public void registerBluetoothStateChangeListener(OnBluetoothStateChang...
    method unregisterBluetoothStateChangeListener (line 110) | public void unregisterBluetoothStateChangeListener(){
    method getTransmitListener (line 114) | public OnBluetoothTransmitListener getTransmitListener() {
    method registerTransmitListener (line 120) | public void registerTransmitListener(OnBluetoothTransmitListener trans...
    method unregisterTransmitListener (line 126) | public void unregisterTransmitListener(){
    method setBluetoothType (line 130) | public void setBluetoothType(short bluetoothType) {
    method setProtocol (line 146) | public void setProtocol(Protocol protocol) {
    method getProtocol (line 158) | public Protocol getProtocol() {
    method isConnected (line 165) | public boolean isConnected() {
    method isConnecting (line 171) | public boolean isConnecting(){
    method isScanning (line 177) | public boolean isScanning(){
    method getBluetoothType (line 184) | public short getBluetoothType() {
    method setBleHighConnectionPriority (line 188) | public boolean setBleHighConnectionPriority(boolean flag){
    method setBleHighSpeedMode (line 195) | public boolean setBleHighSpeedMode(boolean flag){
    method isBleHighSpeedMode (line 202) | public boolean isBleHighSpeedMode(){
    method setSendMethod (line 212) | private void setSendMethod() {
    method sendData (line 221) | public void sendData(byte[] data) {
    method connect (line 230) | public void connect(String address) {
    method connect (line 234) | public void connect(String address, Protocol protocol){
    method disconnect (line 242) | public void disconnect() {
    method startScan (line 251) | public void startScan(OnBluetoothScanListener listener) {
    method stopScan (line 268) | public void stopScan() {
    method registerBluetoothBroadcast (line 286) | private void registerBluetoothBroadcast() {
    method unregisterBluetoothBroadcast (line 297) | private void unregisterBluetoothBroadcast() {
    method onReceive (line 308) | @Override
    method handleScanFindResult (line 368) | private void handleScanFindResult(BluetoothDevice device, int rssi, bo...
    method setScanRemoveRepeat (line 390) | public void setScanRemoveRepeat(boolean b) {
    method isScanRemoveRepeat (line 394) | public boolean isScanRemoveRepeat() {

FILE: bluetooth/src/main/java/com/stag/bluetooth/BluetoothDispatch.java
  class BluetoothDispatch (line 14) | public final class BluetoothDispatch {
    method getInstance (line 20) | public static BluetoothDispatch getInstance(){
    method start (line 30) | public void start(){
    method stop (line 37) | public void stop(){
    method dispatch (line 45) | public void dispatch(final Callback callback, boolean runInMainThread){
    type Callback (line 70) | public interface Callback{
      method callback (line 71) | void callback();

FILE: bluetooth/src/main/java/com/stag/bluetooth/BluetoothTask.java
  class BluetoothTask (line 10) | public final class BluetoothTask<T extends Packet> {
    method BluetoothTask (line 24) | public <E extends T> BluetoothTask(E packet) {
    method BluetoothTask (line 28) | public <E extends T> BluetoothTask(E packet, OnResultListener<E> onRes...
    method BluetoothTask (line 32) | public <E extends T>BluetoothTask(E packet, boolean resultCallbackInMa...
    method BluetoothTask (line 36) | public <E extends T> BluetoothTask(int tryCount, int timeout, E packet...
    method BluetoothTask (line 40) | public <E extends T> BluetoothTask(int tryCount, int timeout, E packet...
    method isTimeout (line 48) | public boolean isTimeout() {
    method send (line 57) | public void send() {
    method sendBySync2 (line 65) | public byte[] sendBySync2() {
    method sendBySync (line 93) | public T sendBySync() {
    method getTryCount (line 117) | public int getTryCount() {
    method setTryCount (line 121) | public BluetoothTask setTryCount(int tryCount) {
    method getTimeout (line 126) | public long getTimeout() {
    method setTimeout (line 130) | public BluetoothTask setTimeout(long timeout) {
    method getSentTime (line 135) | public long getSentTime() {
    method setSentTime (line 139) | BluetoothTask setSentTime(long sendTime) {
    method getPacket (line 144) | public Packet getPacket() {
    method setPacket (line 148) | public BluetoothTask setPacket(T packet) {
    method isResultCallbackInMainThread (line 153) | public boolean isResultCallbackInMainThread() {
    method setResultCallbackInMainThread (line 157) | public BluetoothTask setResultCallbackInMainThread(boolean resultCallb...
    method getOnResult (line 162) | public OnResultListener getOnResult() {
    method setOnResult (line 166) | public BluetoothTask setOnResult(OnResultListener onResult) {
    class OnDataResultListener (line 174) | public abstract static class OnDataResultListener implements OnResultL...
      method onResult (line 176) | @Override
      method onResult (line 181) | public abstract void onResult(boolean isTimeout, byte[] data);
    type OnResultListener (line 187) | public interface OnResultListener<T extends Packet> {
      method onResult (line 188) | void onResult(boolean isTimeout, T packet);

FILE: bluetooth/src/main/java/com/stag/bluetooth/BluetoothTransfer.java
  class BluetoothTransfer (line 17) | public final class BluetoothTransfer {
    method getInstance (line 34) | public static BluetoothTransfer getInstance(){
    method BluetoothTransfer (line 44) | private BluetoothTransfer(){
    method start (line 57) | public void start(){
    method stop (line 69) | public void stop(){
    method startSendQueue (line 99) | private void startSendQueue(){
    method startRecvHandlerQueue (line 137) | private void startRecvHandlerQueue(){
    method startTimeoutCheck (line 190) | private void startTimeoutCheck(){
    method stopSendQueue (line 232) | private void stopSendQueue(){
    method stopRecvHandlerQueue (line 239) | private void stopRecvHandlerQueue(){
    method stopTimeoutCheck (line 246) | private void stopTimeoutCheck(){
    method addSendTask (line 253) | public boolean addSendTask(BluetoothTask task){
    method addRecvData (line 267) | public void addRecvData(byte[] data){
    method isStop (line 274) | public boolean isStop(){
    method checkTimeoutTask (line 281) | private void checkTimeoutTask(){
    method getProtocol (line 304) | public Protocol getProtocol() {
    method setProtocol (line 308) | public void setProtocol(Protocol mProtocol) {
    method getSend (line 312) | public SendMethod getSend() {
    method setSend (line 316) | public void setSend(SendMethod send) {
    type SendMethod (line 320) | public interface SendMethod{
      method send (line 321) | void send(byte[] data);

FILE: bluetooth/src/main/java/com/stag/bluetooth/OnBluetoothConnectStateChangeListener.java
  type OnBluetoothConnectStateChangeListener (line 10) | public interface OnBluetoothConnectStateChangeListener {
    method onBluetoothConnect (line 16) | void onBluetoothConnect(BluetoothDevice device, boolean isSuccess);
    method onBluetoothDisconnect (line 22) | void onBluetoothDisconnect(BluetoothDevice device);

FILE: bluetooth/src/main/java/com/stag/bluetooth/OnBluetoothScanListener.java
  type OnBluetoothScanListener (line 10) | public interface OnBluetoothScanListener {
    method onBluetoothScanFindDevice (line 12) | void onBluetoothScanFindDevice(BluetoothDevice device, int rssi, boole...
    method onBluetoothScanFinish (line 14) | void onBluetoothScanFinish();

FILE: bluetooth/src/main/java/com/stag/bluetooth/OnBluetoothStateChangeListener.java
  type OnBluetoothStateChangeListener (line 8) | public interface OnBluetoothStateChangeListener {
    method onBluetoothOpen (line 10) | void onBluetoothOpen();
    method onBluetoothClose (line 12) | void onBluetoothClose();

FILE: bluetooth/src/main/java/com/stag/bluetooth/OnBluetoothTransmitListener.java
  type OnBluetoothTransmitListener (line 8) | public interface OnBluetoothTransmitListener {
    method onBluetoothSendData (line 10) | void onBluetoothSendData(byte[] data);
    method onBluetoothRecvData (line 11) | void onBluetoothRecvData(byte[] data);

FILE: bluetooth/src/main/java/com/stag/bluetooth/extend/AndroidBle.java
  class AndroidBle (line 73) | @SuppressLint("NewApi")
    method onLeScan (line 84) | @Override
    method onConnectionStateChange (line 93) | @Override
    method onServicesDiscovered (line 115) | @Override
    method onCharacteristicRead (line 127) | @Override
    method onCharacteristicChanged (line 143) | @Override
    method onCharacteristicWrite (line 153) | public void onCharacteristicWrite(BluetoothGatt gatt,
    method onDescriptorWrite (line 166) | public void onDescriptorWrite(BluetoothGatt gatt,
    method AndroidBle (line 196) | public AndroidBle(BleService service) {
    method startScan (line 215) | @Override
    method stopScan (line 220) | @Override
    method adapterEnabled (line 225) | @Override
    method connect (line 233) | @Override
    method disconnect (line 248) | @Override
    method getServices (line 259) | @Override
    method requestReadCharacteristic (line 276) | @Override
    method readCharacteristic (line 289) | public boolean readCharacteristic(String address,
    method discoverServices (line 299) | @Override
    method getService (line 313) | @Override
    method requestCharacteristicNotification (line 328) | @Override
    method characteristicNotification (line 342) | @Override
    method requestWriteCharacteristic (line 381) | @Override
    method writeCharacteristic (line 394) | @Override
    method requestConnect (line 407) | @Override
    method getBTAdapterMacAddr (line 418) | @Override
    method requestIndication (line 426) | @Override
    method requestStopNotification (line 440) | @Override

FILE: bluetooth/src/main/java/com/stag/bluetooth/extend/BleGattCharacteristic.java
  class BleGattCharacteristic (line 55) | @SuppressLint("NewApi")
    method BleGattCharacteristic (line 115) | public BleGattCharacteristic(android.bluetooth.BluetoothGattCharacteri...
    method BleGattCharacteristic (line 121) | public BleGattCharacteristic(
    method BleGattCharacteristic (line 127) | public BleGattCharacteristic(
    method initInfo (line 133) | private void initInfo() {
    method getUuid (line 137) | public UUID getUuid() {
    method getGattCharacteristicA (line 149) | protected android.bluetooth.BluetoothGattCharacteristic getGattCharact...
    method getProperties (line 153) | public int getProperties() {
    method getGattCharacteristicB (line 165) | protected com.broadcom.bt.gatt.BluetoothGattCharacteristic getGattChar...
    method setGattCharacteristicB (line 169) | protected void setGattCharacteristicB(
    method getName (line 174) | public String getName() {
    method setName (line 178) | public void setName(String name) {
    method setValue (line 182) | public boolean setValue(byte[] val) {
    method getValue (line 194) | public byte[] getValue() {
    method setValue (line 206) | public boolean setValue(int value, int formatType, int offset) {
    method setValue (line 218) | public boolean setValue(int mantissa, int exponent, int formatType,
    method setValue (line 234) | public boolean setValue(String value) {
    method getStringValue (line 238) | public String getStringValue(int offset) {
    method getFloatValue (line 250) | public Float getFloatValue(int formatType, int offset) {
    method getIntValue (line 262) | public Integer getIntValue(int formatType, int offset) {
    method byte2uint24 (line 289) | private Integer byte2uint24(int offset, byte[] value) {
    method getGattCharacteristicS (line 297) | protected com.samsung.android.sdk.bt.gatt.BluetoothGattCharacteristic ...
    method setGattCharacteristicS (line 301) | protected void setGattCharacteristicS(
    method setGattCharacteristicA (line 306) | protected void setGattCharacteristicA(

FILE: bluetooth/src/main/java/com/stag/bluetooth/extend/BleGattService.java
  class BleGattService (line 61) | @SuppressLint("NewApi")
    method BleGattService (line 70) | public BleGattService(com.samsung.android.sdk.bt.gatt.BluetoothGattSer...
    method BleGattService (line 76) | public BleGattService(com.broadcom.bt.gatt.BluetoothGattService s) {
    method BleGattService (line 82) | public BleGattService(android.bluetooth.BluetoothGattService s) {
    method initInfo (line 88) | private void initInfo() {
    method getUuid (line 92) | public UUID getUuid() {
    method getCharacteristics (line 104) | public List<BleGattCharacteristic> getCharacteristics() {
    method getCharacteristic (line 126) | public BleGattCharacteristic getCharacteristic(UUID uuid) {
    method setInfo (line 150) | public void setInfo(JSONObject info) {
    method getName (line 162) | public String getName() {
    method setName (line 166) | public void setName(String mName) {

FILE: bluetooth/src/main/java/com/stag/bluetooth/extend/BleRequest.java
  class BleRequest (line 49) | public class BleRequest {
    type RequestType (line 50) | public enum RequestType {
    type FailReason (line 54) | public enum FailReason {
    method BleRequest (line 63) | public BleRequest(RequestType type, String address) {
    method BleRequest (line 68) | public BleRequest(RequestType type, String address,
    method BleRequest (line 75) | public BleRequest(RequestType type, String address,
    method equals (line 83) | @Override

FILE: bluetooth/src/main/java/com/stag/bluetooth/extend/BleService.java
  class BleService (line 66) | public class BleService extends Service {
    type BLESDK (line 135) | public enum BLESDK {
    method run (line 153) | @Override
    method getIntentFilter (line 193) | public static IntentFilter getIntentFilter() {
    method onBind (line 210) | @Override
    class LocalBinder (line 215) | public class LocalBinder extends Binder {
      method getService (line 216) | public BleService getService() {
    method onCreate (line 221) | @Override
    method bleNotSupported (line 238) | protected void bleNotSupported() {
    method bleNoBtAdapter (line 243) | protected void bleNoBtAdapter() {
    method getBleSDK (line 248) | private BLESDK getBleSDK() {
    method getBle (line 273) | public IBle getBle() {
    method bleDeviceFound (line 286) | protected void bleDeviceFound(BluetoothDevice device, int rssi,
    method bleGattConnected (line 304) | protected void bleGattConnected(BluetoothDevice device) {
    method bleGattDisConnected (line 320) | protected void bleGattDisConnected(String address) {
    method bleServiceDiscovered (line 335) | protected void bleServiceDiscovered(String address) {
    method requestProcessed (line 342) | protected void requestProcessed(String address, RequestType requestType,
    method clearTimeoutThread (line 362) | private void clearTimeoutThread() {
    method bleCharacteristicRead (line 388) | protected void bleCharacteristicRead(String address, String uuid,
    method addBleRequest (line 399) | protected void addBleRequest(BleRequest request) {
    method processNextRequest (line 406) | private synchronized void processNextRequest() {
    method startTimeoutThread (line 462) | private void startTimeoutThread() {
    method getCurrentRequest (line 468) | protected BleRequest getCurrentRequest() {
    method setCurrentRequest (line 472) | protected void setCurrentRequest(BleRequest mCurrentRequest) {
    method bleCharacteristicNotification (line 488) | protected void bleCharacteristicNotification(String address, String uuid,
    method bleCharacteristicIndication (line 518) | protected void bleCharacteristicIndication(String address, String uuid,
    method bleCharacteristicWrite (line 541) | protected void bleCharacteristicWrite(String address, String uuid,
    method bleCharacteristicChanged (line 563) | protected void bleCharacteristicChanged(String address, String uuid,
    method bleStatusAbnormal (line 575) | protected void bleStatusAbnormal(String reason) {
    method bleRequestFailed (line 590) | protected void bleRequestFailed(String address, RequestType type,
    method getNotificationAddress (line 599) | protected String getNotificationAddress() {
    method setNotificationAddress (line 603) | protected void setNotificationAddress(String mNotificationAddress) {

FILE: bluetooth/src/main/java/com/stag/bluetooth/extend/BroadcomBle.java
  class BroadcomBle (line 66) | public class BroadcomBle implements IBle, IBleRequestHandler {
    method onAppRegistered (line 74) | @Override
    method onScanResult (line 78) | @Override
    method onConnectionStateChange (line 85) | @Override
    method onServicesDiscovered (line 102) | @Override
    method onCharacteristicRead (line 107) | @Override
    method onCharacteristicChanged (line 117) | @Override
    method onDescriptorRead (line 125) | @Override
    method onDescriptorWrite (line 163) | @Override
    method onServiceConnected (line 194) | @Override
    method onServiceDisconnected (line 200) | @Override
    method BroadcomBle (line 209) | public BroadcomBle(BleService service) {
    method startScan (line 220) | @Override
    method stopScan (line 235) | @Override
    method adapterEnabled (line 245) | @Override
    method connect (line 253) | @Override
    method disconnect (line 259) | @Override
    method getServices (line 265) | @Override
    method requestReadCharacteristic (line 277) | @Override
    method discoverServices (line 285) | @Override
    method readCharacteristic (line 290) | @Override
    method getService (line 300) | @Override
    method requestCharacteristicNotification (line 311) | @Override
    method characteristicNotification (line 320) | @Override
    method requestWriteCharacteristic (line 343) | @Override
    method writeCharacteristic (line 351) | @Override
    method requestConnect (line 358) | @Override
    method getBTAdapterMacAddr (line 367) | @Override
    method requestIndication (line 375) | @Override
    method requestStopNotification (line 383) | @Override

FILE: bluetooth/src/main/java/com/stag/bluetooth/extend/IBle.java
  type IBle (line 52) | public interface IBle {
    method getBTAdapterMacAddr (line 54) | public String getBTAdapterMacAddr();
    method startScan (line 60) | public void startScan();
    method stopScan (line 65) | public void stopScan();
    method adapterEnabled (line 72) | public boolean adapterEnabled();
    method disconnect (line 82) | public void disconnect(String address);
    method discoverServices (line 92) | public boolean discoverServices(String address);
    method getServices (line 101) | public ArrayList<BleGattService> getServices(String address);
    method getService (line 111) | public BleGattService getService(String address, UUID uuid);
    method requestConnect (line 120) | public boolean requestConnect(String address);
    method requestReadCharacteristic (line 132) | public boolean requestReadCharacteristic(String address,
    method requestCharacteristicNotification (line 147) | public boolean requestCharacteristicNotification(String address,
    method requestStopNotification (line 150) | public boolean requestStopNotification(String address,
    method requestIndication (line 165) | public boolean requestIndication(String address,
    method requestWriteCharacteristic (line 180) | public boolean requestWriteCharacteristic(String address,

FILE: bluetooth/src/main/java/com/stag/bluetooth/extend/IBleRequestHandler.java
  type IBleRequestHandler (line 49) | public interface IBleRequestHandler {
    method connect (line 51) | public boolean connect(String address);
    method readCharacteristic (line 58) | public boolean readCharacteristic(String address,
    method characteristicNotification (line 66) | public boolean characteristicNotification(String address,
    method writeCharacteristic (line 74) | public boolean writeCharacteristic(String address,

FILE: bluetooth/src/main/java/com/stag/bluetooth/extend/SamsungBle.java
  class SamsungBle (line 67) | public class SamsungBle implements IBle, IBleRequestHandler {
    method onAppRegistered (line 77) | @Override
    method onScanResult (line 81) | @Override
    method onConnectionStateChange (line 88) | @Override
    method onServicesDiscovered (line 111) | @Override
    method onCharacteristicRead (line 124) | @Override
    method onCharacteristicChanged (line 138) | @Override
    method onCharacteristicWrite (line 147) | @Override
    method onDescriptorRead (line 161) | @Override
    method onDescriptorWrite (line 199) | @Override
    method onServiceConnected (line 231) | @Override
    method onServiceDisconnected (line 237) | @Override
    method SamsungBle (line 243) | public SamsungBle(BleService service) {
    method startScan (line 254) | @Override
    method stopScan (line 269) | @Override
    method adapterEnabled (line 279) | @Override
    method connect (line 287) | @Override
    method disconnect (line 293) | @Override
    method getServices (line 299) | @Override
    method requestReadCharacteristic (line 311) | @Override
    method discoverServices (line 319) | @Override
    method readCharacteristic (line 325) | @Override
    method getService (line 332) | @Override
    method requestCharacteristicNotification (line 343) | @Override
    method characteristicNotification (line 352) | @Override
    method requestWriteCharacteristic (line 370) | @Override
    method writeCharacteristic (line 378) | @Override
    method requestConnect (line 385) | @Override
    method getBTAdapterMacAddr (line 391) | @Override
    method requestIndication (line 399) | @Override
    method requestStopNotification (line 407) | @Override

FILE: bluetooth/src/main/java/com/stag/bluetooth/helper/BleHelper.java
  class BleHelper (line 29) | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
    method getInstance (line 54) | public static BleHelper getInstance(Context context) {
    method BleHelper (line 63) | private BleHelper(Context context) {
    method startScan (line 67) | @Override
    method stopScan (line 76) | @Override
    method connect (line 84) | @Override
    method disconnect (line 105) | @Override
    method bindBleService (line 110) | private void bindBleService() {
    method startScanCount (line 134) | private void startScanCount() {
    method stopScanCount (line 155) | private void stopScanCount() {
    method startTimeoutCount (line 167) | private void startTimeoutCount() {
    method stopTimeoutCount (line 189) | private void stopTimeoutCount() {
    method send (line 197) | @Override
    method onCharacteristicChanged (line 304) | @Override
    method onCharacteristicRead (line 309) | @Override
    method onConnectionStateChange (line 314) | @Override
    method onServicesDiscovered (line 327) | @Override
    method onMtuChanged (line 417) | @Override
    method onCharacteristicWrite (line 434) | @Override
    method onDescriptorWrite (line 450) | @Override
    method isHighSpeedMode (line 461) | public boolean isHighSpeedMode(){
    method setHighConnectionPriority (line 465) | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    method setHighSpeedMode (line 472) | public boolean setHighSpeedMode(boolean flag){
    method handleConnectEvent (line 506) | private synchronized void handleConnectEvent(boolean tryConnect, boole...

FILE: bluetooth/src/main/java/com/stag/bluetooth/helper/BluetoothHelper.java
  class BluetoothHelper (line 18) | public abstract class BluetoothHelper {
    method BluetoothHelper (line 32) | protected BluetoothHelper(Context context){
    method startScan (line 37) | public abstract void startScan();
    method stopScan (line 39) | public abstract void stopScan();
    method connect (line 44) | public abstract void connect(String address);
    method disconnect (line 46) | public abstract void disconnect();
    method send (line 48) | public void send(byte[] data){
    method recv (line 56) | protected void recv(byte[] data){
    method configHandler (line 64) | protected void configHandler(){
    method sendConnectResultMessage (line 92) | protected void sendConnectResultMessage(boolean isSuccess){
    method sendDisconnectResultMessage (line 96) | protected void sendDisconnectResultMessage(){
    method connectCallback (line 104) | private void connectCallback(boolean isSuccess){
    method disconnectCallback (line 112) | private void disconnectCallback(){
    method isConnected (line 117) | public boolean isConnected() {
    method setConnected (line 121) | public void setConnected(boolean connected) {
    method isConnecting (line 125) | public boolean isConnecting() {
    method setConnecting (line 129) | public void setConnecting(boolean connecting) {
    method getConnectStateChangeListener (line 133) | public OnBluetoothConnectStateChangeListener getConnectStateChangeList...
    method setConnectStateChangeListener (line 137) | public void setConnectStateChangeListener(OnBluetoothConnectStateChang...
    method getTransmitListener (line 141) | public OnBluetoothTransmitListener getTransmitListener() {
    method setTransmitListener (line 145) | public void setTransmitListener(OnBluetoothTransmitListener transmitLi...
    method setProtocol (line 149) | public void setProtocol(Protocol protocol){

FILE: bluetooth/src/main/java/com/stag/bluetooth/helper/MyBluetoothService.java
  class MyBluetoothService (line 15) | public class MyBluetoothService {
    type MessageConstants (line 21) | private interface MessageConstants {
    class ConnectedThread (line 29) | public static class ConnectedThread extends Thread {
      method ConnectedThread (line 35) | public ConnectedThread(BluetoothSocket socket) {
      method run (line 57) | public void run() {
      method write (line 84) | public void write(byte[] bytes) {
      method cancel (line 107) | public void cancel() {

FILE: bluetooth/src/main/java/com/stag/bluetooth/helper/TraditionHelper.java
  class TraditionHelper (line 18) | public final class TraditionHelper extends BluetoothHelper {
    method getInstance (line 26) | public static TraditionHelper getInstance(Context context){
    method TraditionHelper (line 35) | private TraditionHelper(Context context){
    method startScan (line 39) | @Override
    method stopScan (line 44) | @Override
    method connect (line 49) | @Override
    method disconnect (line 96) | @Override
    method run (line 117) | @Override
    method send (line 138) | @Override

FILE: bluetooth/src/main/java/com/stag/bluetooth/helper/TraditionServerHelper.java
  class TraditionServerHelper (line 17) | public class TraditionServerHelper extends BluetoothHelper {
    method getInstance (line 23) | public static TraditionServerHelper getInstance(Context context) {
    method TraditionServerHelper (line 32) | private TraditionServerHelper(Context context) {
    method startScan (line 37) | @Override
    method stopScan (line 47) | @Override
    method connect (line 56) | @Override
    method disconnect (line 61) | @Override
    class AcceptThread (line 72) | private class AcceptThread extends Thread {
      method AcceptThread (line 75) | public AcceptThread() {
      method run (line 88) | public void run() {
      method cancel (line 122) | public void cancel() {
    class ConnectedThread (line 133) | public class ConnectedThread extends Thread {
      method ConnectedThread (line 139) | public ConnectedThread(BluetoothSocket socket) {
      method run (line 161) | public void run() {
      method write (line 186) | public void write(byte[] bytes) {
      method cancel (line 197) | public void cancel() {
    method send (line 207) | @Override

FILE: bluetooth/src/main/java/com/stag/bluetooth/packet/Packet.java
  class Packet (line 7) | public class Packet<T extends Packet>{
    method Packet (line 13) | public Packet(int cmd) {
    method Packet (line 17) | public Packet(int cmd, byte[] data) {
    method match (line 26) | public boolean match(T recvPacket){
    method getCmd (line 30) | public int getCmd() {
    method setCmd (line 34) | public void setCmd(int cmd) {
    method getData (line 38) | public byte[] getData() {
    method setData (line 42) | public void setData(byte[] data) {

FILE: bluetooth/src/main/java/com/stag/bluetooth/protocol/OnEventListener.java
  type OnEventListener (line 7) | public interface OnEventListener {

FILE: bluetooth/src/main/java/com/stag/bluetooth/protocol/ParseResult.java
  class ParseResult (line 11) | public final class ParseResult {
    method ParseResult (line 19) | public ParseResult(){
    method ParseResult (line 23) | public ParseResult(ResultType type, Packet packet, BluetoothDispatch.C...
    method getType (line 29) | public ResultType getType() {
    method setType (line 33) | public void setType(ResultType type) {
    method getPacket (line 37) | public Packet getPacket() {
    method setPacket (line 41) | public void setPacket(Packet packet) {
    method getCallback (line 45) | public BluetoothDispatch.Callback getCallback() {
    method setCallback (line 49) | public void setCallback(BluetoothDispatch.Callback callback) {

FILE: bluetooth/src/main/java/com/stag/bluetooth/protocol/Protocol.java
  class Protocol (line 13) | public abstract class Protocol<E extends Packet, T extends OnEventListen...
    method Protocol (line 26) | protected Protocol(Context context) {
    method Protocol (line 33) | protected Protocol(Context context, T listener) {
    method initialize (line 41) | public void initialize(){
    method destroy (line 48) | public void destroy(){
    method packetToBytes (line 56) | public abstract byte[] packetToBytes(E packet);
    method parse (line 61) | public abstract ParseResult parse(byte[] data);
    method getType (line 66) | public abstract int getType();
    method haveSetEventListener (line 71) | protected boolean haveSetEventListener(){
    method getServiceUUID (line 75) | public UUID getServiceUUID() {
    method getSendTunnelUUID (line 79) | public UUID getSendTunnelUUID() {
    method getRecvTunnelUUID (line 83) | public UUID getRecvTunnelUUID() {
    method getDescriptorUUID (line 87) | public UUID getDescriptorUUID() {
    method setMaxBleSendInterval (line 94) | public void setMaxBleSendInterval(int interval) {
    method getMaxBleSendInterval (line 101) | public int getMaxBleSendInterval() {
    method getEventListener (line 105) | public T getEventListener() {
    method setEventListener (line 109) | public void setEventListener(T eventListener) {
    method getData (line 113) | public Object getData() {
    method setData (line 117) | public void setData(Object data) {

FILE: bluetooth/src/main/java/com/stag/bluetooth/protocol/ResultType.java
  type ResultType (line 7) | public enum ResultType {

FILE: bluetooth/src/main/java/com/stag/bluetooth/util/ByteUtils.java
  class ByteUtils (line 11) | public final class ByteUtils {
    method compareBytes (line 20) | public static boolean compareBytes(byte[] first, byte[] second) {
    method longToByte4BigEndian (line 36) | public static byte[] longToByte4BigEndian(long l) {
    method byte4ToLongBigEndian (line 51) | public static long byte4ToLongBigEndian(byte[] b) {
    method byte16ToUuidBigEndian (line 65) | public static UUID byte16ToUuidBigEndian(byte[] b) {
    method uuidToByte16BigEndian (line 75) | public static byte[] uuidToByte16BigEndian(UUID uuid) {
    method byte8ToUuidBigEndian (line 87) | public static UUID byte8ToUuidBigEndian(byte[] b) {
    method uuidToByte8BigEndian (line 97) | public static byte[] uuidToByte8BigEndian(UUID uuid) {
    method byte8ToLongBigEndian (line 108) | public static long byte8ToLongBigEndian(byte[] b) {
    method longToByte8BigEndian (line 126) | public static byte[] longToByte8BigEndian(long l) {
    method byte4ToIntBigEndian (line 144) | public static int byte4ToIntBigEndian(byte[] b) {
    method intToByte4BigEndian (line 158) | public static byte[] intToByte4BigEndian(int i) {
    method byte3ToIntBigEndian (line 173) | public static int byte3ToIntBigEndian(byte[] b) {
    method intToByte3BigEndian (line 186) | public static byte[] intToByte3BigEndian(int i) {
    method toString (line 194) | public static String toString(byte[] data) {
    method subBytes (line 210) | public static byte[] subBytes(byte[] data, int start, int len) {
    method subBytes (line 218) | public static byte[] subBytes(byte[] data, int start) {
    method bytesToLong (line 229) | public static long bytesToLong(byte[] b) {
    method longToBytes (line 248) | public static byte[] longToBytes(long l) {
    method combineByteArray (line 267) | public static byte[] combineByteArray(byte[]... bytes) {
    method uuidToBytes (line 292) | public static byte[] uuidToBytes(UUID uuid) {
    method bytesToUuid (line 302) | public static UUID bytesToUuid(byte[] data) {
    method intToBytes2 (line 316) | public static byte[] intToBytes2(int i) {
    method intToBytes2SmallDian (line 323) | public static byte[] intToBytes2SmallDian(int i) {
    method bytesToIntBigEndian (line 336) | public static int bytesToIntBigEndian(byte[] b) {
    method bytesToIntSmallEndian (line 350) | public static int bytesToIntSmallEndian(byte[] b) {
    method intToBytesBigEndian (line 364) | public static byte[] intToBytesBigEndian(int i) {
    method bytesToInt (line 379) | public static int bytesToInt(byte[] b) {
    method intToBytes (line 393) | public static byte[] intToBytes(int i) {
    method bytesToShort (line 408) | public static short bytesToShort(byte[] b) {
    method shortToBytes (line 420) | public static byte[] shortToBytes(short i) {
    method bytesToShortBigEndian (line 434) | public static short bytesToShortBigEndian(byte[] b) {
    method shortToBytesBigEndian (line 447) | public static byte[] shortToBytesBigEndian(short i) {
    method wrapData (line 461) | public static byte[] wrapData(byte[] data, int len) {
    method getByteBits (line 479) | public static byte[] getByteBits(byte data) {
    method getBytesWithBuffer (line 487) | public static byte[] getBytesWithBuffer(ByteBuffer buffer) {
    method getAsciiString (line 501) | public static String getAsciiString(byte[] bytes) {
    method bytesToHexString (line 513) | public static String bytesToHexString(byte[] src){
    method byteToList (line 536) | public static List<Byte> byteToList(byte[] data) {

FILE: bluetooth/src/main/java/com/stag/bluetooth/util/LogUtils.java
  class LogUtils (line 8) | public class LogUtils {
    method LogUtils (line 12) | private LogUtils() {
    method v (line 15) | public static void v(String tag, String msg) {
    method d (line 21) | public static void d(String tag, String msg) {
    method i (line 37) | public static void i(String tag, String msg) {
    method w (line 43) | public static void w(String tag, String msg) {
    method e (line 49) | public static void e(String tag, String msg) {

FILE: bluetooth/src/main/java/com/stag/bluetooth/util/Logs.java
  class Logs (line 9) | public class Logs {
    method d (line 13) | public static void d(String tag, String msg){
    method e (line 18) | public static void e(String tag, String msg){

FILE: bluetooth/src/test/java/com/stag/bluetooth/ExampleUnitTest.java
  class ExampleUnitTest (line 8) | public class ExampleUnitTest {
    method addition_isCorrect (line 9) | @Test
Condensed preview — 123 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (487K chars).
[
  {
    "path": ".gitignore",
    "chars": 208,
    "preview": "*.iml\n.gradle\n/local.properties\n/.idea/caches\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n/.idea/navEditor."
  },
  {
    "path": ".idea/codeStyles/Project.xml",
    "chars": 3309,
    "preview": "<component name=\"ProjectCodeStyleConfiguration\">\n  <code_scheme name=\"Project\" version=\"173\">\n    <codeStyleSettings lan"
  },
  {
    "path": ".idea/compiler.xml",
    "chars": 288,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"CompilerConfiguration\">\n    <annotationP"
  },
  {
    "path": ".idea/gradle.xml",
    "chars": 801,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"GradleMigrationSettings\" migrationVersio"
  },
  {
    "path": ".idea/jarRepositories.xml",
    "chars": 1052,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"RemoteRepositoriesConfiguration\">\n    <r"
  },
  {
    "path": ".idea/misc.xml",
    "chars": 372,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectRootManager\" version=\"2\" language"
  },
  {
    "path": ".idea/vcs.xml",
    "chars": 180,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"VcsDirectoryMappings\">\n    <mapping dire"
  },
  {
    "path": "README.md",
    "chars": 5148,
    "preview": "<img src=\"https://github.com/LuoPeiQin/Bluetooth/blob/master/app/src/main/res/mipmap-xhdpi/logo.png\" width=\"20%\">\n\n# Blu"
  },
  {
    "path": "app/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "chars": 2264,
    "preview": "apply plugin: 'com.android.application'\napply plugin: 'bugly'\n\nbugly {\n    appId = '4efc7ff5d2' // 注册时分配的App ID\n    appK"
  },
  {
    "path": "app/proguard-rules.pro",
    "chars": 3633,
    "preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
  },
  {
    "path": "app/src/androidTest/java/com/luo/bluetooth/ExampleInstrumentedTest.java",
    "chars": 750,
    "preview": "package com.luo.bluetooth;\n\nimport android.content.Context;\n\nimport androidx.test.platform.app.InstrumentationRegistry;\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "chars": 2289,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:to"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/MainActivity.java",
    "chars": 8726,
    "preview": "package com.luo.bluetooth;\n\nimport android.bluetooth.BluetoothAdapter;\nimport android.bluetooth.BluetoothDevice;\nimport "
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/MyApplication.java",
    "chars": 343,
    "preview": "package com.luo.bluetooth;\n\nimport android.app.Application;\n\nimport com.tencent.bugly.Bugly;\n\npublic class MyApplication"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/base/BaseActivity.java",
    "chars": 1051,
    "preview": "package com.luo.bluetooth.base;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/common/Constants.java",
    "chars": 244,
    "preview": "package com.luo.bluetooth.common;\n\npublic class Constants {\n\n    /**\n     * 蓝牙相关\n     */\n    //蓝牙连接状态\n    public static "
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/BluetoothDeviceAdapter.java",
    "chars": 2674,
    "preview": "package com.luo.bluetooth.customview.searchble;\n\nimport android.content.Context;\nimport android.graphics.Color;\nimport a"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/BluetoothDeviceBean.java",
    "chars": 390,
    "preview": "package com.luo.bluetooth.customview.searchble;\n\nimport java.io.Serializable;\n\nimport lombok.Data;\n\n/**\n * Created by Ad"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/ColorUtils.java",
    "chars": 681,
    "preview": "package com.luo.bluetooth.customview.searchble;\n\nimport android.graphics.ColorFilter;\nimport android.graphics.ColorMatri"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/DeviceListActivity.java",
    "chars": 11007,
    "preview": "package com.luo.bluetooth.customview.searchble;\n\nimport android.Manifest;\nimport android.bluetooth.BluetoothDevice;\nimpo"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/Effectstype.java",
    "chars": 2750,
    "preview": "package com.luo.bluetooth.customview.searchble;\n\n\nimport com.luo.bluetooth.customview.searchble.effects.BaseEffects;\nimp"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/NiftyDialogBuilder.java",
    "chars": 10425,
    "preview": "package com.luo.bluetooth.customview.searchble;\n\nimport android.app.Dialog;\nimport android.content.Context;\nimport andro"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/SignalView.java",
    "chars": 2960,
    "preview": "package com.luo.bluetooth.customview.searchble;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\n"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/effects/BaseEffects.java",
    "chars": 2363,
    "preview": "package com.luo.bluetooth.customview.searchble.effects;\n\nimport android.animation.AnimatorSet;\nimport android.os.Build;\n"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/effects/FadeIn.java",
    "chars": 1010,
    "preview": "package com.luo.bluetooth.customview.searchble.effects;\n\nimport android.animation.ObjectAnimator;\nimport android.view.Vi"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/effects/Fall.java",
    "chars": 1190,
    "preview": "package com.luo.bluetooth.customview.searchble.effects;\n\nimport android.animation.ObjectAnimator;\nimport android.view.Vi"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/effects/FlipH.java",
    "chars": 1017,
    "preview": "package com.luo.bluetooth.customview.searchble.effects;\n\nimport android.animation.ObjectAnimator;\nimport android.view.Vi"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/effects/FlipV.java",
    "chars": 1016,
    "preview": "package com.luo.bluetooth.customview.searchble.effects;\n\nimport android.animation.ObjectAnimator;\nimport android.view.Vi"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/effects/NewsPaper.java",
    "chars": 1301,
    "preview": "package com.luo.bluetooth.customview.searchble.effects;\n\nimport android.animation.ObjectAnimator;\nimport android.view.Vi"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/effects/RotateBottom.java",
    "chars": 1202,
    "preview": "package com.luo.bluetooth.customview.searchble.effects;\n\nimport android.animation.ObjectAnimator;\nimport android.view.Vi"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/effects/RotateLeft.java",
    "chars": 1201,
    "preview": "package com.luo.bluetooth.customview.searchble.effects;\n\nimport android.animation.ObjectAnimator;\nimport android.view.Vi"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/effects/Shake.java",
    "chars": 1197,
    "preview": "package com.luo.bluetooth.customview.searchble.effects;\n\nimport android.animation.ObjectAnimator;\nimport android.os.Buil"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/effects/SideFall.java",
    "chars": 1371,
    "preview": "package com.luo.bluetooth.customview.searchble.effects;\n\nimport android.animation.ObjectAnimator;\nimport android.view.Vi"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/effects/SlideBottom.java",
    "chars": 1233,
    "preview": "package com.luo.bluetooth.customview.searchble.effects;\n\nimport android.animation.ObjectAnimator;\nimport android.os.Buil"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/effects/SlideLeft.java",
    "chars": 1111,
    "preview": "package com.luo.bluetooth.customview.searchble.effects;\n\nimport android.animation.ObjectAnimator;\nimport android.view.Vi"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/effects/SlideRight.java",
    "chars": 1111,
    "preview": "package com.luo.bluetooth.customview.searchble.effects;\n\nimport android.animation.ObjectAnimator;\nimport android.view.Vi"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/effects/SlideTop.java",
    "chars": 1110,
    "preview": "package com.luo.bluetooth.customview.searchble.effects;\n\nimport android.animation.ObjectAnimator;\nimport android.view.Vi"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/customview/searchble/effects/Slit.java",
    "chars": 1325,
    "preview": "package com.luo.bluetooth.customview.searchble.effects;\n\nimport android.animation.ObjectAnimator;\nimport android.view.Vi"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/encryption/Aes.java",
    "chars": 28265,
    "preview": "/*\n * Copyright (c) 2019. stag All rights reserved.\n */\n\npackage com.luo.bluetooth.encryption;\n\n\nimport com.stag.bluetoo"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/encryption/CRC.java",
    "chars": 4238,
    "preview": "package com.luo.bluetooth.encryption;\n\npublic class CRC {\n    static byte[] crc8_tab = { (byte) 0, (byte) 94, (byte) 188"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/protocol/CRC16Utils.java",
    "chars": 8790,
    "preview": "/**\n * Copyright (C), 2007-2021, 未来穿戴有限公司\n * FileName: CRC16Utils\n * Author: Antier\n * Date: 2021/7/16 11:46\n * Descript"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/protocol/CrcUtils.java",
    "chars": 3196,
    "preview": "/**\n * Copyright (C), 2007-2022, 未来穿戴有限公司\n * FileName: CrcUtils\n * Author: lpq\n * Date: 2022/3/11 17:23\n * Description: "
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/protocol/CustomEventListener.java",
    "chars": 185,
    "preview": "package com.luo.bluetooth.protocol;\n\nimport com.stag.bluetooth.protocol.OnEventListener;\n\n/**\n * 一些由设备端主动发起的蓝牙事件的监听\n */\n"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/protocol/CustomPacket.java",
    "chars": 736,
    "preview": "package com.luo.bluetooth.protocol;\n\nimport com.stag.bluetooth.packet.Packet;\n\npublic class CustomPacket extends Packet "
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/protocol/CustomProtocol.java",
    "chars": 9252,
    "preview": "package com.luo.bluetooth.protocol;\n\n\nimport android.content.Context;\nimport android.util.Log;\n\nimport com.luo.bluetooth"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/protocol/OnTimeoutResult.java",
    "chars": 201,
    "preview": "/*\n * Copyright (c) 2019. stag All rights reserved.\n */\n\npackage com.luo.bluetooth.protocol;\n\n/**\n * 蓝牙任务回调\n */\npublic i"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/protocol/WeiCeCode.java",
    "chars": 730,
    "preview": "/**\n * Copyright (C), 2007-2022, 未来穿戴有限公司\n * FileName: WeiCeCode\n * Author: lpq\n * Date: 2022/3/11 16:27\n * Description:"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/protocol/WeiCeDeviceOperate.java",
    "chars": 16751,
    "preview": "\n\n/*\n * Copyright (c) 2019. stag All rights reserved.\n */\n\npackage com.luo.bluetooth.protocol;\n\nimport android.util.Log;"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/utils/ByteUtils.java",
    "chars": 21509,
    "preview": "package com.luo.bluetooth.utils;\n\nimport java.nio.ByteBuffer;\nimport java.nio.charset.StandardCharsets;\nimport java.util"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/utils/DateUtils.java",
    "chars": 9433,
    "preview": "package com.luo.bluetooth.utils;\n\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.C"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/utils/DialogUtils.java",
    "chars": 20184,
    "preview": "package com.luo.bluetooth.utils;\n\nimport android.app.Dialog;\nimport android.content.Context;\nimport android.content.Cont"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/utils/GpsUtils.java",
    "chars": 742,
    "preview": "package com.luo.bluetooth.utils;\n\nimport android.content.Context;\nimport android.location.LocationManager;\n\npublic class"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/utils/GsonUtils.java",
    "chars": 1682,
    "preview": "package com.luo.bluetooth.utils;\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gso"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/utils/LogUtils.java",
    "chars": 1409,
    "preview": "package com.luo.bluetooth.utils;\n\nimport android.util.Log;\n\nimport com.tencent.bugly.crashreport.BuglyLog;\nimport com.lu"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/utils/TextUtils.java",
    "chars": 237,
    "preview": "package com.luo.bluetooth.utils;\n\npublic class TextUtils {\n\n\tpublic static boolean isEmpty(String dateStr) {\n\t\t// TODO A"
  },
  {
    "path": "app/src/main/java/com/luo/bluetooth/utils/ToastUtil.java",
    "chars": 8088,
    "preview": "package com.luo.bluetooth.utils;\n\nimport android.content.Context;\nimport android.view.View;\nimport android.widget.ImageV"
  },
  {
    "path": "app/src/main/res/anim/fade_in.xml",
    "chars": 254,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<alpha xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:int"
  },
  {
    "path": "app/src/main/res/anim/fade_out.xml",
    "chars": 253,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<alpha xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:int"
  },
  {
    "path": "app/src/main/res/drawable/btn_press.xml",
    "chars": 207,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <corner"
  },
  {
    "path": "app/src/main/res/drawable/btn_selector.xml",
    "chars": 339,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item "
  },
  {
    "path": "app/src/main/res/drawable/btn_unpress.xml",
    "chars": 209,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <corner"
  },
  {
    "path": "app/src/main/res/drawable/dialog_bg.xml",
    "chars": 194,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n\t<corners an"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_background.xml",
    "chars": 5606,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:wi"
  },
  {
    "path": "app/src/main/res/drawable/sel_white_gray.xml",
    "chars": 242,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item a"
  },
  {
    "path": "app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "chars": 1702,
    "preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    "
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "chars": 3732,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:"
  },
  {
    "path": "app/src/main/res/layout/activity_search_device_list.xml",
    "chars": 4999,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmln"
  },
  {
    "path": "app/src/main/res/layout/dialog_layout.xml",
    "chars": 4872,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n/*\n** Copyright 2010, The Android Open Source Project\n**\n** Licensed under th"
  },
  {
    "path": "app/src/main/res/layout/item_bluetooth_device_list.xml",
    "chars": 1258,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    andr"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "chars": 272,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <b"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "chars": 272,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <b"
  },
  {
    "path": "app/src/main/res/values/attrs.xml",
    "chars": 240,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <declare-styleable name=\"SignalView\">\n        <attr name=\"noInten"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "chars": 3004,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <!--主色调-->\n    <color name=\"colorPrimaryLight\">#B3E5FC</color>\n "
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "chars": 626,
    "preview": "<resources>\n    <string name=\"app_name\">蓝牙示例程序</string>\n\n    <!--蓝牙开锁界面提示信息-->\n    <string name=\"title_device_list_searc"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "chars": 2235,
    "preview": "<resources>\n\n    <style name=\"DialogTheme.TransparentNoTitle\" parent=\"Theme.AppCompat.Dialog\">\n        <item name=\"andro"
  },
  {
    "path": "app/src/test/java/com/luo/bluetooth/ExampleUnitTest.java",
    "chars": 378,
    "preview": "package com.luo.bluetooth;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, w"
  },
  {
    "path": "bluetooth/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "bluetooth/build.gradle",
    "chars": 997,
    "preview": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion '27.0.3'\n\n    defaultConfi"
  },
  {
    "path": "bluetooth/proguard-rules.pro",
    "chars": 645,
    "preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:"
  },
  {
    "path": "bluetooth/src/androidTest/java/com/stag/bluetooth/ExampleInstrumentedTest.java",
    "chars": 745,
    "preview": "package com.stag.bluetooth;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport"
  },
  {
    "path": "bluetooth/src/main/AndroidManifest.xml",
    "chars": 481,
    "preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" package=\"com.stag.bluetooth\">\n\n    <uses-permission"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/BluetoothController.java",
    "chars": 13185,
    "preview": "package com.stag.bluetooth;\n\nimport android.bluetooth.BluetoothAdapter;\nimport android.bluetooth.BluetoothDevice;\nimport"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/BluetoothDispatch.java",
    "chars": 1817,
    "preview": "package com.stag.bluetooth;\n\nimport android.os.Handler;\nimport android.os.Looper;\n\nimport java.util.concurrent.ExecutorS"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/BluetoothTask.java",
    "chars": 5406,
    "preview": "package com.stag.bluetooth;\n\nimport com.stag.bluetooth.packet.Packet;\n\n/**\n * 蓝牙发送任务\n * Created by Bruce on 2016/11/15.\n"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/BluetoothTransfer.java",
    "chars": 11131,
    "preview": "package com.stag.bluetooth;\n\nimport com.stag.bluetooth.protocol.ParseResult;\nimport com.stag.bluetooth.protocol.Protocol"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/OnBluetoothConnectStateChangeListener.java",
    "chars": 471,
    "preview": "package com.stag.bluetooth;\n\nimport android.bluetooth.BluetoothDevice;\n\n/**\n * 连接状态监听\n * Created by Administrator on 201"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/OnBluetoothScanListener.java",
    "chars": 300,
    "preview": "package com.stag.bluetooth;\n\nimport android.bluetooth.BluetoothDevice;\n\n/**\n * 蓝牙扫描监听\n * Created by Administrator on 201"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/OnBluetoothStateChangeListener.java",
    "chars": 234,
    "preview": "package com.stag.bluetooth;\n\n/**\n * 监听手机蓝牙状态\n * Created by Administrator on 2016/11/18.\n */\n\npublic interface OnBluetoot"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/OnBluetoothTransmitListener.java",
    "chars": 229,
    "preview": "package com.stag.bluetooth;\n\n/**\n * 蓝牙数据收发监听\n * Created by Administrator on 2016/12/21.\n */\n\npublic interface OnBluetoot"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/extend/AndroidBle.java",
    "chars": 15079,
    "preview": "/**\n * This XPG software is supplied to you by Xtreme Programming Group, Inc.\n * (\"XPG\") in consideration of your agreem"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/extend/BleGattCharacteristic.java",
    "chars": 10208,
    "preview": "/**\n * This XPG software is supplied to you by Xtreme Programming Group, Inc.\n * (\"XPG\") in consideration of your agreem"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/extend/BleGattService.java",
    "chars": 6066,
    "preview": "/**\n * This XPG software is supplied to you by Xtreme Programming Group, Inc.\n * (\"XPG\") in consideration of your agreem"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/extend/BleRequest.java",
    "chars": 4107,
    "preview": "/**\n * This XPG software is supplied to you by Xtreme Programming Group, Inc.\n * (\"XPG\") in consideration of your agreem"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/extend/BleService.java",
    "chars": 20596,
    "preview": "/**\n * This XPG software is supplied to you by Xtreme Programming Group, Inc.\n * (\"XPG\") in consideration of your agreem"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/extend/BroadcomBle.java",
    "chars": 12813,
    "preview": "/**\n * This XPG software is supplied to you by Xtreme Programming Group, Inc.\n * (\"XPG\") in consideration of your agreem"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/extend/IBle.java",
    "chars": 6793,
    "preview": "/**\n * This XPG software is supplied to you by Xtreme Programming Group, Inc.\n * (\"XPG\") in consideration of your agreem"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/extend/IBleRequestHandler.java",
    "chars": 3518,
    "preview": "/**\n * This XPG software is supplied to you by Xtreme Programming Group, Inc.\n * (\"XPG\") in consideration of your agreem"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/extend/SamsungBle.java",
    "chars": 13697,
    "preview": "/**\n * This XPG software is supplied to you by Xtreme Programming Group, Inc.\n * (\"XPG\") in consideration of your agreem"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/helper/BleHelper.java",
    "chars": 20380,
    "preview": "package com.stag.bluetooth.helper;\n\nimport android.annotation.TargetApi;\nimport android.bluetooth.BluetoothGatt;\nimport "
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/helper/BluetoothHelper.java",
    "chars": 4511,
    "preview": "package com.stag.bluetooth.helper;\n\nimport android.bluetooth.BluetoothAdapter;\nimport android.bluetooth.BluetoothDevice;"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/helper/MyBluetoothService.java",
    "chars": 4350,
    "preview": "package com.stag.bluetooth.helper;\n\nimport android.bluetooth.BluetoothSocket;\nimport android.os.Bundle;\nimport android.o"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/helper/TraditionHelper.java",
    "chars": 4745,
    "preview": "package com.stag.bluetooth.helper;\n\nimport android.bluetooth.BluetoothSocket;\nimport android.content.Context;\n\nimport co"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/helper/TraditionServerHelper.java",
    "chars": 7444,
    "preview": "package com.stag.bluetooth.helper;\n\nimport android.bluetooth.BluetoothAdapter;\nimport android.bluetooth.BluetoothServerS"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/packet/Packet.java",
    "chars": 845,
    "preview": "package com.stag.bluetooth.packet;\n\n/**\n * Created by Administrator on 2016/11/14.\n */\n\npublic class Packet<T extends Pa"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/protocol/OnEventListener.java",
    "chars": 153,
    "preview": "package com.stag.bluetooth.protocol;\n\n/**\n * 监听蓝牙设备的主动上传事件,不同协议各不相同\n * Created by Administrator on 2016/11/15.\n */\npubli"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/protocol/ParseResult.java",
    "chars": 1052,
    "preview": "package com.stag.bluetooth.protocol;\n\nimport com.stag.bluetooth.BluetoothDispatch;\nimport com.stag.bluetooth.packet.Pack"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/protocol/Protocol.java",
    "chars": 2378,
    "preview": "package com.stag.bluetooth.protocol;\n\nimport android.content.Context;\n\nimport com.stag.bluetooth.packet.Packet;\n\nimport "
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/protocol/ResultType.java",
    "chars": 187,
    "preview": "package com.stag.bluetooth.protocol;\n\n/**\n * Created by Administrator on 2016/11/28.\n */\n\npublic enum ResultType {\n    R"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/util/ByteUtils.java",
    "chars": 13100,
    "preview": "package com.stag.bluetooth.util;\n\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.List;\nimport "
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/util/LogUtils.java",
    "chars": 1201,
    "preview": "package com.stag.bluetooth.util;\n\nimport android.util.Log;\n\nimport com.stag.bluetooth.BuildConfig;\n\n\npublic class LogUti"
  },
  {
    "path": "bluetooth/src/main/java/com/stag/bluetooth/util/Logs.java",
    "chars": 391,
    "preview": "package com.stag.bluetooth.util;\n\nimport android.util.Log;\n\n/**\n * Created by Administrator on 2017/6/21.\n */\n\npublic cl"
  },
  {
    "path": "bluetooth/src/main/res/values/strings.xml",
    "chars": 72,
    "preview": "<resources>\n    <string name=\"app_name\">Bluetooth</string>\n</resources>\n"
  },
  {
    "path": "bluetooth/src/test/java/com/stag/bluetooth/ExampleUnitTest.java",
    "chars": 337,
    "preview": "package com.stag.bluetooth;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n *"
  },
  {
    "path": "build.gradle",
    "chars": 627,
    "preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    \n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 232,
    "preview": "#Sat Apr 18 17:08:04 CST 2020\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
  },
  {
    "path": "gradle.properties",
    "chars": 1073,
    "preview": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will ov"
  },
  {
    "path": "gradlew",
    "chars": 5296,
    "preview": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up"
  },
  {
    "path": "gradlew.bat",
    "chars": 2176,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
  },
  {
    "path": "settings.gradle",
    "chars": 58,
    "preview": "rootProject.name='Bluetooth'\ninclude ':app', ':bluetooth'\n"
  }
]

// ... and 3 more files (download for full content)

About this extraction

This page contains the full source code of the LuoPeiQin/Bluetooth GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 123 files (435.5 KB), approximately 120.6k tokens, and a symbol index with 805 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!