Teeui example

This patch adds an example of a UI described using the new layout
language. It implements the layout described in the
Android Protected Confirmation Design guidelines[1] for layouts with
physical buttons. The example can be linked with the teeui_jni library
and tested with the TeeuiFramebufferizer tool.

[1]https://source.android.com/security/protected-confirmation/design

Test: make TeeuiFramebufferizer
      LD_LIBRARY_PATH=./out/host/linux-x86/lib64 TeeuiFramebufferizer
Bug: 111446692
Bug: 111451575
Change-Id: I5ebcb8a27999ea4c78c82dc5b1855a322f8c8fb0
diff --git a/libteeui/Android.bp b/libteeui/Android.bp
index a2f1bd7..c8dd50b 100644
--- a/libteeui/Android.bp
+++ b/libteeui/Android.bp
@@ -16,3 +16,4 @@
         "-ffunction-sections",
     ],
 }
+
diff --git a/libteeui/example/Android.bp b/libteeui/example/Android.bp
new file mode 100644
index 0000000..63167a9
--- /dev/null
+++ b/libteeui/example/Android.bp
@@ -0,0 +1,16 @@
+cc_library_static {
+    name: "libteeui_example_layout",
+    defaults: ["keystore_defaults"],
+    srcs: [
+        "fonts.S",
+        "teeui.cpp",
+    ],
+    static_libs: [
+        "libft2.nodep",
+        "libteeui",
+    ],
+    host_supported: true,
+    cflags: [
+        "-ffunction-sections",
+    ],
+}
diff --git a/libteeui/example/Roboto-Regular.ttf b/libteeui/example/Roboto-Regular.ttf
new file mode 100644
index 0000000..2c97eea
--- /dev/null
+++ b/libteeui/example/Roboto-Regular.ttf
Binary files differ
diff --git a/libteeui/example/Shield.ttf b/libteeui/example/Shield.ttf
new file mode 100644
index 0000000..a2f5e33
--- /dev/null
+++ b/libteeui/example/Shield.ttf
Binary files differ
diff --git a/libteeui/example/fonts.S b/libteeui/example/fonts.S
new file mode 100644
index 0000000..f1a3f1a
--- /dev/null
+++ b/libteeui/example/fonts.S
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <teeui/incfont.h>
+
+TEEUI_INCFONT(RobotoRegular, "Roboto-Regular.ttf");
+TEEUI_INCFONT(Shield, "Shield.ttf");
diff --git a/libteeui/example/fonts.h b/libteeui/example/fonts.h
new file mode 100644
index 0000000..4aae6e0
--- /dev/null
+++ b/libteeui/example/fonts.h
@@ -0,0 +1,33 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBTEEUI_EXAMPLE_FONTS_H_
+#define LIBTEEUI_EXAMPLE_FONTS_H_
+
+#include <teeui/incfont.h>
+
+/*
+ * Each entry TEEUI_INCFONT(<name>) declares:
+ *    extern unsigned char <name>[];
+ *    extern unsigned int <name>_length;
+ * The first one pointing to a raw ttf font file in the .rodata section, and the second
+ * beeing the size of the buffer.
+ */
+TEEUI_INCFONT(RobotoRegular);
+TEEUI_INCFONT(Shield);
+
+#endif  // LIBTEEUI_EXAMPLE_FONTS_H_
diff --git a/libteeui/example/layout.h b/libteeui/example/layout.h
new file mode 100644
index 0000000..8a93ed0
--- /dev/null
+++ b/libteeui/example/layout.h
@@ -0,0 +1,166 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TEEUI_LIBTEEUI_EXAMPLE_LAYOUT_H_
+#define TEEUI_LIBTEEUI_EXAMPLE_LAYOUT_H_
+
+#include <teeui/button.h>
+#include <teeui/label.h>
+#include <teeui/utils.h>
+
+#include "fonts.h"
+
+namespace teeui {
+
+DECLARE_PARAMETER(RightEdgeOfScreen);
+DECLARE_PARAMETER(BottomOfScreen);
+DECLARE_PARAMETER(PowerButtonTop);
+DECLARE_PARAMETER(PowerButtonBottom);
+DECLARE_PARAMETER(VolUpButtonTop);
+DECLARE_PARAMETER(VolUpButtonBottom);
+DECLARE_PARAMETER(DefaultFontSize);  // 14_dp regular and 18_dp magnified
+DECLARE_PARAMETER(BodyFontSize);     // 16_dp regular and 20_dp magnified
+
+NEW_PARAMETER_SET(ConUIParameters, RightEdgeOfScreen, BottomOfScreen, PowerButtonTop,
+                  PowerButtonBottom, VolUpButtonTop, VolUpButtonBottom, DefaultFontSize,
+                  BodyFontSize);
+
+CONSTANT(BorderWidth, 24_dp);
+CONSTANT(PowerButtonCenter, (PowerButtonTop() + PowerButtonBottom()) / 2_px);
+CONSTANT(VolUpButtonCenter, (VolUpButtonTop() + VolUpButtonBottom()) / 2.0_px);
+CONSTANT(GrayZone, 12_dp);
+CONSTANT(RightLabelEdge, RightEdgeOfScreen() - BorderWidth - GrayZone);
+CONSTANT(LabelWidth, RightLabelEdge - BorderWidth);
+CONSTANT(DefaultTextColor, Color(0xff212121));
+
+CONSTANT(SQRT2, 1.4142135623_dp);
+CONSTANT(SQRT8, 2.828427125_dp);
+
+CONSTANT(ARROW_SHAPE,
+         CONVEX_OBJECTS(CONVEX_OBJECT(Vec2d{.0_dp, .0_dp}, Vec2d{6.0_dp, 6.0_dp},
+                                      Vec2d{6.0_dp - SQRT8, 6.0_dp}, Vec2d{-SQRT2, SQRT2}),
+                        CONVEX_OBJECT(Vec2d{6.0_dp - SQRT8, 6.0_dp}, Vec2d{6.0_dp, 6.0_dp},
+                                      Vec2d{0.0_dp, 12.0_dp}, Vec2d{-SQRT2, 12.0_dp - SQRT2})));
+
+DECLARE_FONT_BUFFER(RobotoRegular, RobotoRegular, RobotoRegular_length);
+DECLARE_FONT_BUFFER(Shield, Shield, Shield_length);
+CONSTANT(DefaultFont, FONT(RobotoRegular));
+
+BEGIN_ELEMENT(LabelOK, teeui::Label)
+FontSize(DefaultFontSize());
+LineHeight(20_dp);
+NumberOfLines(2);
+Dimension(LabelWidth, HeightFromLines);
+Position(BorderWidth, PowerButtonCenter - dim_h / 2.0_px);
+DefaultText("Wiggle your big toe to confirm");
+RightJustified;
+VerticallyCentered;
+TextColor(DefaultTextColor);
+Font(DefaultFont);
+END_ELEMENT();
+
+BEGIN_ELEMENT(IconPower, teeui::Button, ConvexObjectCount(2))
+Dimension(BorderWidth, PowerButtonBottom() - PowerButtonTop());
+Position(RightEdgeOfScreen() - BorderWidth, PowerButtonTop());
+CornerRadius(3_dp);
+ButtonColor(0xff212121);
+RoundTopLeft;
+RoundBottomLeft;
+ConvexObjectColor(0xffffffff);
+ConvexObjects(ARROW_SHAPE);
+END_ELEMENT();
+
+BEGIN_ELEMENT(LabelCancel, teeui::Label)
+FontSize(DefaultFontSize());
+LineHeight(20_dp);
+NumberOfLines(2);
+Dimension(LabelWidth, HeightFromLines);
+Position(BorderWidth, VolUpButtonCenter - dim_h / 2.0_px);
+DefaultText("Wink left then right thrice to cancel");
+RightJustified;
+VerticallyCentered;
+TextColor(DefaultTextColor);
+Font(DefaultFont);
+END_ELEMENT();
+
+BEGIN_ELEMENT(IconVolUp, teeui::Button, ConvexObjectCount(2))
+Dimension(BorderWidth, VolUpButtonBottom() - VolUpButtonTop());
+Position(RightEdgeOfScreen() - BorderWidth, VolUpButtonTop());
+CornerRadius(5_dp);
+ButtonColor(0xffffffff);
+ConvexObjectColor(0xff212121);
+ConvexObjects(ARROW_SHAPE);
+END_ELEMENT();
+
+BEGIN_ELEMENT(IconShield, teeui::Label)
+FontSize(36_dp);
+LineHeight(36_dp);
+NumberOfLines(1);
+Dimension(LabelWidth, HeightFromLines);
+Position(BorderWidth, BOTTOM_EDGE_OF(LabelCancel) + 60_dp);
+DefaultText("A");  // ShieldTTF has just one glyph at the code point for capital A
+TextColor(0xfff48542);
+Font(FONT(Shield));
+END_ELEMENT();
+
+BEGIN_ELEMENT(LabelTitle, teeui::Label)
+FontSize(22_dp);
+LineHeight(28_dp);
+NumberOfLines(1);
+Dimension(RightEdgeOfScreen() - BorderWidth, HeightFromLines);
+Position(BorderWidth, BOTTOM_EDGE_OF(IconShield) + 16_dp);
+DefaultText("Android Protected Confirmation");
+Font(DefaultFont);
+VerticallyCentered;
+TextColor(DefaultTextColor);
+END_ELEMENT();
+
+BEGIN_ELEMENT(LabelHint, teeui::Label)
+FontSize(DefaultFontSize());
+LineHeight(DefaultFontSize() * 1.5_px);
+NumberOfLines(4);
+Dimension(LabelWidth, HeightFromLines);
+Position(BorderWidth, BottomOfScreen() - BorderWidth - dim_h);
+DefaultText("This confirmation provides an extra layer of security for the action that you're "
+            "about to take");
+VerticallyCentered;
+TextColor(DefaultTextColor);
+Font(DefaultFont);
+END_ELEMENT();
+
+BEGIN_ELEMENT(LabelBody, teeui::Label)
+FontSize(BodyFontSize());
+LineHeight(BodyFontSize() * 1.4_px);
+NumberOfLines(20);
+Position(BorderWidth, BOTTOM_EDGE_OF(LabelTitle) + 24_dp);
+Dimension(LabelWidth, LabelHint::pos_y - pos_y - 24_dp);
+DefaultText(
+    "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut "
+    "labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco "
+    "laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in "
+    "voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat "
+    "cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");
+TextColor(DefaultTextColor);
+Font(DefaultFont);
+END_ELEMENT();
+
+NEW_LAYOUT(ConfUILayout, LabelOK, IconPower, LabelCancel, IconVolUp, IconShield, LabelTitle,
+           LabelHint, LabelBody);
+
+}  // namespace teeui
+
+#endif  // TEEUI_LIBTEEUI_EXAMPLE_LAYOUT_H_
diff --git a/libteeui/example/teeui.cpp b/libteeui/example/teeui.cpp
new file mode 100644
index 0000000..a72ae07
--- /dev/null
+++ b/libteeui/example/teeui.cpp
@@ -0,0 +1,147 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "layout.h"
+#include <teeui/example/teeui.h>
+
+using namespace teeui;
+
+static uint32_t device_width_px;
+static uint32_t device_height_px;
+static double dp2px_;
+static double mm2px_;
+
+uint32_t alfaCombineChannel(uint32_t shift, double alfa, uint32_t a, uint32_t b) {
+    a >>= shift;
+    a &= 0xff;
+    b >>= shift;
+    b &= 0xff;
+    double acc = alfa * a + (1 - alfa) * b;
+    if (acc <= 0) return 0;
+    uint32_t result = acc;
+    if (result > 255) return 255 << shift;
+    return result << shift;
+}
+
+template <typename T> uint32_t renderPixel(uint32_t x, uint32_t y, const T& e) {
+    return e.bounds_.drawPoint(Point<pxs>(x, y));
+}
+
+template <typename... Elements>
+uint32_t renderPixel(uint32_t x, uint32_t y, const std::tuple<Elements...>& layout) {
+    uint32_t intensity = (x * 256) / device_width_px;
+    uint32_t acc = (intensity & 0xff) << 16 | (intensity & 0xff) << 8 | (intensity & 0xff);
+    for (uint32_t value : {renderPixel(x, y, std::get<Elements>(layout))...}) {
+        double alfa = (value & 0xff000000) >> 24;
+        alfa /= 255.0;
+        acc = alfaCombineChannel(0, alfa, value, acc) | alfaCombineChannel(8, alfa, value, acc) |
+              alfaCombineChannel(16, alfa, value, acc);
+    }
+    return acc;
+}
+
+struct FrameBuffer {
+    uint32_t left_;
+    uint32_t top_;
+    uint32_t width_;
+    uint32_t height_;
+    uint32_t* buffer_;
+    size_t size_in_elements_;
+    uint32_t lineStride_;
+
+    Error drawPixel(uint32_t x, uint32_t y, uint32_t color) const {
+        size_t pos = (top_ + y) * lineStride_ + x + left_;
+        if (pos >= size_in_elements_) {
+            return Error::OutOfBoundsDrawing;
+        }
+        double alfa = (color & 0xff000000) >> 24;
+        alfa /= 255.0;
+        auto acc = buffer_[pos];
+        buffer_[pos] = alfaCombineChannel(0, alfa, color, acc) |
+                       alfaCombineChannel(8, alfa, color, acc) |
+                       alfaCombineChannel(16, alfa, color, acc);
+        return Error::OK;
+    }
+};
+
+template <typename... Elements>
+Error drawElements(std::tuple<Elements...>& layout, const PixelDrawer& drawPixel) {
+    // Error::operator|| is overloaded, so we don't get short circuit evaluation.
+    // But we get the first error that occurs. We will still try and draw the remaining
+    // elements in the order they appear in the layout tuple.
+    return (std::get<Elements>(layout).draw(drawPixel) || ...);
+}
+
+uint32_t setDeviceInfo(uint32_t width, uint32_t height, uint32_t colormodel, double dp2px,
+                       double mm2px) {
+    dp2px_ = dp2px;
+    mm2px_ = mm2px;
+    (void)colormodel;  // ignored for now;
+    device_width_px = width;
+    device_height_px = height;
+    return 0;
+}
+
+uint32_t renderUIIntoBuffer(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t lineStride,
+                            uint32_t* buffer, size_t buffer_size_in_elements_not_bytes) {
+    uint32_t afterLastPixelIndex = 0;
+    if (__builtin_add_overflow(y, h, &afterLastPixelIndex) ||
+        __builtin_add_overflow(afterLastPixelIndex, -1, &afterLastPixelIndex) ||
+        __builtin_mul_overflow(afterLastPixelIndex, lineStride, &afterLastPixelIndex) ||
+        __builtin_add_overflow(afterLastPixelIndex, x, &afterLastPixelIndex) ||
+        __builtin_add_overflow(afterLastPixelIndex, w, &afterLastPixelIndex) ||
+        afterLastPixelIndex > buffer_size_in_elements_not_bytes) {
+        return uint32_t(Error::OutOfBoundsDrawing);
+    }
+    context<ConUIParameters> conv(mm2px_, dp2px_);
+    conv.setParam<RightEdgeOfScreen>(pxs(device_width_px));
+    conv.setParam<BottomOfScreen>(pxs(device_height_px));
+    conv.setParam<PowerButtonTop>(100_dp);
+    conv.setParam<PowerButtonBottom>(150_dp);
+    conv.setParam<VolUpButtonTop>(200_dp);
+    conv.setParam<VolUpButtonBottom>(250_dp);
+    conv.setParam<DefaultFontSize>(14_dp);
+    conv.setParam<BodyFontSize>(16_dp);
+
+    auto layoutInstance = instantiateLayout(ConfUILayout(), conv);
+
+    uint32_t* begin = buffer + (y * lineStride + x);
+    for (uint32_t yi = 0; yi < h; ++yi) {
+        for (uint32_t xi = 0; xi < w; ++xi) {
+            begin[xi] = 0xffffffff;
+            //            begin[xi] = renderPixel(x + xi, y + yi, layoutInstance);
+        }
+        begin += lineStride;
+    }
+    FrameBuffer fb;
+    fb.left_ = x;
+    fb.top_ = y;
+    fb.width_ = w;
+    fb.height_ = h;
+    fb.buffer_ = buffer;
+    fb.size_in_elements_ = buffer_size_in_elements_not_bytes;
+    fb.lineStride_ = lineStride;
+
+    auto pixelDrawer = makePixelDrawer(
+        [&fb](uint32_t x, uint32_t y, Color color) -> Error { return fb.drawPixel(x, y, color); });
+
+    if (auto error = drawElements(layoutInstance, pixelDrawer)) {
+        return uint32_t(error.code());
+    }
+
+    return 0;  // OK
+}
diff --git a/libteeui/include/teeui/example/teeui.h b/libteeui/include/teeui/example/teeui.h
new file mode 100644
index 0000000..7fdc032
--- /dev/null
+++ b/libteeui/include/teeui/example/teeui.h
@@ -0,0 +1,29 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TEEUI_LIBTEEUI_INCLUDE_TEEUI_H_
+#define TEEUI_LIBTEEUI_INCLUDE_TEEUI_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+uint32_t setDeviceInfo(uint32_t width, uint32_t height, uint32_t colormodel, double dp2px,
+                       double mm2px);
+uint32_t renderUIIntoBuffer(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t lineStride,
+                            uint32_t* buffer, size_t buffer_size_in_elements_not_bytes);
+
+#endif  // TEEUI_LIBTEEUI_INCLUDE_TEEUI_H_
diff --git a/libteeui/include/teeui/incfont.h b/libteeui/include/teeui/incfont.h
new file mode 100644
index 0000000..59a9183
--- /dev/null
+++ b/libteeui/include/teeui/incfont.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBTEEUI_INCLUDE_TEEUI_INCFONT_H_
+#define LIBTEEUI_INCLUDE_TEEUI_INCFONT_H_
+
+#ifdef __ASSEMBLY__
+.macro TEEUI_ASM_INCFONT fontname, filename
+.section .rodata
+.align 4
+.globl \fontname
+\fontname:
+.incbin "\filename"
+.section .rodata
+.align 1
+\fontname\()_end:
+.section .rodata
+.align 4;
+.globl \fontname\()_length
+\fontname\()_length:
+.long \fontname\()_end - \fontname - 1
+.endmacro
+
+#define TEEUI_INCFONT(fontname, filename) TEEUI_ASM_INCFONT fontname, filename
+#else
+
+#define TEEUI_INCFONT(fontname, ...)                                                               \
+    extern unsigned char fontname[];                                                               \
+    extern unsigned int fontname##_length
+
+#endif
+
+#endif  // LIBTEEUI_INCLUDE_TEEUI_INCFONT_H_
diff --git a/libteeui/include/teeui/label.h b/libteeui/include/teeui/label.h
index 5198e25..a952081 100644
--- a/libteeui/include/teeui/label.h
+++ b/libteeui/include/teeui/label.h
@@ -101,7 +101,7 @@
     static const constexpr bool label_right_justified = false;
     static const constexpr bool label_vertically_centered = false;
     static const constexpr Color label_text_color = 0xff000000;
