Skip to content

Project overview

Discover code

Important classes

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:

android:width="45sp"
android:height="45sp"
android:viewportWidth="30"
android:viewportHeight="30"

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:

GBPrefs prefs = GBApplication.getPrefs();

User's device specific preferences - that is, each devices own preferences, go into:

DevicePrefs prefs = GBApplication.getDevicePrefs(gbDevice);

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.

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/>.
*/
  1. 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.