Project overview¶
Discover code¶
Important classes¶
- BtLEQueue (communication queue for Bluetooth LE devices)
- DeviceCommunicationService (Android service channeling the communication with devices)
- DeviceService ("client side API" of DeviceCommunicationService, see GBApplication#deviceService())
- GBDevice (generic, device-unspecific)
- DeviceCoordinator
- ControlCenterv2 (main activity)
Examples¶
Short article demonstrating adding a simple database/UI feature: Adding battery info screen to Gadgetbridge.
Overview¶
All the details about the communication/protocol with a concrete device (Pebble, Mi Band, ...) is inside the "Concrete Device Impl." component, that is, the concrete implementations of the DeviceSupport interface. Only the DeviceCommunicationService has access to those -- clients (typically Activities) talk to the DeviceService interface in order to communicate with the devices.
Bluetooth error codes¶
See here.
Logging¶
We use slf4j for logging, so just use LoggerFactory.getLogger(Your.class) and log away. The output will be written to the Android Log (so you can get it with logcat or Android Studio) as well as to the file /sdcard/Android/data/nodomain.freeyourgadget.gadgetbridge/files/gadgetbridge.log. File logging needs to be enabled in Gadgetbridge's preferences, first.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// ...
private static final Logger LOG = LoggerFactory.getLogger(Your.class);
// ...
LOG.error("Error accessing database", e);
GBDevice is cached in activities¶
Most activities receive the GBDevice via Intent during activity invocation. Be aware that the device in the activity is a copy of the device and thus it might not have the same updated information. So if you for example subscribe to device state updates and then want to get current data from the device (for example device.getBatteryLevel(), make sure to update the activities local copy of GBDevice:
BroadcastReceiver commandReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
LOG.debug("device receiver received " + intent.getAction());
if (intent.getAction().equals(GBDevice.ACTION_DEVICE_CHANGED)) {
GBDevice newDevice = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE);
if (newDevice.equals(device)) {
device = newDevice; // ← update local copy of the GBDevice
// Do your stuff here...
}
}
}
};
Information display¶
Use one of the nodomain.freeyourgadget.gadgetbridge.util.GB#toast() methods to display information to the user.
- The toast when given an exception also logs warnings and errors, so with the toast you not have to use "LOG" afterwards.
- Can safely be called from a background thread.
import nodomain.freeyourgadget.gadgetbridge.util.GB;
// ...
GB.toast("My toast message", Toast.LENGTH_SHORT, GB.ERROR, e);
Database¶
We use greenDAO for database access. See nodomain.freeyourgadget.gadgetbridge.daogen.GBDaoGenerator for entity definition and generation. Do note that we use greenDAO in version 2, the official greenDAO documentation already mentions version 3.
To add a column to a database, simply add a new field to a particular class in nodomain.freeyourgadget.gadgetbridge.daogen.GBDaoGenerator, then build the project, which will trigger generating of corresponding ...dao.class files. Also, make sure to set a new schema version Schema schema = new Schema(xx... and prepare a migration file in src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/.
Icons¶
All icons should be provided as vector drawables, do not use PNGs anymore. If you are drawing the original design in SVG, make sure to export as regular uncompressed SVG, because Android Studio handles these files better. Then, import it to Android Studio via right click in "Project panel → New → Vector Asset → Local file". Then, use Avocado optimizer for Android VectorDrawable (VD) and AnimatedVectorDrawable (AVD) XML files. Avocado rewrites the VectorDrawable using the smallest number of <group>s and <path>s possible, reducing their file sizes and making them faster to parse and draw at runtime.
Device icons¶
For device icons (ic_device_xxx, ic_device_xxx_disabled), start from an existing icon's SVG source, you can use the Galaxy Buds icon, here is the source for the normal state and here for the disabled state. Modify this SVG (remove the buds and draw the device you need), save, then import into Android Studio as described above, then optimize with avocado. Then, in Android Studio, change the dimensions inside the XML file to this:
And if you want to optimize it even further, change the strokeWidth to remove unnecessary precision, for example from strokeWidth="0.498675" to strokeWidth=0.5". Look at the other device icons for examples.
Colors¶
The colors.xml defines colors which are then used throughout the app. See also styles.xml.
| Color | Name | Usage |
|---|---|---|
#FF3D00
| primary_light | Windows & text |
#FF3D00
| primary_light | Windows & text |
#DD2C00
| primarydark_light | Windows & text |
#FF3D00
| primary_dark | Windows & text |
#DD2C00
| primarydark_dark | Windows & text |
#0091EA
| accent | Windows & text |
#000000
| primarytext_light | Windows & text |
#FFFFFF
| primarytext_dark | Windows & text |
#FF808080
| secondarytext | Windows & text |
#FFD0D0D0
| tertiarytext_light | Windows & text |
#FF606060
| tertiarytext_dark | Windows & text |
#000000
| tertiarytext_black | Windows & text |
#1F000000
| divider | Windows & text |
#FFAB40
| chart_heartrate | Charts |
#8B0000
| chart_heartrate_alternative | Charts |
#FADAB1
| chart_heartrate_fill | Charts |
#0071B7
| chart_deep_sleep_light | Charts |
#4C5AFF
| chart_deep_sleep_dark | Charts |
#46ACEA
| chart_light_sleep_light | Charts |
#B6BFFF
| chart_light_sleep_dark | Charts |
#60BD6D
| chart_activity_light | Charts |
#59B22C
| chart_activity_dark | Charts |
#545254
| chart_not_worn_light | Charts |
#D8D9D8
| chart_not_worn_dark | Charts |
#FFEDEDED
| alternate_row_background_light | Tables |
#545254
| alternate_row_background_dark | Tables |
Preferences¶
Preferences that are not specific to the user's device but are for the whole application are in:
User's device specific preferences - that is, each devices own preferences, go into:
See Device-Specific Settings for more information on how to create device-specific preferences.
Adding a feature¶
The Adding battery info screen to Gadgetbridge blog post is a friendly documentation of the steps needed to add a new feature to Gadgetbridge and it touches on several important parts, adding a new database table, hooking up device Bluetooth events, storing data, adding a chart screen and so on.
Translations¶
Do not add translations by editing the language variants of strings.xml directly as this creates merge conflicts between Codeberg Git repo and Weblate Git repository. Always use Weblate, as per info in the website.
Copyright¶
All source files should contain the relevant copyright header. As an example, for Java files created specifically for Gadgetbridge:
/*
Copyright (C) 2023 John Smith(1)
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
- A real name is not mandatory - a nickname can be used.
For source code copied or adapted from other opensource projects, the relevant copyright header should be kept, not violating that project's license.