1 /*
2  * Copyright 2020, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "touch_button_example.h"
18 
19 #include <stddef.h>
20 #include <stdint.h>
21 
22 #include "example_utils.h"
23 #include "layout/touch_button_layout.h"
24 
25 namespace teeui {
26 namespace example {
27 namespace touch_button {
28 
translateLabels(Layout * layout)29 template <typename Layout> static void translateLabels(Layout* layout) {
30     translateLabel<LabelOK>(layout);
31     translateLabel<LabelCancel>(layout);
32     translateLabel<LabelTitle>(layout);
33     translateLabel<LabelHint>(layout);
34 }
35 
36 class GUIStateTouch : public ITeeuiExample {
37   private:
38     bool okTapped_ = false;
39     bool cancelTapped_ = false;
40     EventResult eventResult_ = EventResult::NONE;
41 
42   public:
43     bool inverted_;
44     std::string confirmationMessage_;
45     layout_t<ConfUILayout> layoutInstance_ = {};
46 
GUIStateTouch()47     GUIStateTouch() : okTapped_(false), cancelTapped_(false), inverted_(false), layoutInstance_{} {}
48 
isOkTapped() const49     bool isOkTapped() const { return okTapped_; }
isCancelTapped() const50     bool isCancelTapped() const { return cancelTapped_; }
51 
tapOk(Event e)52     Error tapOk(Event e) {
53         if (e.event_ == EventType::KeyUp) {
54             okTapped_ = true;
55             eventResult_ = EventResult::CONFIRM;
56         }
57         return Error::OK;
58     }
59 
tapCancel(Event e)60     Error tapCancel(Event e) {
61         if (e.event_ == EventType::KeyUp) {
62             cancelTapped_ = true;
63             eventResult_ = EventResult::CANCEL;
64         }
65         return Error::OK;
66     }
67 
selectLanguage(const char * language_id)68     void selectLanguage(const char* language_id) override {
69         teeui::localization::selectLangId(language_id);
70         translateLabels(&layoutInstance_);
71     }
72 
setConfirmationMessage(std::string confirmationMessage)73     void setConfirmationMessage(std::string confirmationMessage) override {
74         confirmationMessage_ = std::move(confirmationMessage);
75         std::get<LabelBody>(layoutInstance_)
76             .setText({&*confirmationMessage_.begin(), &*confirmationMessage_.end()});
77     }
78 
79     uint32_t setDeviceInfo(DeviceInfo device_info, bool magnified, bool inverted = false) override;
80 
81     EventResult onEvent(uint32_t x, uint32_t y, uint32_t) override;
82 
83     uint32_t renderUIIntoBuffer(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t lineStride,
84                                 uint32_t* buffer,
85                                 size_t buffer_size_in_elements_not_bytes) override;
86 };
87 
createTeeuiExample()88 std::unique_ptr<ITeeuiExample> createTeeuiExample() {
89     return std::make_unique<GUIStateTouch>();
90 }
91 
onEvent(uint32_t x,uint32_t y,uint32_t)92 EventResult GUIStateTouch::onEvent(uint32_t x, uint32_t y, uint32_t) {
93     eventResult_ = EventResult::NONE;
94     Event event{x, y, EventType::KeyUp};
95     handleAllEvent(layoutInstance_, event);
96     return eventResult_;
97 }
98 
setLayoutParams(DeviceInfo & deviceInfo,bool magnified,bool inverted)99 static context<ConfUIParameters> setLayoutParams(DeviceInfo& deviceInfo, bool magnified,
100                                                  bool inverted) {
101     context<ConfUIParameters> ctx(deviceInfo.mm2px_, deviceInfo.dp2px_);
102     ctx.setParam<RightEdgeOfScreen>(pxs(deviceInfo.width_));
103     ctx.setParam<BottomOfScreen>(pxs(deviceInfo.height_));
104     if (magnified) {
105         ctx.setParam<DefaultFontSize>(18_dp);
106         ctx.setParam<BodyFontSize>(20_dp);
107     } else {
108         ctx.setParam<DefaultFontSize>(14_dp);
109         ctx.setParam<BodyFontSize>(16_dp);
110     }
111     if (inverted) {
112         ctx.setParam<ShieldColor>(kShieldColorInv);
113         ctx.setParam<ColorText>(kTextColorInv);
114         ctx.setParam<ColorBG>(kBackGroundColorInv);
115         ctx.setParam<ColorButton>(kShieldColorInv);
116     } else {
117         ctx.setParam<ShieldColor>(kShieldColor);
118         ctx.setParam<ColorText>(kTextColor);
119         ctx.setParam<ColorBG>(kBackGroundColor);
120         ctx.setParam<ColorButton>(kShieldColor);
121     }
122     return ctx;
123 }
124 
setDeviceInfo(DeviceInfo device_info,bool magnified,bool inverted)125 uint32_t GUIStateTouch::setDeviceInfo(DeviceInfo device_info, bool magnified, bool inverted) {
126     layoutInstance_ =
127         instantiateLayout(ConfUILayout(), setLayoutParams(device_info, magnified, inverted));
128     inverted_ = inverted;
129     std::get<LabelOK>(layoutInstance_)
130         .setCB(makeCallback<Error, Event>(
131             [](Event e, void* p) -> Error { return reinterpret_cast<GUIStateTouch*>(p)->tapOk(e); },
132             this));
133     std::get<LabelCancel>(layoutInstance_)
134         .setCB(makeCallback<Error, Event>(
135             [](Event e, void* p) -> Error {
136                 return reinterpret_cast<GUIStateTouch*>(p)->tapCancel(e);
137             },
138             this));
139     return 0;
140 }
141 
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)142 uint32_t GUIStateTouch::renderUIIntoBuffer(uint32_t x, uint32_t y, uint32_t w, uint32_t h,
143                                            uint32_t lineStride, uint32_t* buffer,
144                                            size_t buffer_size_in_elements_not_bytes) {
145     uint32_t afterLastPixelIndex = 0;
146     if (__builtin_add_overflow(y, h, &afterLastPixelIndex) ||
147         __builtin_add_overflow(afterLastPixelIndex, -1, &afterLastPixelIndex) ||
148         __builtin_mul_overflow(afterLastPixelIndex, lineStride, &afterLastPixelIndex) ||
149         __builtin_add_overflow(afterLastPixelIndex, x, &afterLastPixelIndex) ||
150         __builtin_add_overflow(afterLastPixelIndex, w, &afterLastPixelIndex) ||
151         afterLastPixelIndex > buffer_size_in_elements_not_bytes) {
152         return uint32_t(Error::OutOfBoundsDrawing);
153     }
154 
155     uint32_t* begin = buffer + (y * lineStride + x);
156 
157     Color bgColor = inverted_ ? kBackGroundColorInv : kBackGroundColor;
158 
159     for (uint32_t yi = 0; yi < h; ++yi) {
160         for (uint32_t xi = 0; xi < w; ++xi) {
161             begin[xi] = bgColor;
162         }
163         begin += lineStride;
164     }
165     FrameBuffer fb;
166     fb.left_ = x;
167     fb.top_ = y;
168     fb.width_ = w;
169     fb.height_ = h;
170     fb.buffer_ = buffer;
171     fb.size_in_elements_ = buffer_size_in_elements_not_bytes;
172     fb.lineStride_ = lineStride;
173 
174     auto pixelDrawer = makePixelDrawer(
175         [&fb](uint32_t x, uint32_t y, Color color) -> Error { return fb.drawPixel(x, y, color); });
176 
177     if (auto error = drawElements(layoutInstance_, pixelDrawer)) {
178         return uint32_t(error.code());
179     }
180 
181     return 0;  // OK
182 }
183 
184 }  // namespace touch_button
185 }  // namespace example
186 }  // namespace teeui
187