Browse Source

First submission

master
陈福行 5 years ago
commit
5402adfc80
75 changed files with 3594 additions and 0 deletions
  1. 13
    0
      .gitignore
  2. 224
    0
      .idea/codeStyles/Project.xml
  3. 5
    0
      .idea/codeStyles/codeStyleConfig.xml
  4. 6
    0
      .idea/compiler.xml
  5. 3
    0
      .idea/dictionaries/xing.xml
  6. 6
    0
      .idea/encodings.xml
  7. 19
    0
      .idea/gradle.xml
  8. 14
    0
      .idea/misc.xml
  9. 12
    0
      .idea/runConfigurations.xml
  10. 6
    0
      .idea/vcs.xml
  11. 290
    0
      README.md
  12. 290
    0
      README_CN.md
  13. 1
    0
      app/.gitignore
  14. 37
    0
      app/build.gradle
  15. 21
    0
      app/proguard-rules.pro
  16. 27
    0
      app/src/androidTest/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/ExampleInstrumentedTest.java
  17. 32
    0
      app/src/main/AndroidManifest.xml
  18. 689
    0
      app/src/main/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/MainActivity.java
  19. 54
    0
      app/src/main/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/WelcomeActivity.java
  20. 116
    0
      app/src/main/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/base/BaseActivity.java
  21. 56
    0
      app/src/main/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/utils/AppUtils.java
  22. 8
    0
      app/src/main/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/utils/Config.java
  23. 126
    0
      app/src/main/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/utils/SPUtils.java
  24. 80
    0
      app/src/main/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/utils/T.java
  25. 104
    0
      app/src/main/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/view/SetRssiDialog.java
  26. 34
    0
      app/src/main/res/drawable-v24/ic_launcher_foreground.xml
  27. 5
    0
      app/src/main/res/drawable/activity_title_right.xml
  28. 171
    0
      app/src/main/res/drawable/ic_launcher_background.xml
  29. 7
    0
      app/src/main/res/drawable/main_divider.xml
  30. 13
    0
      app/src/main/res/drawable/warning_cancel_btn_bg.xml
  31. 13
    0
      app/src/main/res/drawable/warning_query_btn_bg.xml
  32. 33
    0
      app/src/main/res/layout/activity_title.xml
  33. 23
    0
      app/src/main/res/layout/activity_welcome.xml
  34. 57
    0
      app/src/main/res/layout/dialog_set_rssi.xml
  35. 5
    0
      app/src/main/res/layout/divider_horizontal.xml
  36. 354
    0
      app/src/main/res/layout/main.xml
  37. 5
    0
      app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  38. 5
    0
      app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  39. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher.png
  40. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher_round.png
  41. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher.png
  42. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher_round.png
  43. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher.png
  44. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
  45. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  46. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
  47. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  48. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
  49. 45
    0
      app/src/main/res/values-zh/strings.xml
  50. 10
    0
      app/src/main/res/values/arrays.xml
  51. 17
    0
      app/src/main/res/values/colors.xml
  52. 10
    0
      app/src/main/res/values/dimens.xml
  53. 45
    0
      app/src/main/res/values/strings.xml
  54. 59
    0
      app/src/main/res/values/styles.xml
  55. 17
    0
      app/src/test/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/ExampleUnitTest.java
  56. 27
    0
      build.gradle
  57. 20
    0
      gradle.properties
  58. BIN
      gradle/wrapper/gradle-wrapper.jar
  59. 6
    0
      gradle/wrapper/gradle-wrapper.properties
  60. 172
    0
      gradlew
  61. 84
    0
      gradlew.bat
  62. 1
    0
      pabulumlibrary/.gitignore
  63. 46
    0
      pabulumlibrary/build.gradle
  64. BIN
      pabulumlibrary/libs/AicareUtils.jar
  65. BIN
      pabulumlibrary/libs/PabulumLibrary.jar
  66. BIN
      pabulumlibrary/libs/arm64-v8a/libaicare-lib.so
  67. BIN
      pabulumlibrary/libs/armeabi-v7a/libaicare-lib.so
  68. BIN
      pabulumlibrary/libs/x86/libaicare-lib.so
  69. BIN
      pabulumlibrary/libs/x86_64/libaicare-lib.so
  70. 21
    0
      pabulumlibrary/proguard-rules.pro
  71. 27
    0
      pabulumlibrary/src/androidTest/java/aicare/net/cn/sdk/pabulumlibrary/ExampleInstrumentedTest.java
  72. 2
    0
      pabulumlibrary/src/main/AndroidManifest.xml
  73. 3
    0
      pabulumlibrary/src/main/res/values/strings.xml
  74. 17
    0
      pabulumlibrary/src/test/java/aicare/net/cn/sdk/pabulumlibrary/ExampleUnitTest.java
  75. 1
    0
      settings.gradle

+ 13
- 0
.gitignore View File

@@ -0,0 +1,13 @@
*.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

+ 224
- 0
.idea/codeStyles/Project.xml View File

@@ -0,0 +1,224 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
</value>
</option>
<option name="RIGHT_MARGIN" value="100" />
<AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" />
</AndroidXmlCodeStyleSettings>
<JavaCodeStyleSettings>
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
</value>
</option>
</JavaCodeStyleSettings>
<XML>
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_NAMESPACE>Namespace:</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_NAMESPACE>Namespace:</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</code_scheme>
</component>

+ 5
- 0
.idea/codeStyles/codeStyleConfig.xml View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default (1)" />
</state>
</component>

+ 6
- 0
.idea/compiler.xml View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="9" />
</component>
</project>

+ 3
- 0
.idea/dictionaries/xing.xml View File

@@ -0,0 +1,3 @@
<component name="ProjectDictionaryState">
<dictionary name="xing" />
</component>

+ 6
- 0
.idea/encodings.xml View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8" addBOMForNewFiles="with NO BOM">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>

+ 19
- 0
.idea/gradle.xml View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<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$/pabulumlibrary" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>

+ 14
- 0
.idea/misc.xml View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeSettings">
<configurations>
<configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" />
</configurations>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" 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>

+ 12
- 0
.idea/runConfigurations.xml View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

+ 6
- 0
.idea/vcs.xml View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

+ 290
- 0
README.md View File

@@ -0,0 +1,290 @@
# Pabulum SDK Instructions - Android

