From 2cb5844020a4df0e7eb29180b32a8d93e76fbdd8 Mon Sep 17 00:00:00 2001 From: gfwilliams Date: Thu, 31 Mar 2022 11:36:26 +0200 Subject: [PATCH] Bangle.js build flavor (#2621) This PR adds build flavors to `build.gradle`. The default is called `main`, but we also add `banglejs` which allows the building of an app called `Bangle.js Gadgetbridge`. This will have internet connectivity, allowing Bangle.js watches to request data directly from the internet - and it's named so as hopefully not to be confused with the normal offline Gadgetbridge, while still giving credit. Eventually the plan is to put this on the Google Play store, and to have additions in it which are good for Bangle.js users but would otherwise negatively impact normal Gadgetbridge users (a build flavor is used so we can keep the same codebase and not fork). About naming - I'd mentioned `Gadgetbridge for Bangle` to @ashimokawa but thinking about how it would appear in the app store and Android apps list, it probably makes sense to call it `Bangle.js Gadgetbridge` so it's listed under `B...`. Happy to change or use something else if you have strong opinions though. **Note:** adding build flavors seems to add the flavor name to existing builds. As a result, *all other builds will now have `main` in the name*. Unfortunately I didn't see another way around this, but hopefully it won't break anything. Co-authored-by: Gordon Williams Reviewed-on: https://codeberg.org/Freeyourgadget/Gadgetbridge/pulls/2621 Co-authored-by: gfwilliams Co-committed-by: gfwilliams --- README.md | 1 + app/build.gradle | 23 ++++++ app/src/banglejs/AndroidManifest.xml | 5 ++ .../res/drawable/ic_launcher_foreground.xml | 72 +++++++++++++++++++ app/src/banglejs/res/values/strings.xml | 8 +++ .../activities/ControlCenterv2.java | 7 ++ .../banglejs/BangleJSDeviceSupport.java | 69 +++++++++++++++--- 7 files changed, 176 insertions(+), 9 deletions(-) create mode 100644 app/src/banglejs/AndroidManifest.xml create mode 100644 app/src/banglejs/res/drawable/ic_launcher_foreground.xml create mode 100644 app/src/banglejs/res/values/strings.xml diff --git a/README.md b/README.md index 3eb5905e6..a264f89d8 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ vendor's servers. - T-Rex [**\[!\]**](#special-pairing-procedures) - Verge Lite [**\[!\]**](#special-pairing-procedures) - [X ](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Mi-Band-5) [**\[!\]**](#special-pairing-procedures) +- [Bangle.js](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Bangle.js) - BFH-16 - [Casio](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Casio) - Casio GB-X6900B diff --git a/app/build.gradle b/app/build.gradle index 80fe1036d..ee4ef5613 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -60,6 +60,7 @@ android { vectorDrawables.useSupportLibrary = true multiDexEnabled true buildConfigField "String", "GIT_HASH_SHORT", "\"${getGitHashShort()}\"" + buildConfigField "boolean", "INTERNET_ACCESS", "false" resValue "string", "pebble_content_provider", "com.getpebble.android.provider" } signingConfigs { @@ -121,6 +122,27 @@ android { } + flavorDimensions "device_type" + productFlavors { + main { + // Ensure that when starting from scratch, 'main' is selected, not 'banglejs' + getIsDefault().set(true) + // the default build product flavor + dimension "device_type" + //applicationIdSuffix "" + //versionNameSuffix "" + } + banglejs { + dimension "device_type" + applicationId "com.espruino.gadgetbridge" + applicationIdSuffix ".banglejs" + versionNameSuffix "-banglejs" + buildConfigField "boolean", "INTERNET_ACCESS", "true" + // Disable pebble provider to allow Bangle.js Gadgetbridge to coexist with Gadgetbridge + resValue "string", "pebble_content_provider", "com.getpebble.android.nopebble.provider" + } + } + lintOptions { abortOnError ABORT_ON_CHECK_FAILURE lintConfig file("${project.rootDir}/config/lint/lint.xml") @@ -195,6 +217,7 @@ dependencies { implementation 'com.github.wax911:android-emojify:0.1.7' implementation 'com.google.protobuf:protobuf-lite:3.0.1' implementation "androidx.multidex:multidex:2.0.1" + implementation 'com.android.volley:volley:1.2.1' } preBuild.dependsOn(":GBDaoGenerator:genSources") diff --git a/app/src/banglejs/AndroidManifest.xml b/app/src/banglejs/AndroidManifest.xml new file mode 100644 index 000000000..8478e0e63 --- /dev/null +++ b/app/src/banglejs/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/banglejs/res/drawable/ic_launcher_foreground.xml b/app/src/banglejs/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 000000000..92a455296 --- /dev/null +++ b/app/src/banglejs/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/banglejs/res/values/strings.xml b/app/src/banglejs/res/values/strings.xml new file mode 100644 index 000000000..e965e9764 --- /dev/null +++ b/app/src/banglejs/res/values/strings.xml @@ -0,0 +1,8 @@ + + + Bangle.js Gadgetbridge + Bangle.js Gadgetbridge + About Bangle.js Gadgetbridge + Android companion app for Bangle.js built on top of the Gadgetbridge project, with added Internet Access. + Bangle.js running + diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenterv2.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenterv2.java index 2b2e82205..e63c4d23e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenterv2.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenterv2.java @@ -65,6 +65,7 @@ import java.util.Set; import de.cketti.library.changelog.ChangeLog; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.BuildConfig; import nodomain.freeyourgadget.gadgetbridge.adapter.GBDeviceAdapterv2; import nodomain.freeyourgadget.gadgetbridge.database.DBAccess; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; @@ -438,6 +439,12 @@ public class ControlCenterv2 extends AppCompatActivity } } + if (BuildConfig.INTERNET_ACCESS) { + if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.INTERNET) == PackageManager.PERMISSION_DENIED) { + wantedPermissions.add(Manifest.permission.INTERNET); + } + } + if (!wantedPermissions.isEmpty()) { Prefs prefs = GBApplication.getPrefs(); // If this is not the first run, we can rely on diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/banglejs/BangleJSDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/banglejs/BangleJSDeviceSupport.java index 73fb64da3..e79089800 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/banglejs/BangleJSDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/banglejs/BangleJSDeviceSupport.java @@ -31,6 +31,13 @@ import android.widget.Toast; import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import com.android.volley.Request; +import com.android.volley.Response; +import com.android.volley.RequestQueue; +import com.android.volley.VolleyError; +import com.android.volley.toolbox.StringRequest; +import com.android.volley.toolbox.Volley; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -270,6 +277,39 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport { LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent); } } break; + case "http": { + // FIXME: This should be behind a default-off option in Gadgetbridge settings + RequestQueue queue = Volley.newRequestQueue(getContext()); + String url = json.getString("url"); + // Request a string response from the provided URL. + StringRequest stringRequest = new StringRequest(Request.Method.GET, url, + new Response.Listener() { + @Override + public void onResponse(String response) { + JSONObject o = new JSONObject(); + try { + o.put("t", "http"); + o.put("resp", response); + } catch (JSONException e) { + GB.toast(getContext(), "HTTP: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR); + } + uartTxJSON("http", o); + } + }, new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + JSONObject o = new JSONObject(); + try { + o.put("t", "http"); + o.put("err", error.toString()); + } catch (JSONException e) { + GB.toast(getContext(), "HTTP: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR); + } + uartTxJSON("http", o); + } + }); + queue.add(stringRequest); + } break; } } @@ -628,23 +668,34 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport { /** Convert a drawable to a bitmap, for use with bitmapToEspruino */ public static Bitmap drawableToBitmap(Drawable drawable) { + final int maxWidth = 32; + final int maxHeight = 32; + /* Return bitmap directly but only if it's small enough. It could be + we have a bitmap but it's just too big to send direct to the bangle */ if (drawable instanceof BitmapDrawable) { BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; - if (bitmapDrawable.getBitmap() != null) { - return bitmapDrawable.getBitmap(); - } + Bitmap bmp = bitmapDrawable.getBitmap(); + if (bmp != null && bmp.getWidth()<=maxWidth && bmp.getHeight()<=maxHeight) + return bmp; } - int w = 24; - int h = 24; + /* Otherwise render this to a bitmap ourselves.. work out size */ + int w = maxWidth; + int h = maxHeight; if (drawable.getIntrinsicWidth() > 0 && drawable.getIntrinsicHeight() > 0) { w = drawable.getIntrinsicWidth(); h = drawable.getIntrinsicHeight(); - // don't allocate anything too big - if (w>24) w=24; - if (h>24) h=24; + // don't allocate anything too big, but keep the ratio + if (w>maxWidth) { + h = h * maxWidth / w; + w = maxWidth; + } + if (h>maxHeight) { + w = w * maxHeight / h; + h = maxHeight; + } } + /* render */ Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel - Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas);