Skip to content

Android

🚀 Preparation

Hardware Connection Guide

For device power operations, LED indicator meanings, and device pairing instructions across all SDKs, please consult the FAQ first before starting development: Device Setup & FAQ.

Requirements

  • OS: Your host project's minSdkVersion must be set to 18 (Android 4.3) or higher.
  • Hardware Limitations: Supports Bluetooth Low Energy (BLE 4.0+).

⚠️ Real Device Requirement

Since the official Android Emulator does not support low-level Bluetooth hardware drivers, you must use a physical Android device connected via a data cable to run the demo app and your project for actual debugging (not mocked data). Otherwise, scanning for peripherals will always return empty results.

Installation & Integration

Import SDK (Maven Repository)

We recommend using the BrainCo Maven repository to import the OxyZen / Zenlite SDK.

1. Configure Repository Address Edit build.gradle (or settings.gradle in newer Android Studio projects) at the root level of your project and add the private repository credentials:

groovy
repositories {
    maven {
        credentials {
            username '<maven-username>'
            password '<maven-password>'
        }
        url = "https://nexus.ci.brainco.cn/repository/maven-public"
    }
}

2. Add Remote Dependency
In your app module (usually app/build.gradle), import the SDK dependency:

groovy
dependencies {
    implementation 'tech.brainco:zenlitejna:1.5.2'  // Or the newest version
}

Required Permissions

Add the following to your AndroidManifest.xml:

xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.xxx.xxx">
    
    <!-- Bluetooth permissions for Android 11 and below -->
    <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
    
    <!-- Location permission required for BLE scanning -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    
    <!-- Dynamic Bluetooth permissions for Android 12+ -->
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
</manifest>

ProGuard Configuration

If you use code obfuscation (ProGuard/R8), please add the following rules to proguard-rules.pro to prevent low-level dependencies (like JNA / DFU) from being removed:

properties
-dontwarn java.awt.*
-keep class no.nordicsemi.android.dfu.** { *; }
-keep class com.sun.jna.* { *; }
-keepclassmembers class * extends com.sun.jna.* { public *; }

Core API Reference

ZenliteSDK (Class)

Global SDK basic configuration management:

java
public class ZenliteSDK {
    // Start scanning
    public static void startScan(ZenliteDeviceScanListener listener, List<ScanFilter> filters);
    
    // Stop scanning
    public static void stopScan();
    
    // Register / Unregister Bluetooth state receiver
    public static void registerBLEStateReceiver(Context context);
    public static void unregisterBLEStateReceiver(Context context);
    
    // Set the log level
    public static void setLogLevel(LogLevel level);
}

ZenliteDevice (Class)

The core device object encapsulating device control and data communication:

java
public class ZenliteDevice {
    // Connection
    public void connect(Context context);
    public void disconnect();
    public boolean isConnected();
    public boolean isDisconnected();
    public boolean isConnecting();
    public boolean isDisconnecting();
    
    // Auth & Pair
    public void pair(boolean requireAuth, ZenliteResponseCallback callback);

    // EEG Data Stream
    public int startEEGStream(EEGSampleRate sampleRate, ZenliteResponseCallback callback);
    public int stopEEGStream(ZenliteResponseCallback callback);
    
    // IMU Data Stream
    public int startIMU(IMUSampleRate sampleRate, IMUMode mode, ZenliteResponseCallback callback);
    public int stopIMU(ZenliteResponseCallback callback);
    
    // PPG / Heart Rate Stream
    public int startPPG(PPGReportRate reportRate, PPGMode mode, int rawSetReg, int rawSetVal, ZenliteResponseCallback callback);
    public int stopPPG(ZenliteResponseCallback callback);

    // System Control Commands
    public int setDeviceName(String name, ZenliteResponseCallback callback);
    public int setSleepIdleTime(int timeSec, ZenliteResponseCallback callback);

    // State Queries
    public void getSysInfo(OnSysInfoCallback callback);
    public void readRssi(OnRssiCallback successCb, OnRssiCallback failureCb);
    
    // State Constants 
    public String getName();
    public String getID(); // MAC Address
    public int getBatteryLevel(); 
    public String getHardwareRevision();
    public String getFirmwareRevision();
}

IZenliteDeviceListener (Interface)

Listener used to receive device events and algorithm indicators:

java
public interface IZenliteDeviceListener {
    // Info & States
    void OnDeviceInfo(ZenliteDevice device, ZenliteDeviceInfo info);
    void OnConnectivityChanged(ZenliteDevice device, int connectivity); // Connectivity enum
    
    // Physical Characteristics Layer
    void OnContactStateChanged(ZenliteDevice device, int contactState); // DeviceContactState enum
    void OnOrientationChanged(ZenliteDevice device, int orientation);   // DeviceOrientation enum
    
    // Exception
    void OnError(ZenliteDevice device, ZenliteError error);
    