[![](https://jitpack.io/v/elinkthings/PabulumSDKRepositoryAndroid.svg)](https://jitpack.io/#elinkthings/PabulumSDKRepositoryAndroid)

[aar package download link](https://github.com/elinkthings/PabulumSDKRepositoryAndroid/releases)

[中文文档](README_CN.md)

This document is to guide Android developers to integrate Pabulum-SDK-Android in Android 4.4 and above systems, mainly for some key use examples

## 1. Import SDK


```
repositories {
    flatDir {
        dirs 'libs'
    }
}


Step 1. Add the JitPack repository to your build file
Add it to the root build.gradle at the end of the repository:
allprojects {
repositories {
...
maven {url 'https://jitpack.io'}
}
}

Step 2. Add dependencies
dependencies {
implementation 'com.github.elinkthings:PabulumSDKRepositoryAndroid:1.2.6'
}





You can also use the aar package dependency, please download it yourself and put it in the project's libs



```

## 2, permission settings

```
<!-In most cases, you need to ensure that the device supports BLE .-->
<uses-feature
    android: name = "android.hardware.bluetooth_le"
    android: required = "true" />

<uses-permission android: name = "android.permission.BLUETOOTH" />
<uses-permission android: name = "android.permission.BLUETOOTH_ADMIN" />

<!-Android 6.0 and above. Bluetooth scanning requires one of the following two permissions. You need to apply at run time .-->
<uses-permission android: name = "android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android: name = "android.permission.ACCESS_FINE_LOCATION" />

<!-Optional. If your app need dfu function .-->
<uses-permission android: name = "android.permission.INTERNET" />
```

> 6.0 and above systems must locate permissions and need to manually obtain permissions

## 3, start integration

> Add under AndroidManifest.xml application tag
```
<application>
    ...

    <service android: name = "cn.net.aicare.pabulumlibrary.pabulum.PabulumService" />

</ application>

```


> Initialization, [key registration](http://sdk.aicare.net.cn/register)
```
// It is recommended to initialize in Application
PabulumSDK.getInstance (). Init (this, "key", "secret");
```

You can directly make your own Activity class inherit BleProfileServiceReadyActivity

```
public class MyActivity extends BleProfileServiceReadyActivity
      @Override
    protected void onCreate (Bundle savedInstanceState) {
        super.onCreate (savedInstanceState);
        // Determine whether the mobile device supports Ble
        if (! ensureBLESupported ()) {
            T.showShort (this, R.string.not_support_ble);
            finish ();
        }
        // Determine whether there is positioning permission, this method does not encapsulate the specific code can be obtained in the demo, you can also call the request permission method in your own way
        initPermissions ();
        // Determine whether Bluetooth is turned on, if you need to change the style, you can implement it yourself
        if (! isBLEEnabled ()) {
            showBLEDialog ();
        }
    }


```

## 4, scan the device, stop scanning the device, check the scan status
The APIs related to scanning are as follows. For details, refer to the BleProfileServiceReadyActivity class. For specific use, refer to the demo

```
  // Call the startScan method to start scanning
  startScan ();
  // onLeScanCallback (BluetoothDevice device, int rssi) interface will callback to get the device that conforms to the protocol
    @Override
    protected void onLeScanCallback (BluetoothDevice device, int rssi) {
               // equipment conforming to the agreement


    }
// Call the stopScan method to stop scanning
 stopScan ();


```



## 5, connect the device, disconnect the device

The connection-related APIs are as follows. For details, refer to the BleProfileServiceReadyActivity class. For specific usage, refer to the demo.

```
// Call the connectDevice (BluetoothDevice device) method to connect to the device. You need to pass in the BluetoothDevice object, which can be obtained in the onLeScanCallback () callback method.

connectDevice (BluetoothDevice device)
// The connection state can be obtained in onStateChanged
@Override
    public void onStateChanged (String deviceAddress, int state) {
        super.onStateChanged (deviceAddress, state);
        // state specific state see class description
        // The connection is successful: (state = BleProfileService.STATE_CONNECTED)
        // Disconnect: (state = BleProfileService.STATE_DISCONNECTED)
        // Successful verification: (state = BleProfileService.STATE_INDICATION_SUCCESS)
    }
// Call the disconnect method in the PabulumService.PabulumBinder class to disconnect
 binder.disconnect ()
```

Use the `connectDevice` method to connect, use the` onStateChanged` method to monitor the status of the connection, and use the `onError` method to monitor exceptions during the connection process for additional processing and troubleshooting. Use the `isConnected` method to determine whether the connection has been established.

## 6 Connect successfully, accept the data returned by the scale
The following methods or interfaces can be automatically obtained directly after inheriting the BleProfileServiceReadyActivity class

```
// Get the instance of PabulumService.PabulumBinder in the onServiceBinded method
    @Override
    protected void onServiceBinded (BleProfileService.LocalBinder binder) {
        this.binder = (PabulumService.PabulumBinder) binder;

   }
    // The device returns data
    @Override
    protected void getFoodData (FoodData foodData) {
         // FoodData (String data, byte unit, byte deviceType, double weight);
         // data (weight, corresponding to current unit),
         // unit (unit, same as above unitType),
         // deviceType (0x04: no decimal point, 0x05: large range),
         // weight (weight in g)
    }
    // List of supported units
    @Override
    protected void getUnits (int [] units) {
       // List of units defined in PabulumBleConfig
       UNIT_G = 0x00; // g
       UNIT_ML = 0x01; // ml
       UNIT_LB = 0x02; // pound
       UNIT_OZ = 0x03; // oz
       UNIT_KG = 0x04; // kg
       UNIT_FG = 0x05; // jin = 500g
       UNIT_ML_MILK = 0x06; // milk ml
       UNIT_ML_WATER = 0x07; // water ml
       UNIT_FL_OZ_MILK = 0x08; // milk floz
       UNIT_FL_OZ_WATER = 0x09; // Water floz
    }
    // Current unit
    @Override
    protected void getUnit (byte unitType) {

    }
    // The timing operation instruction returned by the device
    @Override
    protected void getTimeStatus (int status) {
        // status status (on = 1, off = 2, reset = 3)
    }

    // Countdown start instruction returned by the device
   @Override
    protected void getCountdownStart (int time) {
        // time seconds
    }

    // Sync time instruction returned by the device
    @Override
    protected void getSynTime (byte cmdType, int timeS) {
        // timeS seconds
        // cmdType is the instruction type, range
        //PabulumBleConfig.SYN_TIME-> positive timing synchronization time
        //PabulumBleConfig.SYN_TIME_LESS-> Countdown synchronization time
        //PabulumBleConfig.TIMING_PAUSE-> Pause the synchronization time while timing
        //PabulumBleConfig.TIMING_PAUSE_LESS-> Countdown pauses synchronization time
    }

    // Error instruction
    @Override
    protected void getErrCodes (int [] ints) {
        // err [0] == 1 overload, 0 positiveNormal;
// err [1] == 1 low power, 0 normal
    }
    // stop alarm instruction
    @Override
    protected void getStopAlarm () {

    }

    // Version information returned by the device
    @Override
    protected void getBleVersion (String version) {

    }

    // The signal strength of the device
    @Override
    public void onReadRssi (int rssi) {

    }

    // Transparent transmission data returned by the device (cannot start with 0xAC and 0xAD to avoid conflict with other SDK protocols):
    @Override
    protected void getPenetrateData (byte [] bytes) {

    }

```
> Note: Some of these interfaces or methods require APP to issue commands to body fat to return data.
## 7 Give instructions to the device
Get an instance of PabulumService.PabulumBinder in BleProfileServiceReadyActivity.onServiceBinded (PabulumService.PabulumBinder binder), call the method inside binder


```
Units supported by the scale: getUnits ();

Setting unit: setUnit (byte unitType); // The list supported by unitType is obtained from getUnits ()

Tare: netWeight ();

Shutdown: powerOff ();

Custom write data interface: writeValue (byte [] value); // value cannot be null, length cannot be greater than 20

// --------- Timing related functions of coffee scale

Start timing: startTime ();

Pause, timing: pauseTime (int time);

Pause, countdown: pauseTimeLess (int time);

Reset timing: resetTime ();

Start countdown: startTimeLess (int time); // time is seconds

Stop alarm command: stopAlarm ();

```


## 8 categories


#### 1.FoodData (weight data)
```
Type Parameter name Description
String data; // Weight, corresponding to the current unit
byte unit; // unit
byte deviceType; // Device type: 0x04 (no decimal point), 0x05 (large range)
double weight; // Weight, corresponding unit g
```

+ 290
- 0
README_CN.md View File

@@ -0,0 +1,290 @@

# 好营养SDK使用说明 - Android

[![](https://jitpack.io/v/elinkthings/PabulumSDKRepositoryAndroid.svg)](https://jitpack.io/#elinkthings/PabulumSDKRepositoryAndroid)

[aar包下载地址](https://github.com/elinkthings/PabulumSDKRepositoryAndroid/releases)

[English documentation](README.md)

该文档为指导Android开发人员在Android 4.4及以上系统中集成好营养-SDK-Android,主要为一些关键的使用示例

## 一、导入SDK


```
repositories {
flatDir {
dirs 'libs'
}
}


步骤1.将JitPack存储库添加到您的构建文件中
将其添加到存储库末尾的root build.gradle中:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}

步骤2.添加依赖项
dependencies {
implementation 'com.github.elinkthings:PabulumSDKRepositoryAndroid:1.2.6'
}





也可以使用aar包依赖,请自行下载放到项目的libs中



```

## 二、权限设置

```
<!--In most cases, you need to ensure that the device supports BLE.-->
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true"/>

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

<!--Android 6.0 and above. Bluetooth scanning requires one of the following two permissions. You need to apply at run time.-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

<!--Optional. If your app need dfu function.-->
<uses-permission android:name="android.permission.INTERNET"/>
```

> 6.0及以上系统必须要定位权限,且需要手动获取权限

## 三、开始集成

> 在AndroidManifest.xml application标签下面增加
```
<application>
...

<service android:name="cn.net.aicare.pabulumlibrary.pabulum.PabulumService" />

</application>

```


> 初始化,[key注册](http://sdk.aicare.net.cn/register)
```
//建议在Application中初始化
PabulumSDK.getInstance().init(this,"key","secret");
```

你可以直接让你自己的`Activity`类继承`BleProfileServiceReadyActivity`

```
public class MyActivity extends BleProfileServiceReadyActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//判断手机设备是否支持Ble
if (!ensureBLESupported()) {
T.showShort(this, R.string.not_support_ble);
finish();
}
//判断是否有定位权限,此方法没有进行封装具体代码可在demo中获得,也可按照自己方式去调用请求权限方法
initPermissions();
//判断蓝牙是否打开,若需要换样式,可自己去实现
if (!isBLEEnabled()) {
showBLEDialog();
}
}


```

## 四、扫描设备,停止扫描设备,查看扫描状态
与扫描相关的API如下,详情参考BleProfileServiceReadyActivity类,具体使用参考demo

```
//调用startScan方法开启扫描
startScan();
//onLeScanCallback(BluetoothDevice device, int rssi)接口会回调获取到符合协议的设备
@Override
protected void onLeScanCallback(BluetoothDevice device, int rssi) {
//符合协议的设备


}
//调用stopScan方法停止扫描
stopScan();


```



## 五、连接设备,断开设备

与连接相关的API如下,详情参考BleProfileServiceReadyActivity类,具体使用参考demo。

```
//调用connectDevice(BluetoothDevice device)方法去连接设备 需要传入BluetoothDevice对象,可以在onLeScanCallback()回调方法中获得 。

connectDevice(BluetoothDevice device)
//在onStateChanged可以获取到连接状态
@Override
public void onStateChanged(String deviceAddress, int state) {
super.onStateChanged(deviceAddress, state);
//state 具体状态看类说明
//连接成功:(state = BleProfileService.STATE_CONNECTED)
//断开连接:(state = BleProfileService.STATE_DISCONNECTED)
//校验成功:(state = BleProfileService.STATE_INDICATION_SUCCESS)
}
//调用PabulumService.PabulumBinder类中disconnect方法去断开连接
binder.disconnect()
```

使用`connectDevice`方法连接,,使用`onStateChanged`方法监听连接的状态,使用`onError`方法监听连接过程中的异常,以便于进行额外的处理和问题排查。使用`isConnected`方法判断连接是否已经建立。

## 六 连接成功,接受秤返回的数据
以下方法或接口可直接在继承BleProfileServiceReadyActivity类后自动获得

```
//onServiceBinded方法中获得PabulumService.PabulumBinder的实例
@Override
protected void onServiceBinded(BleProfileService.LocalBinder binder) {
this.binder = (PabulumService.PabulumBinder) binder;

}
//设备返回数据
@Override
protected void getFoodData(FoodData foodData) {
//FoodData(String data, byte unit, byte deviceType, double weight);
//data(重量, 对应当前单位),
//unit(单位,同上 unitType),
//deviceType(0x04: 无小数点,0x05:大量程),
//weight(重量,以 g 为单位)
}
//支持的单位列表
@Override
protected void getUnits(int[] units) {
//PabulumBleConfig 中定义的单位列表
UNIT_G = 0x00; //克
UNIT_ML = 0x01; //毫升
UNIT_LB = 0x02; //磅
UNIT_OZ = 0x03; //盎司
UNIT_KG = 0x04; //千克
UNIT_FG = 0x05; //斤=500g
UNIT_ML_MILK = 0x06; //牛奶 ml
UNIT_ML_WATER = 0x07; //水 ml
UNIT_FL_OZ_MILK = 0x08; //牛奶 floz
UNIT_FL_OZ_WATER = 0x09; //水 floz
}
//当前单位
@Override
protected void getUnit(byte unitType) {

}
//设备返回的计时操作指令
@Override
protected void getTimeStatus(int status) {
//status 状态(开=1,关=2,重置=3)
}

//设备返回的倒计时开始指令
@Override
protected void getCountdownStart(int time) {
//time 秒
}

//设备返回的同步时间指令
@Override
protected void getSynTime(byte cmdType, int timeS) {
//timeS 秒
//cmdType 为指令类型, 范围
//PabulumBleConfig.SYN_TIME -->正计时同步时间
//PabulumBleConfig.SYN_TIME_LESS -->倒计时同步时间
//PabulumBleConfig.TIMING_PAUSE -->正计时暂停同步时间
//PabulumBleConfig.TIMING_PAUSE_LESS -->倒计时暂停同步时间
}

//错误指令
@Override
protected void getErrCodes(int[] ints) {
//err[0]==1 超载,0 正常;err[1]==1 低电,0 正常
}
//停止闹铃指令
@Override
protected void getStopAlarm() {

}

//设备返回的版本信息
@Override
protected void getBleVersion(String version) {

}

//设备的信号强度
@Override
public void onReadRssi(int rssi) {

}

//设备返回的透传数据(不能用 0xAC 和 0xAD 开头,避免与 SDK 其他协议冲突):
@Override
protected void getPenetrateData(byte[] bytes) {

}

```
> 注意:这些接口或方法部分需要APP给体脂下发命令才会有返回数据.
## 七 给设备下发指令
在BleProfileServiceReadyActivity.onServiceBinded(PabulumService.PabulumBinder binder)获得PabulumService.PabulumBinder的实例,调用binder里面方法


```
秤支持的单位:getUnits();

设置单位:setUnit(byte unitType); //unitType 支持的列表从getUnits()中获取

去皮:netWeight();

关机:powerOff();

自定义写数据接口:writeValue(byte[] value);//value 不能为 null, 长度不能大于 20

//---------咖啡秤定时相关功能

开始计时:startTime();

暂停,正计时:pauseTime(int time);

暂停,倒计时:pauseTimeLess(int time);

重置计时:resetTime();

开始倒计时:startTimeLess(int time);//time 为秒

停止闹铃指令:stopAlarm();

```


## 八 类说明


#### 1.FoodData(重量数据)
```
类型 参数名 说明
String data;//重量,对应当前单位
byte unit;//单位
byte deviceType;//设备类型:0x04(无小数点), 0x05(大量程)
double weight;//重量,对应单位g
```

+ 1
- 0
app/.gitignore View File

@@ -0,0 +1 @@
/build

+ 37
- 0
app/build.gradle View File

@@ -0,0 +1,37 @@
apply plugin: 'com.android.application'
apply plugin: 'com.jakewharton.butterknife'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "aicare.net.cn.sdk.pabulumsdkrepositoryandroid"
minSdkVersion 19
targetSdkVersion 29
versionCode 1
versionName "1.2.6"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation project(path: ':pabulumlibrary')
implementation 'com.jakewharton:butterknife:10.2.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.0'
}

+ 21
- 0
app/proguard-rules.pro View File

@@ -0,0 +1,21 @@
# 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

+ 27
- 0
app/src/androidTest/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/ExampleInstrumentedTest.java View File

@@ -0,0 +1,27 @@
package aicare.net.cn.sdk.pabulumsdkrepositoryandroid;

import android.content.Context;

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

import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

import static org.junit.Assert.assertEquals;

/**
* 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.getTargetContext();

assertEquals("aicare.net.cn.sdk.pabulumsdkrepositoryandroid", appContext.getPackageName());
}
}

+ 32
- 0
app/src/main/AndroidManifest.xml View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="aicare.net.cn.sdk.pabulumsdkrepositoryandroid"
xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">

</activity>
<activity android:name=".WelcomeActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>

<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service android:name="cn.net.aicare.pabulumlibrary.pabulum.PabulumService" />
</application>

</manifest>

+ 689
- 0
app/src/main/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/MainActivity.java View File

@@ -0,0 +1,689 @@
package aicare.net.cn.sdk.pabulumsdkrepositoryandroid;

import android.Manifest;
import android.bluetooth.BluetoothDevice;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;

import java.util.Arrays;
import java.util.Random;

import aicare.net.cn.sdk.pabulumsdkrepositoryandroid.base.BaseActivity;
import aicare.net.cn.sdk.pabulumsdkrepositoryandroid.utils.AppUtils;
import aicare.net.cn.sdk.pabulumsdkrepositoryandroid.utils.Config;
import aicare.net.cn.sdk.pabulumsdkrepositoryandroid.utils.SPUtils;
import aicare.net.cn.sdk.pabulumsdkrepositoryandroid.utils.T;
import aicare.net.cn.sdk.pabulumsdkrepositoryandroid.view.SetRssiDialog;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnCheckedChanged;
import butterknife.OnClick;
import cn.net.aicare.pabulumlibrary.bleprofile.BleProfileService;
import cn.net.aicare.pabulumlibrary.entity.FoodData;
import cn.net.aicare.pabulumlibrary.pabulum.PabulumService;
import cn.net.aicare.pabulumlibrary.utils.L;
import cn.net.aicare.pabulumlibrary.utils.PabulumBleConfig;
import cn.net.aicare.pabulumlibrary.utils.ParseData;


public class MainActivity extends BaseActivity implements SetRssiDialog.OnQueryListener {

private final static String TAG = MainActivity.class.getSimpleName();
@BindView(R.id.ib_title_left)
ImageButton ibTitleLeft;
@BindView(R.id.tv_title_middle)
TextView tvTitleMiddle;
@BindView(R.id.btn_title_right)
Button btnTitleRight;
@BindView(R.id.tv_show_state)
TextView tvShowState;
@BindView(R.id.tv_show_rssi)
TextView tvShowRssi;
@BindView(R.id.tv_show_version)
TextView tvShowVersion;
@BindView(R.id.rg_unit)
RadioGroup rgUnit;
@BindView(R.id.et_set_weight)
EditText etSetWeight;
@BindView(R.id.tv_show_result)
TextView tvShowResult;
@BindView(R.id.tv_show_did)
TextView tvShowDid;
@BindView(R.id.tv_show_time)
TextView tv_show_time;

@OnClick({R.id.btn_title_right, R.id.tv_show_state, R.id.btn_set_weight, R.id.btn_tare,
R.id.btn_power_off, R.id.btn_cal, R.id.btn_all_cal, R.id.btn_fat, R.id.btn_all_fat,
R.id.btn_pro, R.id.btn_all_pro, R.id.btn_car, R.id.btn_all_car, R.id.btn_fib,
R.id.btn_all_fib, R.id.btn_cho, R.id.btn_all_cho, R.id.btn_sod, R.id.btn_all_sod,
R.id.btn_sug, R.id.btn_all_sug, R.id.btn_write_value, R.id.btn_did,
R.id.btn_get_version, R.id.btn_start, R.id.btn_start_less, R.id.btn_pause,
R.id.btn_reset, R.id.btn_pause_less})
void onClick(View view) {
switch (view.getId()) {
case R.id.btn_title_right:
new SetRssiDialog(this, defaultRssi, this).show();
break;
case R.id.tv_show_state:
if (binder != null) {
binder.disconnect();
}
break;
case R.id.btn_set_weight:
String weight = etSetWeight.getText().toString().trim();
if (TextUtils.isEmpty(weight)) {
T.showShort(this, R.string.pls_input_weight);
} else {
int wei = Integer.valueOf(weight);
if (binder != null) {
binder.setWeight(wei);
}
}
break;
case R.id.btn_tare:
if (binder != null) {
binder.netWeight();
}
break;
case R.id.btn_power_off:
if (binder != null) {
binder.powerOff();
handler.postDelayed(disconnectRunnable, 1000);
}
break;
case R.id.btn_did:
if (binder != null) {
binder.getDid();
}
break;
//2019/4/29
case R.id.btn_start:
if (binder != null) {
binder.startTime();
}
break; //2019/6/25
case R.id.btn_start_less:
if (binder != null) {
binder.startTimeLess(180);
}
break;
//2019/6/25
case R.id.btn_pause:
if (binder != null) {
L.i(TAG, "Positive timing pause");
binder.pauseTime(80);
}
break;
//2019/6/25
case R.id.btn_pause_less:
if (binder != null) {
L.i(TAG, "Countdown pause");
binder.pauseTimeLess(90);
}
break;
//2019/4/29
case R.id.btn_reset:
if (binder != null) {
binder.resetTime();
}
break;
case R.id.btn_write_value:
if (binder != null) {
byte[] value = initRandomByteArr(new Random().nextInt(21));
L.e(TAG, "value: " + ParseData.arr2Str(value));
binder.writeValue(value);
}
break;
case R.id.btn_get_version:
if (binder != null) {
binder.getVersion();

}
break;
default:
setData(view.getId());
break;
}
}

private byte[] initRandomByteArr(int count) {
byte[] bytes = new byte[count];
Random random = new Random();
for (int i = 0; i < bytes.length; ++i) {
bytes[i] = Integer.valueOf(random.nextInt(256)).byteValue();
}

return bytes;
}

private void setData(int id) {
String data = etSetWeight.getText().toString().trim();
if (TextUtils.isEmpty(data)) {
T.showShort(this, R.string.pls_input_weight);
} else {
int wei = Integer.valueOf(data);
if (binder != null) {
switch (id) {
case R.id.btn_cal:
binder.setCal(wei);
break;
case R.id.btn_all_cal:
binder.setAllCal(wei);
break;
case R.id.btn_fat:
binder.setFat(wei);
break;
case R.id.btn_all_fat:
binder.setAllFat(wei);
break;
case R.id.btn_pro:
binder.setPro(wei);
break;
case R.id.btn_all_pro:
binder.setAllPro(wei);
break;
case R.id.btn_car:
binder.setCar(wei);
break;
case R.id.btn_all_car:
binder.setAllCar(wei);
break;
case R.id.btn_fib:
binder.setFib(wei);
break;
case R.id.btn_all_fib:
binder.setAllFib(wei);
break;
case R.id.btn_cho:
binder.setCho(wei);
break;
case R.id.btn_all_cho:
binder.setAllCho(wei);
break;
case R.id.btn_sod:
binder.setSod(wei);
break;
case R.id.btn_all_sod:
binder.setAllSod(wei);
break;
case R.id.btn_sug:
binder.setSug(wei);
break;
case R.id.btn_all_sug:
binder.setAllSug(wei);
break;
}
}
}
}

@OnCheckedChanged({R.id.rb_g, R.id.rb_lb, R.id.rb_ml, R.id.rb_oz, R.id.rb_kg, R.id.rb_fg})
void onCheckedChange(RadioButton radioButton, boolean isChecked) {
if (isBleChangeUnit) {
isBleChangeUnit = false;
return;
}
if (isChecked) {
switch (radioButton.getId()) {
case R.id.rb_g:
if (binder != null) {
binder.setUnit(PabulumBleConfig.UNIT_G);
}
break;
case R.id.rb_ml:
if (binder != null) {
binder.setUnit(PabulumBleConfig.UNIT_ML);
}
break;
case R.id.rb_lb:
if (binder != null) {
binder.setUnit(PabulumBleConfig.UNIT_LB);
}
break;
case R.id.rb_oz:
if (binder != null) {
binder.setUnit(PabulumBleConfig.UNIT_OZ);
}
break;
case R.id.rb_kg:
if (binder != null) {
binder.setUnit(PabulumBleConfig.UNIT_KG);
}
break;
case R.id.rb_fg:
if (binder != null) {
binder.setUnit(PabulumBleConfig.UNIT_FG);
}
break;
}
}
}

private PabulumService.PabulumBinder binder;
private int defaultRssi;

private final static int DEFAULT_RSSI = -70;

private String preWeight = "0";

/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
L.isDebug = true;
setContentView(R.layout.main);
initData();
ButterKnife.bind(this);
initViews();
if (!AppUtils.isLocServiceEnable(this)) {
T.showShort(this,this.getString(R.string.permissions_server));
}

if (ensureBLESupported()) {

initPermissions();
}
reset();
}

private void initData() {
defaultRssi = (int) SPUtils.get(this, Config.DEFAULT_RSSI, DEFAULT_RSSI);
}

private void initViews() {
setTitleRight(Math.abs(defaultRssi));
}

private void reset() {
setCurrentRssi(null);
setBleVersion(getResources().getString(R.string.no_version));
tvShowResult.setText(String.valueOf(preWeight));
tvShowResult.setTextColor(getResources().getColor(R.color.black_theme));
}



private void setState(Object object) {
if (object instanceof Integer) {
tvShowState.setText((Integer) object);
} else if (object instanceof String) {
tvShowState.setText((String) object);
}
}


private void setCurrentRssi(Object object) {
if (object == null) {
tvShowRssi.setText(R.string.no_rssi);
} else {
if (object instanceof Integer) {
tvShowRssi.setText(String.format(getResources().getString(R.string.current_rssi),
(Integer) object));
}
}
}

private void setBleVersion(String version) {
tvShowVersion.setText(version);

}


@Override
protected void getTimeStatus(int status) {
//2019/4/29
Toast.makeText(MainActivity.this, "getTimeStatus:" + status, Toast.LENGTH_SHORT).show();
}

@Override
protected void getCountdownStart(int time) {
//2019/5/22
Toast.makeText(MainActivity.this, "getCountdownStart:" + time, Toast.LENGTH_SHORT).show();
}

@Override
protected void getSynTime(byte cmdType, int timeS) {
//2019/5/22
String tyepName="";
switch (cmdType) {

case PabulumBleConfig.SYN_TIME:
tyepName="Time synchronization";
break;
case PabulumBleConfig.SYN_TIME_LESS:
tyepName="Countdown time synchronization";
break;
case PabulumBleConfig.TIMING_PAUSE:
tyepName="Positive timing pause";
Toast.makeText(MainActivity.this,"Positive timing pause", Toast.LENGTH_SHORT).show();
break;
case PabulumBleConfig.TIMING_PAUSE_LESS:
tyepName="Countdown pause";
Toast.makeText(MainActivity.this,"Countdown pause", Toast.LENGTH_SHORT).show();
break;

}
L.i(TAG, "TIME:" + timeS + "||" + tyepName);
tv_show_time.setText("TIME:" + timeS);
}

@Override
protected void getBleDID(int did) {
L.i(TAG, "getBleDID:" + did);
tvShowDid.setText("DID:" + did);
}


@Override
protected void getUnits(int[] units) {
L.i(TAG, "支持的单位列表 = " + Arrays.toString(units));
}

@Override
protected void getErrCodes(int[] ints) {
super.getErrCodes(ints);
}

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

@Override
protected void getPenetrateData(byte[] data) {
L.i(TAG, "透传数据:" + ParseData.arr2Str(data));

}

private void setTitleRight(int rssi) {
btnTitleRight.setText(String.format(getResources().getString(R.string.default_rssi), rssi));
}

@Override
protected void onServiceBinded(BleProfileService.LocalBinder binder) {

this.binder = (PabulumService.PabulumBinder) binder;
this.binder.getDeviceAddress();
this.binder.getDeviceName();
}

@Override
public void onStateChanged(int state) {
super.onStateChanged(state);
switch (state) {
case BleProfileService.STATE_CONNECTED:
L.e(TAG, "onDeviceConnected");
if (binder != null) {
setState(String.format(getResources().getString(R.string.current_device),
binder.getDeviceAddress()));
}
break;
case BleProfileService.STATE_DISCONNECTED:
L.e(TAG, "onDeviceDisconnected");
setState(R.string.disconnected);
preWeight = "0";
reset();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
startScan();
}
}, 1000);
break;
case BleProfileService.STATE_INDICATION_SUCCESS:
L.e(TAG, "onIndicationSuccess");
if (binder != null) {
binder.setUnit(preUnit);
}
rgUnit.check(R.id.rb_g);
break;
}
}

@Override
public void onError(String msg, int errorCode) {
T.showLong(this, "msg = " + msg + "; code = " + errorCode);
}

private int countRssi = 0;

@Override
public void onReadRssi(int rssi) {
L.e(TAG, "onReadRssi rssi: " + rssi);
setCurrentRssi(Math.abs(rssi));
if (Math.abs(rssi) > Math.abs(defaultRssi)) {
countRssi += 1;
} else {
countRssi = 0;
}
if (countRssi >= 20) {
if (binder != null) {
binder.disconnect();
}
}
}

private int countWei = 0;

@Override
protected void getUnit(byte unitType) {
L.e(TAG, "unitType = " + unitType);
}

@Override
protected void getBleVersion(String version) {
L.e(TAG, "version = " + version);
setBleVersion(String.format(getResources().getString(R.string.ble_version), version));
}

@Override
protected void onLeScanCallback(BluetoothDevice device, int rssi) {
if (rssi >= defaultRssi) {
connectDevice(device);
}
}

@Override
protected void onStartScan() {
setState(R.string.scan_ing);
}

@Override
protected void bluetoothStateOn() {
super.bluetoothStateOn();
setState(R.string.ble_state_on);
L.e(TAG, "bluetoothStateOn");
handler.postDelayed(new Runnable() {
@Override
public void run() {
startScan();
}
}, 500);
}

private byte preUnit = PabulumBleConfig.UNIT_G;
private boolean isBleChangeUnit = false;

@Override
protected void getFoodData(FoodData foodData) {
if (foodData == null) {//2017-06-16
return;
}
L.e(TAG, "weight = " + foodData.getData());
String curWeight = foodData.getData();
if (TextUtils.equals(curWeight, preWeight)) {
countWei += 1;
} else {
countWei = 0;
preWeight = curWeight;
}
if (countWei >= 5) {
tvShowResult.setTextColor(getResources().getColor(android.R.color.holo_red_dark));
} else {
tvShowResult.setTextColor(getResources().getColor(R.color.black_theme));
}
if (foodData.getUnit() != preUnit) {
preUnit = foodData.getUnit();
isBleChangeUnit = true;
switch (preUnit) {
case PabulumBleConfig.UNIT_G:
rgUnit.check(R.id.rb_g);
break;
case PabulumBleConfig.UNIT_ML:
rgUnit.check(R.id.rb_ml);
break;
case PabulumBleConfig.UNIT_LB:
rgUnit.check(R.id.rb_lb);
break;
case PabulumBleConfig.UNIT_OZ:
rgUnit.check(R.id.rb_oz);
break;
case PabulumBleConfig.UNIT_KG:
rgUnit.check(R.id.rb_kg);
break;
case PabulumBleConfig.UNIT_FG:
rgUnit.check(R.id.rb_fg);
break;
}
}

tvShowResult.setText(preWeight + "\n" + foodData.getDeviceType() + "\n" + foodData.getWeight());
}

@Override
protected void bluetoothStateOff() {
super.bluetoothStateOff();
setState(R.string.ble_state_off);
L.e(TAG, "bluetoothStateOff");
}

@Override
protected void bluetoothTurningOff() {
super.bluetoothTurningOff();
L.e(TAG, "bluetoothTurningOff");
}

@Override
protected void bluetoothTurningOn() {
super.bluetoothTurningOn();
L.e(TAG, "bluetoothTurningOn");
}

@Override
protected void onDestroy() {
super.onDestroy();
L.e(TAG, "onDestroy");
stopScan();
if (binder != null) {
binder.disconnect();
}
}

private Handler handler = new Handler();

private Runnable disconnectRunnable = new Runnable() {
@Override
public void run() {
binder.disconnect();
}
};

@Override
public void query(int rssi) {
defaultRssi = rssi;
setTitleRight(Math.abs(defaultRssi));
if (binder != null) {
binder.disconnect();
} else {
startScan();
}
}

@Override
protected void onWriteSuccess(byte[] value) {
L.e(TAG, "onWriteSuccess: " + ParseData.arr2Str(value));
}



private void initPermissions() {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode != 1) {
return;
}
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startScan();
} else {

if (ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[0])) {
new AlertDialog.Builder(this).setTitle(this.getString(R.string.hint)).setMessage(this.getString(R.string.permissions)).setPositiveButton(this.getString(R.string.query), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package",
getApplicationContext().getPackageName(), null);
intent.setData(uri);
startActivity(intent);
}
}).setNegativeButton(getString(R.string.cancel),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (dialog != null) {
dialog.cancel();
}
}
}).show();
} else {
new AlertDialog.Builder(this).setTitle(this.getString(R.string.hint)).setMessage(this.getString(R.string.permissions)).setPositiveButton(this.getString(R.string.query), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package",
getApplicationContext().getPackageName(), null);
intent.setData(uri);
startActivity(intent);

}
}).setNegativeButton(getString(R.string.cancel),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (dialog != null) {
dialog.cancel();
}
}
}).show();
}

}

}

}

+ 54
- 0
app/src/main/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/WelcomeActivity.java View File

@@ -0,0 +1,54 @@
package aicare.net.cn.sdk.pabulumsdkrepositoryandroid;

import android.app.Application;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;

import aicare.net.cn.sdk.pabulumsdkrepositoryandroid.base.BaseActivity;
import aicare.net.cn.sdk.pabulumsdkrepositoryandroid.utils.AppUtils;
import aicare.net.cn.sdk.pabulumsdkrepositoryandroid.utils.T;
import butterknife.BindView;
import butterknife.ButterKnife;
import cn.net.aicare.pabulumlibrary.PabulumSDK;

/**
* Created by Suzy on 2016/5/10.
*/
public class WelcomeActivity extends BaseActivity {
@BindView(R.id.tv_show_version)
TextView tv_show_version;

private Handler mHandler = new Handler();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
ButterKnife.bind(this);
initViews();
PabulumSDK.getInstance().init(this,"8b834bfc14581ad3","00253970fb418e7b8e240f2869");
if (ensureBLESupported()) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
openActivity(MainActivity.class);
WelcomeActivity.this.finish();
}
}, 3000);
} else {
T.showLong(this, R.string.not_support_ble);
this.finish();
}
}

protected void openActivity(Class<?> cls) {
Intent intent = new Intent(this, cls);
startActivity(intent);
}

private void initViews() {
tv_show_version.setText(getString(R.string.current_version, AppUtils.getVersionName(this)));
}
}

+ 116
- 0
app/src/main/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/base/BaseActivity.java View File

@@ -0,0 +1,116 @@
package aicare.net.cn.sdk.pabulumsdkrepositoryandroid.base;

import android.bluetooth.BluetoothDevice;
import android.os.Build;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;

import cn.net.aicare.pabulumlibrary.bleprofile.BleProfileService;
import cn.net.aicare.pabulumlibrary.bleprofile.BleProfileServiceReadyActivity;
import cn.net.aicare.pabulumlibrary.entity.FoodData;


public abstract class BaseActivity extends BleProfileServiceReadyActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}

@Override
protected void onStartScan() {

}

@Override
protected void onServiceBinded(BleProfileService.LocalBinder binder) {

}

@Override
public void onStateChanged(int state) {
super.onStateChanged(state);
}

@Override
public void onReadRssi(int rssi) {

}

@Override
public void onError(String msg, int errorCode) {

}

@Override
protected void getFoodData(FoodData foodData) {

}

@Override
protected void getUnit(byte unitType) {

}

@Override
protected void getBleVersion(String version) {

}

@Override
protected void getTimeStatus(int status) {

}

@Override
protected void getCountdownStart(int time) {

}

@Override
protected void getSynTime(byte cmdType, int timeS) {

}

@Override
protected void getBleDID(int did) {

}

@Override
protected void getUnits(int[] ints) {

}

@Override
protected void getErrCodes(int[] ints) {

}

@Override
protected void getStopAlarm() {

}

@Override
protected void getPenetrateData(byte[] bytes) {

}

@Override
protected void onLeScanCallback(BluetoothDevice device, int rssi) {

}

@Override
protected void onWriteSuccess(byte[] value) {

}


}

