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
minSdkVersionmust 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:
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:
dependencies {
implementation 'tech.brainco:zenlitejna:1.5.2' // Or the newest version
}Required Permissions
Add the following to your AndroidManifest.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:
-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:
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:
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:
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)
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)
public class IMU {
public float getSampleRate();
public ACC getAcc();
public Gyro getGyro();
public EulerAngle getEulerAngle();
}PPG Data (Heart Rate/SpO2)
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
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
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_SCANandBLUETOOTH_CONNECTpermissions 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).
- Android 12 and above introduces stricter nearby device permission management. Before using peripheral features, ensure you have correctly requested
- UI Thread Updates: All data callbacks in the SDK (e.g.,
OnEEGDataand 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 (likerunOnUiThread).
📖 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:
