This document provides a technical overview of the Android application for the Remote Switch project.
| Item | Specification |
|---|---|
| Language | Java |
| Minimum SDK | API 29 (Android 10.0 Q) |
| Build Tool | Gradle |
| Permissions | BLUETOOTH_SCAN, BLUETOOTH_CONNECT, ACCESS_FINE_LOCATION |
The app is designed with a modular approach, separating responsibilities into different manager classes that are orchestrated by the main activity.
-
MainActivity.javaThe central hub of the application. Its primary responsibilities are:- Managing the UI and handling user input from buttons.
- Requesting necessary Bluetooth permissions at runtime.
- Orchestrating the
BleScanManagerandBleConnectManager. - Implementing listener interfaces to receive callbacks from the managers and update the UI state.
- Managing the overall application state (e.g., scanning, connected).
- Managing the bonding status.
- Dealing with reset logic.
-
BleScanManager.javaA dedicated class for handling BLE scanning.- Responsibility: To scan for a BLE device with the specific name "Remote Switch".
- Mechanism: It uses the
BluetoothLeScannerand is configured with aScanFilterto find the target device efficiently. It notifiesMainActivityof results via theOnDeviceFoundListenerinterface.
-
BleConnectManager.javaHandles all aspects of the GATT connection and data transfer.- Responsibility: Connect to a given
BluetoothDevice, discover its services and characteristics, enable notifications, and provide methods for writing data. - Mechanism: It implements the
BluetoothGattCallbackto handle all asynchronous BLE events like connection state changes, service discovery, and characteristic writes.
- Responsibility: Connect to a given
-
AndroidManifest.xmlDeclares the fundamental properties of the app.- Permissions: Crucially, it requests
BLUETOOTH_SCANandBLUETOOTH_CONNECTfor Android 12+, and legacyBLUETOOTH,BLUETOOTH_ADMIN, andACCESS_FINE_LOCATIONfor older versions. - Features: Declares that the app requires
android.hardware.bluetooth_le, preventing it from being installed on devices without BLE support.
- Permissions: Crucially, it requests
- User taps the Scan button.
MainActivitycallsbleScanManager.startScan()which:- Checks for
BLUETOOTH_SCANpermission - Sets up a scan filter for the device name "Remote Switch"
- Starts BLE scanning with low latency mode
- Sets a 15-second timeout handler
- Checks for
- When the device is found,
bleScanManager'sleScanCallbacktriggers:- Logs device details (MAC, RSSI)
- Stops scanning immediately
- Calls the
onDeviceFound()callback inMainActivity
- In
MainActivity.onDeviceFound():- Updates UI to show found status
- Checks bond state via
device.getBondState() - If not bonded (
BOND_NONE):- Calls
device.createBond()to initiate pairing - Shows "Bonding..." status
- Calls
- If already bonded (
BOND_BONDED):- Enables Connect button
- Shows "Bonded" status
- Bonding process:
- System handles the actual pairing dialog
MainActivity'sBroadcastReceiverlistens forACTION_BOND_STATE_CHANGED- On successful bonding (
BOND_BONDED):- Calls
saveDevice()to persist MAC address - Updates UI to show bonded status
- Enables Connect button
- Disables Scan button
- Calls
- On bond removal (
BOND_NONE):- Calls
clearSavedDevice() - Resets UI to initial state
- Calls
- Device persistence:
saveDevice()stores MAC address inSharedPreferencesunder "Bond Information"restoreDevice()(called at startup):- Retrieves MAC from
SharedPreferences - Gets device reference via
bluetoothAdapter.getRemoteDevice() - Verifies bond state matches
- Falls back to searching bonded devices by name
- Retrieves MAC from
clearSavedDevice():- Removes bond via reflection (
removeBond()) - Clears
SharedPreferencesentry - Resets device reference
- Updates UI
- Removes bond via reflection (
- Reset process:
- User taps Reset button
- Calls
clearSavedDevice() - After 500ms delay, calls
initializeStatus()to:- Reset all UI elements
- Re-enable scanning
- Prepare for new device connection
- User taps the Connect button.
MainActivityinstantiatesBleConnectManagerand callsbleConnectManager.connect()which:- Checks for
BLUETOOTH_CONNECTpermission - Initiates GATT connection with
autoConnect=false
- Checks for
- The
onConnectionStateChangecallback in the manager is triggered:- On
STATE_CONNECTED: Callsgatt.discoverServices() - On
STATE_DISCONNECTED: Cleans up resources and notifies UI
- On
onServicesDiscoveredis called:- Locates both required services (
SERVICE_UUID_TIMESYNCandSERVICE_UUID_SERVOCONTROL) - Retrieves characteristics (
phoneTimeCharacteristicandservoSignalCharacteristic) - Validates both characteristics exist before proceeding
- Locates both required services (
- Upon successful discovery:
- Calls
listener.onDeviceConnected() MainActivityenables control buttons and callswriteCurrentTime()
- Calls
- Time sync process:
- Formats current time as "HH:mm:ss"
- Writes to
phoneTimeCharacteristicwithWRITE_TYPE_DEFAULT
- When write completes:
onCharacteristicWritelogs success- Calls
listener.onTimeSynced() MainActivityshows sync confirmation toast
- User taps ON or OFF button
MainActivitycallsbleConnectManager.sendServoCommand()with:- "on" → sends "1" to characteristic
- "off" → sends "0" to characteristic
- In
BleConnectManager:- Validates GATT connection and characteristic availability
- Sets characteristic value based on command
- Uses
WRITE_TYPE_DEFAULTfor reliable delivery
- On write completion:
onCharacteristicWritelogs the sent command- ESP32 receives value and activates corresponding servo
- User taps Help button in
MainActivity MainActivitylaunchesHelpActivityvia explicit IntentHelpActivity.onCreate():- Sets up back button in action bar
- Loads help text from
assets/help_text.txt - Sets click listener for settings button
- Help text loading:
- Reads file line-by-line via
BufferedReader - Falls back to error message if file missing
- Reads file line-by-line via
- Settings button:
- Opens app-specific system settings
- Uses
Settings.ACTION_APPLICATION_DETAILS_SETTINGSIntent
- Back navigation:
- Handled automatically via action bar back button
- Returns to
MainActivitypreserving state
- Initial permission check in
MainActivity.onCreate():- Calls
requestBluetoothPermissions()
- Calls
- Permission handling:
- Android 12+ (
S+): RequestsBLUETOOTH_SCANandBLUETOOTH_CONNECT - Android 11-: Requests
ACCESS_FINE_LOCATION(legacy requirement)
- Android 12+ (
- Permission results:
- Handled in
onRequestPermissionsResult() - Verifies all requested permissions granted
- Shows toast and stops app if denied
- Handled in
- Runtime checks:
- Before scanning: Verifies
BLUETOOTH_SCAN - Before connecting: Verifies
BLUETOOTH_CONNECT - Gracefully handles denial with error messages
- Before scanning: Verifies
- Fallback behavior:
- Critical operations disabled without permissions
- User prompted to grant via system dialog
- Settings button in HelpActivity provides alternative access