+ 56
- 0
app/src/main/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/utils/AppUtils.java View File

@@ -0,0 +1,56 @@
package aicare.net.cn.sdk.pabulumsdkrepositoryandroid.utils;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.location.LocationManager;

public class AppUtils {

private AppUtils() {
/* cannot be instantiated */
throw new UnsupportedOperationException("cannot be instantiated");

}


public static String getAppName(Context context) {
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(
context.getPackageName(), 0);
int labelRes = packageInfo.applicationInfo.labelRes;
return context.getResources().getString(labelRes);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}


public static String getVersionName(Context context) {
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(
context.getPackageName(), 0);
return packageInfo.versionName;

} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}



public static boolean isLocServiceEnable(Context context) {
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
boolean gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
boolean network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (gps || network) {
return true;
}
return false;
}
}

+ 8
- 0
app/src/main/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/utils/Config.java View File

@@ -0,0 +1,8 @@
package aicare.net.cn.sdk.pabulumsdkrepositoryandroid.utils;

/**
* Created by Suzy on 2016/6/22.
*/
public class Config {
public final static String DEFAULT_RSSI = "DEFAULT_RSSI";
}

+ 126
- 0
app/src/main/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/utils/SPUtils.java View File

@@ -0,0 +1,126 @@
package aicare.net.cn.sdk.pabulumsdkrepositoryandroid.utils;