    // Data Callbacks
    void OnEEGData(ZenliteDevice device, EEG eeg);
    void OnRawEEGData(ZenliteDevice device, EEGData rawEeg);
    void OnBrainWave(ZenliteDevice device, BrainWave wave);
    
    void OnIMUData(ZenliteDevice device, IMU imu);
    void OnPPGData(ZenliteDevice device, PPGData ppgData);
    
    // Physiological Indicators 
    void OnAttention(ZenliteDevice device, double attention, double weightedAttention);
    void OnMeditation(ZenliteDevice device, double meditation, double calmness, double awareness);
    void OnSleepStage(ZenliteDevice device, int sleepStage, double confidence, double drowsiness);
    
    void OnEvent(ZenliteDevice device, DeviceEvent event);
    void OnBlink(ZenliteDevice device);
}

Data Models

EEG (Brainwave Data)

java
public class EEG {
    public float getSampleRate();    // Sample Rate (Hz)
    public float[] getData();        // Microvolts array
}

public class BrainWave {
    public double getDelta();      // 0.5-4 Hz
    public double getTheta();      // 4-8 Hz
    public double getAlpha();      // 8-13 Hz
    public double getLowBeta();    // 13-20 Hz
    public double getHighBeta();   // 20-30 Hz
    public double getGamma();      // 30-50 Hz
}

IMU (Inertial Measurement Unit Data)

java
public class IMU {
    public float getSampleRate();
    public ACC getAcc();              
    public Gyro getGyro();             
    public EulerAngle getEulerAngle();
}

PPG Data (Heart Rate/SpO2)

java
public class PPGData {
    public int seqNum;           // Sequence number
    public double reportRate;    // Report frequency
    public List<PPGRawItem> rawDataList;   // Raw readings
    public List<PPGAlgoItem> algoDataList; // Computed algorithm results
    public double respiratoryRate; // Respiration
}

public class PPGAlgoItem {
    public double hr;            // Heart rate (bpm)
    public int hrConf;           // Heart rate confidence (0-100%)
    public double rr;            // Respiration rate
    public double spo2;          // SpO2
    public int spo2Conf;         // SpO2 confidence (0-100%)
    public double hrv;           // HRV
}

Enums / Constants

Connectivity and Physical Contact

java
public class Connectivity {
    public static final int CONNECTING = 0;
    public static final int CONNECTED = 1;
    public static final int DISCONNECTING = 2;
    public static final int DISCONNECTED = 3;
}

public class DeviceContactState {
    public static final int UNKNOWN = 0;
    public static final int OFF = 1;      // Poor contact
    public static final int EEG = 2;      // Good EEG contact
    public static final int ALL = 3;      // Both EEG and PPG are well-contacted
}

public class DeviceOrientation {
    public static final int UNKNOWN = 0;
    public static final int UPWARD = 1;    // Correct orientation
    public static final int DOWNWARD = 2;  // Upside down
}

Sensor Sample Rates and Working Modes

java
public class EEGSampleRate {
    public static final int OFF = 1;     // Turn off EEG
    public static final int SR_128 = 2;  // 128 Hz
    public static final int SR_256 = 3;  // 256 Hz
}

public class IMUSampleRate {
    public static final int OFF = 1;     
    public static final int SR_25 = 2;   // 25 Hz
    public static final int SR_50 = 3;   // 50 Hz
}

public class IMUMode {
    public static final int NONE = 0;    // Turn off
    public static final int ACC = 1;     // Accelerometer only
    public static final int GYRO = 2;    // Gyroscope only
    public static final int ACC_GYRO = 3; // ACC + GYRO
    public static final int EULER = 4;   // Euler angle calculated
}

public class PPGMode {
    public static final int RAW_DATA = 1;    // Raw reading only
    public static final int ALGO = 2;        // Computed indicators (HR, SpO2)
}

Troubleshooting & Considerations

Common Connection and Pairing Issues

If you encounter scenarios such as "cannot scan the device", "connection failed", or "pairing failed", please refer to the troubleshooting guidelines in our global FAQ: 👉 Device Setup & FAQ

Android Development Considerations

  • System Permissions & Background Execution Policy:
    • Android 12 and above introduces stricter nearby device permission management. Before using peripheral features, ensure you have correctly requested BLUETOOTH_SCAN and BLUETOOTH_CONNECT permissions and handled the user response appropriately.
    • Background Cleanup and App Suspension: If your application requires long-duration scanning and data reception while the screen is locked or in the background, you must spin up a Foreground Service (bound with a persistent notification bar).
  • UI Thread Updates: All data callbacks in the SDK (e.g., OnEEGData and algorithm indicators) are guaranteed to be triggered on a Background IO Thread. If you need to write incoming high-frequency data to the UI (such as redrawing charts), developers must perform safe thread cross-dispatching (like runOnUiThread).

📖 Complete Integration Example

We provide a comprehensive open-source Android sample application demonstrating the lifecycle invocation structure, permission configurations on modern Android operating systems, and Bluetooth re-connection routines.

Check the specific code and full application layer implementations here:

👉 OxyZen Android Example Repository