Migrate from Bazel

This commit is contained in:
Marc Plano-Lesay 2025-12-12 15:30:04 +11:00
commit 016dbd0814
Signed by: kernald
GPG key ID: 66A41B08CC62A6CF
59 changed files with 7044 additions and 0 deletions

View file

@ -0,0 +1,436 @@
+++
template = "article.html"
title = "Android Things: first look"
date = 2017-01-06T10:55:08+01:00
description = "An introduction to Android Things, Google's IoT platform that brings the Android ecosystem to embedded devices."
[taxonomies]
tags = ["android", "iot"]
+++
## What is Android Things?
Android Things is an alternative Android version, announced at Google I/O 2015,
and released as a first developer preview in December 2016. Its purpose is to
develop embedded IoT devices, with a known and widely documented Android
ecosystem basis.
It's currently running on three different boards: the Intel Edison, the NXP Pico
i.MX6UL, and the Raspberry Pi 3. Some higher-end boards are coming soon.
On the SDK side, Android Things comes with a specific support library to ease
low-level hardware usage. It consists in two parts: the Peripheral I/O API,
which supports GPIO, PWM, I2C, SPI and UART, and the User Driver API, which
allows a developer to write a hardware-specific, high-level driver, to ease
hardware reusability by injecting events into the Android framework. Other
applications can in turn use those events without having to interact with the
hardware directly.
There's a downside: the bundled Android is not as complete as the one you can
find on a phone. Most of the standard applications aren't installed (Calendar,
Phone…), and standard content providers are absent too (MediaProvider,
Dictionary…).
Android Things supports displays, with the default Android UI toolkit. However,
the display is a bit different from what you're used to seeing on an Android
device: there's no notification bar, navigation bar or anything, the running
application will use the full display. That is, if it uses it at all: displays
are purely optional.
<!--more-->
## Installing Android Things
Installation depends on the device you're targeting. Up-to-date, device-specific
instructions are available in [the official
documentation](https://developer.android.com/things/hardware/developer-kits.html).
Note that there is no emulator available (yet?), you'll need to install Android
Things on a real board.
The next steps of this post assume your local adb is connected to your device
(that is, `adb devices` is listing it as attached).
## Creating a new application
Android Things uses the same Activity, Service… lifecycles you're used to
seeing in any Android application. As so, creating an Android Things project is
really close to creating an Android one:
- create a blank project on Android Studio (selecting a form factor is
mandatory, and Android Studio doesn't support Things yet, keep Phone
and Tablet selected), without any activities
- in the `build.gradle`, remove all the dependencies and add the Things support
library:
```groovy
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "fr.enoent.mything"
minSdkVersion 24
targetSdkVersion 24
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
provided 'com.google.android.things:androidthings:0.1-devpreview'
}
```
- add a reference to the Things support library in the `AndroidManifest.xml`:
```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="fr.enoent.mything">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name">
<uses-library
android:name="com.google.android.things"/>
</application>
</manifest>
```
- the last step is to create an Activity: create a new blank, without layout,
non-support Activity from Android Studio. You'll also need to add a
Things-specific intent-filter to this Activity in the Manifest, so it will
start automatically on boot. Keep the Launcher intent-filter to make it easier
to start this Activity from Android Studio:
```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="fr.enoent.mything">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name">
<uses-library
android:name="com.google.android.things"/>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<!-- Launch activity automatically on boot -->
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.IOT_LAUNCHER"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
</manifest>
```
Now you have an Activity, which is supposed to start automatically on boot.
Let's check that by adding a log in the `onCreate` method:
*MainActivity.java*
```java
public class MainActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("MainActivity", "onCreate");
}
}
```
As you can see, it's perfectly standard Android code.
You can run it from Android Studio, and you should see the `onCreate` mention in
the logs.
## Lights, action!
I won't cover Android UI in this post, as it's something really standard you can
already find all over the web. Let's do a much more fun UI: a blinking LED to
indicate the application is running.
### Connecting the LED
I only have a Raspberry Pi 3, so I won't be able to cover the other boards for
this part. You can find the Pi pinout details
[here](https://developer.android.com/things/hardware/raspberrypi-io.html).
The circuit is dead simple: connect the LED's cathode to Pi's ground, a small
resistor in series with your LED's anode (Pi's GPIOs are 3v3), and the other
side of the resistor to the Pi's BCM6. You can use any pin labelled as GPIO in
the diagram.
### Pimp your 'droid
Time to go back to Android Studio. First step: listing the available GPIOs on
your board. There's a new class in the support library to access the GPIOs:
`PeripheralManagerService`.
*MainActivity.java*
```java
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PeripheralManagerService service = new PeripheralManagerService();
Log.d("MainActivity", "Available GPIOs: " + service.getGpioList());
}
```
This code will list all the GPIOs we're allowed to use. On a Pi, hopefully
you'll find the BCM6 pin you connected the LED to. Here's the output on a Pi 3:
```
Available GPIOs: [BCM12, BCM13, BCM16, BCM17, BCM18, BCM19, BCM20, BCM21,
BCM22, BCM23, BCM24, BCM25, BCM26, BCM27, BCM4, BCM5, BCM6]
```
The next step is to initialize this GPIO. We'll use the
`PeripheralManagerService` once more to get a reference to it, then set it up to
`LOW` (0v) by default:
*MainActivity.java*
```java
private static final String GPIO_PIN_NAME_LED = "BCM6";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PeripheralManagerService service = new PeripheralManagerService();
try {
Gpio ledGpio = service.openGpio(GPIO_PIN_NAME_LED);
ledGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
} catch (IOException e) {
Log.e("MainActivity", "Error on PeripheralIO API", e);
}
}
```
Now, the only thing left to do is to toggle the GPIO value. This is a single
call: `ledGpio.setValue(!ledGpio.getValue());`. Toggling it every second comes
with a purely Android-oriented solution: a `Handler`, and a delayed
`Runnable`.
*MainActivity.java*
```java
public class MainActivity extends Activity {
private static final int INTERVAL_BETWEEN_BLINKS_MS = 1000;
private static final String GPIO_PIN_NAME_LED = "BCM6";
private Handler handler = new Handler();
private Gpio ledGpio;
private Runnable blinkRunnable = new Runnable() {
@Override
public void run() {
// Exit if the GPIO is already closed
if (ledGpio == null) {
return;
}
try {
ledGpio.setValue(!ledGpio.getValue());
handler.postDelayed(blinkRunnable, INTERVAL_BETWEEN_BLINKS_MS);
} catch (IOException e) {
Log.e("MainActivity", "Error on PeripheralIO API", e);
}
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PeripheralManagerService service = new PeripheralManagerService();
try {
ledGpio = service.openGpio(GPIO_PIN_NAME_LED);
ledGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
handler.post(blinkRunnable);
} catch (IOException e) {
Log.e("MainActivity", "Error on PeripheralIO API", e);
}
}
}
```
## User drivers
Google already ships some user-drivers, ready to use, in the form of Gradle
libraries. Let's take the Button driver as an example.
### Installation
It's a simple Gradle dependency to add:
`compile 'com.google.android.things.contrib:driver-button:0.1'`
### Usage
The button driver provides a simple class which you feed with the GPIO name to
use, and a callback:
*MainActivity.java*
```java
public class MainActivity extends Activity {
private static final String GPIO_PIN_NAME_BUTTON = "BCM6";
Button button;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("MainActivity", "onCreate");
try {
button = new Button(GPIO_PIN_NAME_BUTTON,
Button.LogicState.PRESSED_WHEN_HIGH
);
button.setOnButtonEventListener(new Button.OnButtonEventListener() {
@Override
public void onButtonEvent(Button button, boolean pressed) {
Log.d("MainActivity", "Button has been pressed!");
}
});
} catch (IOException e) {
Log.e("MainActivity", "Unable to configure the button", e);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
try {
button.close();
} catch (IOException e) {
Log.e("MainActivity", "There's been an error while closing the button");
}
}
}
```
Notice that you'll have to close the GPIO when you leave your Activity
(`button.close()`).
And with those simple dozen lines of Java, you can use your hardware button
to trigger things in your application. The button driver also provides a way to
bind your hardware button to a software event, then any application can simply
listen to the software key event. This is an example binding the button to the
key `A`:
*MainActivity.java*
```java
public class MainActivity extends Activity {
private static final String GPIO_PIN_NAME_BUTTON = "BCM6";
ButtonInputDriver inputDriver;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
inputDriver = new ButtonInputDriver(GPIO_PIN_NAME_BUTTON,
Button.LogicState.PRESSED_WHEN_HIGH,
KeyEvent.KEYCODE_A // the keycode to send
);
inputDriver.register();
} catch (IOException e) {
Log.e("MainActivity", "Error while binding button", e);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
inputDriver.unregister();
try {
inputDriver.close();
} catch (IOException e) {
Log.e("MainActivity", "Error while unregistering the button driver", e);
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_A) {
Log.d("MainActivity", "Button has been pressed");
return true;
}
return super.onKeyDown(keyCode, event);
}
}
```
## Conclusion
Even if it may be early to conclude anything from this preview, I have mixed
feelings regarding the state of Android Things.
While having the whole UI
toolkit available is great for industry-oriented hardware, I don't really see
the point of it in consumer products. Most of the connected devices uses LEDs or
a screen with minimal information. From my point of view, a connected device
should be set up then forgot, and work without requesting anything from me past
the initial configuration. I don't want to press a button to turn the lights on.
I don't want to take my phone, unlock it, start the relevant application, then
press a button to turn the lights on. I want the lights to turn on when I need
it. Using a motion sensor, location tracking from my phone, whatever. As long as
I have to interact with the lights, they are not smarter than my good old light
bulbs with their big button I can use even in the dark with both hands full.
The first thing I expected from this preview was Weave integration. Which is
completely absent (I guess it will come eventually). You can start making a
connected device powered by Google technologies, but *you can't use the standard
Google tries pushing forward to control it*. You'll have to write your own
control interface (probably a REST API, which means integrating a web-server in
your Android Things application).
Having the ability to work on the IDE I'm used to, with an SDK I already know,
and being able to reuse the ton of existing Java libraries is really great
though. It makes the entry barrier much lower than usual embedded development.
That is, when you have someone else to do the hardware part for you.
I know computing power and storage comes nearly free nowadays, but being used to
use AVRs, MSPs…, I can't help thinking a Raspberry Pi 3 is totally
overkill for that kind of use. I just used a 1.2 GHz, quad-core SoC and 600 MB
of storage *to blink an LED*. Most of those devices will only be
remote-controlled and will send data for analysis anyway. An ESP8266 is much
smaller, uses less power, comes with built-in Wi-Fi, for a couple bucks.
In the end, I think Google shouldn't have used Android as a basis for that kind
of IoT platform. While it surely looks attractive, it comes with multiple
drawbacks inherent to the idea itself. A Google-branded toolchain for something
like the ESP8266 with built-in Weave support and first-class Firebase/Google
Cloud client libraries would have been a much better approach.