import android.content.Context;
import android.content.SharedPreferences;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

public class SPUtils {
public SPUtils() {
/* cannot be instantiated */
throw new UnsupportedOperationException("cannot be instantiated");
}


public static final String FILE_NAME = "share_data";


public static void put(Context context, String key, Object object) {

SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();

if (object instanceof String) {
editor.putString(key, (String) object);
} else if (object instanceof Integer) {
editor.putInt(key, (Integer) object);
} else if (object instanceof Boolean) {
editor.putBoolean(key, (Boolean) object);
} else if (object instanceof Float) {
editor.putFloat(key, (Float) object);
} else if (object instanceof Long) {
editor.putLong(key, (Long) object);
} else {
editor.putString(key, object.toString());
}

SharedPreferencesCompat.apply(editor);
}


public static Object get(Context context, String key, Object defaultObject) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);

if (defaultObject instanceof String) {
return sp.getString(key, (String) defaultObject);
} else if (defaultObject instanceof Integer) {
return sp.getInt(key, (Integer) defaultObject);
} else if (defaultObject instanceof Boolean) {
return sp.getBoolean(key, (Boolean) defaultObject);
} else if (defaultObject instanceof Float) {
return sp.getFloat(key, (Float) defaultObject);
} else if (defaultObject instanceof Long) {
return sp.getLong(key, (Long) defaultObject);
}