-    static const constexpr FontBuffer label_font = {};
+    static const constexpr int label_font = 0;
 
     Label() = default;
     template <typename Context>
@@ -111,7 +111,7 @@
               context = Derived::label_font_size, context = Derived::label_line_height,
               {&Derived::label_text[0], &Derived::label_text[sizeof(Derived::label_text) - 1]},
               Derived::label_right_justified, Derived::label_vertically_centered,
-              Derived::label_text_color, Derived::label_font) {}
+              Derived::label_text_color, getFont(Derived::label_font)) {}
 
     Error draw(const PixelDrawer& drawPixel) {
         LabelImpl::LineInfo::info_t lines[Derived::label_number_of_lines];
@@ -138,8 +138,12 @@
 
 #define TextColor(color) static const constexpr Color label_text_color = color
 
-#define FONT(buffer, ...) FontBuffer(buffer, ##__VA_ARGS__)
+#define FONT(name) TEEUI_FONT_##name()
 
-#define Font(fontbuffer) static const constexpr FontBuffer label_font = fontbuffer
+#define DECLARE_FONT_BUFFER(name, buffer, ...)                                                     \
+    struct TEEUI_FONT_##name {};                                                                   \
+    inline FontBuffer getFont(TEEUI_FONT_##name) { return FontBuffer(buffer, ##__VA_ARGS__); }
+
+#define Font(fontbuffer) static const constexpr auto label_font = fontbuffer
 
 #endif  // LIBTEEUI_LABEL_H_
diff --git a/libteeui_jni/Android.bp b/libteeui_jni/Android.bp
index cb105ba..c3d53fc 100644
--- a/libteeui_jni/Android.bp
+++ b/libteeui_jni/Android.bp
@@ -6,5 +6,8 @@
         "libteeui_jni.cpp",
     ],
     static_libs: [
+        "libft2.nodep",
+        "libteeui",
+        "libteeui_example_layout",
     ],
 }
diff --git a/libteeui_jni/libteeui_jni.cpp b/libteeui_jni/libteeui_jni.cpp
index fe4a59f..b71dc4a 100644
--- a/libteeui_jni/libteeui_jni.cpp
+++ b/libteeui_jni/libteeui_jni.cpp
@@ -16,6 +16,7 @@
  */
 
 #include <jni.h>
+#include <teeui/example/teeui.h>
 
 /*
  * JTypeTraits provides hints for JArray on how to access and free the array elements and how