return null;
}


public static void remove(Context context, String key) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.remove(key);
SharedPreferencesCompat.apply(editor);
}


public static void clear(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.clear();
SharedPreferencesCompat.apply(editor);
}


public static boolean contains(Context context, String key) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
return sp.contains(key);
}


public static Map<String, ?> getAll(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
return sp.getAll();
}


private static class SharedPreferencesCompat {
private static final Method sApplyMethod = findApplyMethod();


@SuppressWarnings({ "unchecked", "rawtypes" })
private static Method findApplyMethod() {
try {
Class clz = SharedPreferences.Editor.class;
return clz.getMethod("apply");
} catch (NoSuchMethodException e) {
}

return null;
}

public static void apply(SharedPreferences.Editor editor) {
try {
if (sApplyMethod != null) {
sApplyMethod.invoke(editor);
return;
}
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
editor.commit();
}
}

}

+ 80
- 0
app/src/main/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/utils/T.java View File

@@ -0,0 +1,80 @@
package aicare.net.cn.sdk.pabulumsdkrepositoryandroid.utils;

import android.content.Context;
import android.widget.Toast;

public class T {

private T() {
/* cannot be instantiated */
throw new UnsupportedOperationException("cannot be instantiated");
}

private static Toast mToast;


public static void showShort(Context context, CharSequence message) {
if (mToast == null) {
mToast = Toast.makeText(context, message, Toast.LENGTH_SHORT);
} else {
mToast.setText(message);
mToast.setDuration(Toast.LENGTH_SHORT);
}
mToast.show();
}

public static void showShort(Context context, int message) {
if (mToast == null) {
mToast = Toast.makeText(context, message, Toast.LENGTH_SHORT);
} else {
mToast.setText(message);
mToast.setDuration(Toast.LENGTH_SHORT);
}
mToast.show();
}


public static void showLong(Context context, CharSequence message) {
if (mToast == null) {
mToast = Toast.makeText(context, message, Toast.LENGTH_LONG);
} else {
mToast.setText(message);
mToast.setDuration(Toast.LENGTH_LONG);
}
mToast.show();
}


public static void showLong(Context context, int message) {
if (mToast == null) {
mToast = Toast.makeText(context, message, Toast.LENGTH_LONG);
} else {
mToast.setText(message);
mToast.setDuration(Toast.LENGTH_LONG);
}
mToast.show();
}


public static void show(Context context, CharSequence message, int duration) {
if (mToast == null) {
mToast = Toast.makeText(context, message, duration);
} else {
mToast.setText(message);
mToast.setDuration(duration);
}
mToast.show();
}


public static void show(Context context, int message, int duration) {
if (mToast == null) {
mToast = Toast.makeText(context, message, duration);
} else {
mToast.setText(message);
mToast.setDuration(duration);
}
mToast.show();
}

}

+ 104
- 0
app/src/main/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/view/SetRssiDialog.java View File

@@ -0,0 +1,104 @@
package aicare.net.cn.sdk.pabulumsdkrepositoryandroid.view;

import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;

import aicare.net.cn.sdk.pabulumsdkrepositoryandroid.R;
import aicare.net.cn.sdk.pabulumsdkrepositoryandroid.utils.Config;
import aicare.net.cn.sdk.pabulumsdkrepositoryandroid.utils.SPUtils;
import aicare.net.cn.sdk.pabulumsdkrepositoryandroid.utils.T;


/**
* Created by Suzy on 2016/6/22.
*/
public class SetRssiDialog extends Dialog implements View.OnClickListener {

private Context context;
private int rssi;
private OnQueryListener onQueryListener;

private Button btn_cancel, btn_query;
private EditText et_input_rssi;

public SetRssiDialog(Context context) {
super(context, R.style.MyDialog);
}

public SetRssiDialog(Context context, int rssi, OnQueryListener onQueryListener) {
this(context);
this.context = context;
this.rssi = rssi;
this.onQueryListener = onQueryListener;
}

public interface OnQueryListener {
void query(int rssi);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_set_rssi);
setDialogWidth();
initViews();
setEvents();
}


private void setDialogWidth() {
Window dialogWindow = getWindow();
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
DisplayMetrics d = context.getResources().getDisplayMetrics();
lp.width = (int) (d.widthPixels * 0.8);
dialogWindow.setAttributes(lp);
}

private void initViews() {
btn_cancel = (Button) findViewById(R.id.btn_cancel);
btn_query = (Button) findViewById(R.id.btn_query);
et_input_rssi = (EditText) findViewById(R.id.et_input_rssi);
et_input_rssi.setText(String.valueOf(Math.abs(rssi)));
et_input_rssi.setSelection(String.valueOf(Math.abs(rssi)).length());
}

private void setEvents() {
btn_cancel.setOnClickListener(this);
btn_query.setOnClickListener(this);
}

@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.btn_cancel:
T.showShort(context, R.string.user_cancel);
break;
case R.id.btn_query:
String rssiStr = et_input_rssi.getText().toString();
if (TextUtils.isEmpty(rssiStr)) {
T.showShort(context, R.string.rssi_not_null);
}else {
int customRssi = Integer.valueOf(rssiStr);
if (customRssi < 30 || customRssi > 120) {
T.showShort(context, R.string.rssi_error);
}else {
SPUtils.put(context, Config.DEFAULT_RSSI, 0 - customRssi);
if (onQueryListener != null) {
onQueryListener.query(0 - customRssi);
}
T.showShort(context, R.string.rssi_set_success);
}
}
break;
}
dismiss();
}
}

+ 34
- 0
app/src/main/res/drawable-v24/ic_launcher_foreground.xml View File

@@ -0,0 +1,34 @@
<vector xmlns:aapt="http://schemas.android.com/aapt"
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0"/>
<item
android:color="#00000000"
android:offset="1.0"/>
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1"/>
</vector>

+ 5
- 0
app/src/main/res/drawable/activity_title_right.xml View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="false" android:drawable="@android:color/transparent" />
<item android:state_pressed="true" android:drawable="@color/dark_grey_50" />
</selector>

+ 171
- 0
app/src/main/res/drawable/ic_launcher_background.xml View File

@@ -0,0 +1,171 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillColor="#008577"
android:pathData="M0,0h108v108h-108z"/>
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
</vector>

+ 7
- 0
app/src/main/res/drawable/main_divider.xml View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

<solid android:color="@color/black_theme" />
<size android:height="1px"/>
</shape>

+ 13
- 0
app/src/main/res/drawable/warning_cancel_btn_bg.xml View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle" >
<solid android:color="@color/dark_grey_50" />
</shape>
</item>
<item>
<shape android:shape="rectangle" >
<solid android:color="@color/dark_grey" />
</shape>
</item>
</selector>

+ 13
- 0
app/src/main/res/drawable/warning_query_btn_bg.xml View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle" >
<solid android:color="@color/system_theme_50" />
</shape>
</item>
<item>
<shape android:shape="rectangle" >
<solid android:color="@color/system_theme" />
</shape>
</item>
</selector>

+ 33
- 0
app/src/main/res/layout/activity_title.xml View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/activity_title_height">

<ImageButton
android:id="@+id/ib_title_left"
style="@style/ActivityTitleIB"
android:layout_gravity="center_vertical" />

<TextView
android:id="@+id/tv_title_middle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="58dp"
android:layout_marginRight="58dp"
android:gravity="center"
android:singleLine="true"
android:text="@string/app_name"
android:textColor="@color/black_theme"
android:textSize="@dimen/activity_title_size" />

<Button
android:id="@+id/btn_title_right"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="right"
android:background="@drawable/activity_title_right"
android:gravity="center"
android:padding="10dp"
android:textColor="@color/black_theme"
android:textSize="@dimen/activity_title_right_size" />
</FrameLayout>

+ 23
- 0
app/src/main/res/layout/activity_welcome.xml View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="true"
android:fitsSystemWindows="true"
android:orientation="vertical">

<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:text="@string/app_name"
android:textSize="22sp" />

<TextView
android:id="@+id/tv_show_version"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"/>
</LinearLayout>

+ 57
- 0
app/src/main/res/layout/dialog_set_rssi.xml View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="218dp"
android:background="@color/white_theme"
android:padding="20dp">

<TextView
android:id="@+id/tv_dialog_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:gravity="center"
android:text="@string/dialog_set_rssi_title"
android:textColor="@color/dark_grey"
android:textSize="20sp" />

<EditText
android:id="@+id/et_input_rssi"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_dialog_title"
android:inputType="numberDecimal"
android:layout_marginTop="10dp"
android:hint="30~120"
android:textColor="@color/dark_grey" />

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/et_input_rssi"
android:text="@string/dialog_set_rssi_tips"
android:textColor="@color/dark_grey_50"
android:textSize="18sp" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
android:weightSum="2">

<Button
android:id="@+id/btn_cancel"
style="@style/DialogWarningBtn"
android:layout_marginRight="10dp"
android:background="@drawable/warning_cancel_btn_bg"
android:text="@string/cancel" />

<Button
android:id="@+id/btn_query"
style="@style/DialogWarningBtn"
android:layout_marginLeft="10dp"
android:background="@drawable/warning_query_btn_bg"
android:text="@string/query" />
</LinearLayout>
</RelativeLayout>

+ 5
- 0
app/src/main/res/layout/divider_horizontal.xml View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<View xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/black_theme" />

+ 354
- 0
app/src/main/res/layout/main.xml View File

@@ -0,0 +1,354 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/system_theme"
android:clipToPadding="true"
android:divider="@drawable/main_divider"
android:fitsSystemWindows="true"
android:orientation="vertical"
android:showDividers="middle">

<include layout="@layout/activity_title" />

<TextView
android:id="@+id/tv_show_state"
style="@style/Base_Text_View" />

<TextView
android:id="@+id/tv_show_rssi"
style="@style/Base_Text_View" />

<TextView
android:id="@+id/tv_show_version"
style="@style/Base_Text_View" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<RadioGroup
android:id="@+id/rg_unit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">

<RadioButton
android:id="@+id/rb_g"
style="@style/Base_Radio_Button"
android:text="g" />

<RadioButton
android:id="@+id/rb_ml"
style="@style/Base_Radio_Button"
android:text="ml" />

<RadioButton
android:id="@+id/rb_lb"
style="@style/Base_Radio_Button"
android:text="lb" />

<RadioButton
android:id="@+id/rb_oz"
style="@style/Base_Radio_Button"
android:text="oz" />

<RadioButton
android:id="@+id/rb_kg"
style="@style/Base_Radio_Button"
android:text="kg" />

<RadioButton
android:id="@+id/rb_fg"
style="@style/Base_Radio_Button"
android:text="斤" />

</RadioGroup>
</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<EditText
android:id="@+id/et_set_weight"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:hint="@string/pls_input_weight"
android:inputType="number" />

<Button
android:id="@+id/btn_set_weight"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/set_weight" />
</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="horizontal"
android:visibility="gone">

<Button
android:id="@+id/btn_cal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="2dp"
android:text="卡路里" />

<Button
android:id="@+id/btn_all_cal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="总卡路里" />

<Button
android:id="@+id/btn_sug"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:text="糖" />

<Button
android:id="@+id/btn_all_sug"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="总糖" />

</LinearLayout>


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="horizontal"
android:visibility="gone"
>

<Button
android:id="@+id/btn_fat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="2dp"
android:text="脂肪" />

<Button
android:id="@+id/btn_all_fat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="总脂肪" />

<Button
android:id="@+id/btn_pro"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:text="蛋白质" />

<Button
android:id="@+id/btn_all_pro"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="总蛋白质" />

</LinearLayout>


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="horizontal"
android:visibility="gone">

<Button
android:id="@+id/btn_car"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="2dp"
android:text="碳水" />

<Button
android:id="@+id/btn_all_car"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="总碳水" />

<Button
android:id="@+id/btn_fib"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:text="纤维" />

<Button
android:id="@+id/btn_all_fib"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="总纤维" />

</LinearLayout>


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="horizontal"
android:visibility="gone">

<Button
android:id="@+id/btn_cho"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="2dp"
android:text="胆固醇" />

<Button
android:id="@+id/btn_all_cho"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="总胆固醇" />

<Button
android:id="@+id/btn_sod"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:text="钠" />

<Button
android:id="@+id/btn_all_sod"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="总钠" />

</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="horizontal">

<Button
android:id="@+id/btn_tare"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="2dp"
android:text="@string/zero" />

<Button
android:id="@+id/btn_power_off"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/shut_down" />

<Button
android:id="@+id/btn_write_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/write" />

<Button
android:id="@+id/btn_get_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/get_version" />



</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="horizontal">

<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="2dp"
android:text="@string/timing" />

<Button
android:id="@+id/btn_reset"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/reset" />
<Button
android:id="@+id/btn_did"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="2dp"
android:text="DID" />

</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="horizontal">


<Button
android:id="@+id/btn_start_less"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/countdown" />

<Button
android:id="@+id/btn_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pause" />
<Button
android:id="@+id/btn_pause_less"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pause_less" />



</LinearLayout>

<TextView
android:id="@+id/tv_show_did"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18dp"
android:text="DID:"
/>

<TextView
android:id="@+id/tv_show_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18dp"
android:text="TIME:"
/>

<TextView
android:id="@+id/tv_show_result"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/black_theme"
android:textSize="28sp"
android:textStyle="bold" />
</LinearLayout>


+ 5
- 0
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

+ 5
- 0
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png View File


BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.png View File


BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png View File


BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.png View File


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png View File


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.png View File


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png View File


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png View File


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png View File


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png View File


+ 45
- 0
app/src/main/res/values-zh/strings.xml View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">营养秤SDK</string>

<string name="not_support_ble">您的设备支持BLE!</string>
<string name="scan_ing">正在扫描...</string>
<string name="ble_state_off">蓝牙已关闭!</string>
<string name="ble_state_on">蓝牙已开启!</string>
<string name="current_device">当前设备:%1$s</string>
<string name="current_version">当前版本:%1$s</string>
<string name="disconnected">已与设备断开连接。</string>
<string name="current_rssi">当前信号:%1$d</string>
<string name="no_rssi">当前信号:--</string>
<string name="ble_version">蓝牙版本:%1$s</string>
<string name="no_version">蓝牙版本:--</string>
<string name="default_rssi">过滤信号:%1$d</string>
<string name="cancel">取消</string>
<string name="query">确定</string>
<string name="dialog_set_rssi_title">设置蓝牙信号过滤值</string>
<string name="dialog_set_rssi_tips">30~120,值越小信号越强,推荐70</string>
<string name="rssi_not_null">信号值不能为空!</string>
<string name="rssi_error">请确认信号值在30~120范围内!</string>
<string name="rssi_set_success">设置成功!</string>
<string name="user_cancel">用户取消</string>
<string name="no_unit">当前单位:--</string>
<string name="current_unit">当前单位:%1$s</string>
<string name="current_unit_str">当前单位:</string>

<string name="pls_input_weight">请输入重量</string>
<string name="set_weight">设置重量</string>

<string name="zero">清零</string>
<string name="shut_down">关机</string>
<string name="get_version">获取版本</string>
<string name="get_units">获取单位列表</string>
<string name="timing">计时</string>
<string name="countdown">倒计时</string>
<string name="pause">暂停</string>
<string name="pause_less">倒计时暂停</string>
<string name="reset">重置</string>
<string name="write">透传</string>
<string name="hint">提示</string>
<string name="permissions">请求使用定位权限搜索蓝牙设备</string>
<string name="permissions_server">没有开启定位服务</string>
</resources>

+ 10
- 0
app/src/main/res/values/arrays.xml View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="Device_Unit">
<item>克(g)</item>
<item>毫升(ml)</item>
<item>磅(lb)</item>
<item>盎司(oz)</item>
<item>未知</item>
</array>
</resources>

+ 17
- 0
app/src/main/res/values/colors.xml View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>

<color name="system_theme">#39cea1</color>
<color name="system_theme_50">#8039cea1</color>
<color name="dark_system_theme">#24B884</color>
<color name="light_grey">#9b9b9b</color>
<color name="divider_bg">#d5d5d5</color>
<color name="black_theme">#000000</color>
<color name="dark_grey">#303030</color>
<color name="dark_grey_50">#30303030</color>
<color name="white_theme">#ffffff</color>

</resources>

+ 10
- 0
app/src/main/res/values/dimens.xml View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>

<!-- 标题栏 -->
<dimen name="activity_title_height">48dp</dimen>
<dimen name="activity_title_size">20sp</dimen>
<dimen name="activity_title_right_size">14sp</dimen>
<dimen name="activity_title_left_padding">20dp</dimen>

</resources>

+ 45
- 0
app/src/main/res/values/strings.xml View File

@@ -0,0 +1,45 @@
<resources>
<string name="app_name">PabulumSDK</string>

<string name="not_support_ble">Your device supports BLE!</string>
<string name="scan_ing">Scanning...</string>
<string name="ble_state_off">Bluetooth is off!</string>
<string name="ble_state_on">Bluetooth is on!</string>
<string name="current_device">Current device:%1$s</string>
<string name="current_version">current version:%1$s</string>
<string name="disconnected">Disconnected from device。</string>
<string name="current_rssi">Current signal:%1$d</string>
<string name="no_rssi">Current signal:--</string>
<string name="ble_version">Bluetooth version:%1$s</string>
<string name="no_version">Bluetooth version:--</string>
<string name="default_rssi">Filter signal:%1$d</string>
<string name="cancel">cancel</string>
<string name="query">determine</string>
<string name="dialog_set_rssi_title">Set the Bluetooth signal filter value</string>
<string name="dialog_set_rssi_tips">30~120, the smaller the value, the stronger the signal. 70 is recommended.</string>
<string name="rssi_not_null">Signal value cannot be empty!</string>
<string name="rssi_error">Please confirm that the signal value is in the range of 30~120!</string>
<string name="rssi_set_success">Successful setup!</string>
<string name="user_cancel">User canceled</string>
<string name="no_unit">Current unit:--</string>
<string name="current_unit">Current unit:%1$s</string>
<string name="current_unit_str">Current unit:</string>

<string name="pls_input_weight">Please enter the weight</string>
<string name="set_weight">Setting weight</string>

<string name="zero">zero</string>
<string name="shut_down">Shut down</string>
<string name="get_version">Get version</string>
<string name="timing">Timing</string>
<string name="countdown">Countdown</string>
<string name="pause">Pause</string>
<string name="pause_less">Countdown pause</string>
<string name="reset">Reset</string>
<string name="write">Penetrate</string>

<string name="hint">Prompt</string>
<string name="permissions">Request to search for Bluetooth devices with targeting permissions</string>
<string name="permissions_server">Location service is not turned on</string>
<string name="get_units">getUnits</string>
</resources>

+ 59
- 0
app/src/main/res/values/styles.xml View File

@@ -0,0 +1,59 @@
<resources>

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>


<style name="ActivityTitleIB">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:background">@drawable/activity_title_right</item>
<item name="android:padding">@dimen/activity_title_left_padding</item>
</style>

<style name="MyDialog" parent="android:Theme.Dialog">
<!--<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:background">@null</item>
<item name="android:windowFrame">@null</item>-->
<!-- 是否浮现在activity之上 -->
<item name="android:windowIsFloating">true</item>
<!-- 半透明 -->
<!--<item name="android:windowIsTranslucent">true</item>-->
<!-- 无标题 -->
<item name="android:windowNoTitle">true</item>
<!-- 模糊 -->
<item name="android:backgroundDimEnabled">true</item>
</style>

<style name="DialogWarningBtn">
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">1</item>
<item name="android:textSize">20sp</item>
<item name="android:textColor">@color/white_theme</item>
<item name="android:paddingTop">10dp</item>
<item name="android:paddingBottom">10dp</item>
</style>

<style name="Base_Text_View">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:padding">5dp</item>
<item name="android:textColor">@color/black_theme</item>
<item name="android:textSize">18sp</item>
</style>

<style name="Base_Radio_Button">
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">1</item>
<item name="android:padding">5dp</item>
</style>

</resources>

+ 17
- 0
app/src/test/java/aicare/net/cn/sdk/pabulumsdkrepositoryandroid/ExampleUnitTest.java View File

@@ -0,0 +1,17 @@
package aicare.net.cn.sdk.pabulumsdkrepositoryandroid;

import org.junit.Test;

import static org.junit.Assert.*;

/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

+ 27
- 0
build.gradle View File

@@ -0,0 +1,27 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.0'
classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}

allprojects {
repositories {
google()
jcenter()
}
}

task clean(type: Delete) {
delete rootProject.buildDir
}

+ 20
- 0
gradle.properties View File

@@ -0,0 +1,20 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true


BIN
gradle/wrapper/gradle-wrapper.jar View File


+ 6
- 0
gradle/wrapper/gradle-wrapper.properties View File

@@ -0,0 +1,6 @@
#Thu Apr 09 09:42:45 CST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip

+ 172
- 0
gradlew View File

@@ -0,0 +1,172 @@
#!/usr/bin/env sh

##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn () {
echo "$*"
}

die () {
echo
echo "$*"
echo
exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`

# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option

if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi

# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")

# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"

# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi

exec "$JAVACMD" "$@"

+ 84
- 0
gradlew.bat View File

@@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto init

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:init
@rem Get command-line arguments, handling Windows variants

if not "%OS%" == "Windows_NT" goto win9xME_args

:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2

:win9xME_args_slurp
if "x%~1" == "x" goto execute

set CMD_LINE_ARGS=%*

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega

+ 1
- 0
pabulumlibrary/.gitignore View File

@@ -0,0 +1 @@
/build

+ 46
- 0
pabulumlibrary/build.gradle View File

@@ -0,0 +1,46 @@
apply plugin: 'com.android.library'

android {
compileSdkVersion 29
buildToolsVersion "29.0.2"


defaultConfig {
minSdkVersion 19
targetSdkVersion 29
versionCode 1
versionName "1.2.6"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}


}

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

implementation 'androidx.appcompat:appcompat:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
api files('libs/AicareUtils.jar')
api files('libs/PabulumLibrary.jar')
}

BIN
pabulumlibrary/libs/AicareUtils.jar View File


BIN
pabulumlibrary/libs/PabulumLibrary.jar View File


BIN
pabulumlibrary/libs/arm64-v8a/libaicare-lib.so View File


BIN
pabulumlibrary/libs/armeabi-v7a/libaicare-lib.so View File


BIN
pabulumlibrary/libs/x86/libaicare-lib.so View File


BIN
pabulumlibrary/libs/x86_64/libaicare-lib.so View File


+ 21
- 0
pabulumlibrary/proguard-rules.pro View File

@@ -0,0 +1,21 @@
# 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

+ 27
- 0
pabulumlibrary/src/androidTest/java/aicare/net/cn/sdk/pabulumlibrary/ExampleInstrumentedTest.java View File

@@ -0,0 +1,27 @@
package aicare.net.cn.sdk.pabulumlibrary;

import android.content.Context;

import androidx.test.InstrumentationRegistry;
import androidx.test.runner.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.getTargetContext();

assertEquals("aicare.net.cn.sdk.pabulumlibrary.test", appContext.getPackageName());
}
}

+ 2
- 0
pabulumlibrary/src/main/AndroidManifest.xml View File

@@ -0,0 +1,2 @@
<manifest package="aicare.net.cn.sdk.pabulumlibrary"
xmlns:android="http://schemas.android.com/apk/res/android"/>

+ 3
- 0
pabulumlibrary/src/main/res/values/strings.xml View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">PabulumLibrary</string>
</resources>

+ 17
- 0
pabulumlibrary/src/test/java/aicare/net/cn/sdk/pabulumlibrary/ExampleUnitTest.java View File

@@ -0,0 +1,17 @@
package aicare.net.cn.sdk.pabulumlibrary;

import org.junit.Test;

import static org.junit.Assert.*;

/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

+ 1
- 0
settings.gradle View File

@@ -0,0 +1 @@
include ':app', ':pabulumlibrary'

Loading…
Cancel
Save