1 /*
2  * Copyright 2019, 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 #pragma once
18 
19 #include <device_layout.h>
20 #include <teeui/button.h>
21 #include <teeui/label.h>
22 #include <teeui/localization/ConfirmationUITranslations.h>
23 #include <teeui/utils.h>
24 #include <memory>
25 #include <tuple>
26 
27 #include "fonts.h"
28 
29 using teeui::localization::TranslationId;
30 
31 namespace teeui {
32 
33 DECLARE_PARAMETER(RightEdgeOfScreen);
34 DECLARE_PARAMETER(BottomOfScreen);
35 DECLARE_PARAMETER(PowerButtonTop);
36 DECLARE_PARAMETER(PowerButtonBottom);
37 DECLARE_PARAMETER(VolUpButtonTop);
38 DECLARE_PARAMETER(VolUpButtonBottom);
39 DECLARE_PARAMETER(DefaultFontSize);  // 14_dp regular and 18_dp magnified
40 DECLARE_PARAMETER(BodyFontSize);     // 16_dp regular and 20_dp magnified
41 DECLARE_TYPED_PARAMETER(ShieldColor, ::teeui::Color);
42 DECLARE_TYPED_PARAMETER(ColorText, ::teeui::Color);
43 DECLARE_TYPED_PARAMETER(ColorBG, ::teeui::Color);
44 DECLARE_TYPED_PARAMETER(ColorTextHint, ::teeui::Color);
45 DECLARE_TYPED_PARAMETER(ColorButton, ::teeui::Color);
46 DECLARE_TYPED_PARAMETER(ColorButtonBG, ::teeui::Color);
47 
48 NEW_PARAMETER_SET(ConUIParameters,
49                   RightEdgeOfScreen,
50                   BottomOfScreen,
51                   PowerButtonTop,
52                   PowerButtonBottom,
53                   VolUpButtonTop,
54                   VolUpButtonBottom,
55                   DefaultFontSize,
56                   BodyFontSize,
57                   ShieldColor,
58                   ColorText,
59                   ColorBG,
60                   ColorTextHint,
61                   ColorButton,
62                   ColorButtonBG);
63 
64 namespace layouts {
65 
66 CONSTANT(BorderWidth, 24_dp);
67 CONSTANT(PowerButtonCenter, (PowerButtonTop() + PowerButtonBottom()) / 2_px);
68 CONSTANT(VolUpButtonCenter, (VolUpButtonTop() + VolUpButtonBottom()) / 2.0_px);
69 CONSTANT(GrayZone, 12_dp);
70 CONSTANT(RightLabelEdge, RightEdgeOfScreen() - BorderWidth - GrayZone);
71 CONSTANT(LabelWidth, RightLabelEdge - BorderWidth);
72 
73 CONSTANT(SQRT2, 1.4142135623_dp);
74 CONSTANT(SQRT8, 2.828427125_dp);
75 
76 CONSTANT(ARROW_SHAPE,
77          CONVEX_OBJECTS(CONVEX_OBJECT(Vec2d{.0_dp, .0_dp},
78                                       Vec2d{6.0_dp, 6.0_dp},
79                                       Vec2d{6.0_dp - SQRT8, 6.0_dp},
80                                       Vec2d{-SQRT2, SQRT2}),
81                         CONVEX_OBJECT(Vec2d{6.0_dp - SQRT8, 6.0_dp},
82                                       Vec2d{6.0_dp, 6.0_dp},
83                                       Vec2d{0.0_dp, 12.0_dp},
84                                       Vec2d{-SQRT2, 12.0_dp - SQRT2})));
85 
86 DECLARE_FONT_BUFFER(RobotoMedium, RobotoMedium, RobotoMedium_length);
87 DECLARE_FONT_BUFFER(RobotoRegular, RobotoRegular, RobotoRegular_length);
88 DECLARE_FONT_BUFFER(Shield, Shield, Shield_length);
89 
90 CONSTANT(DefaultFont, FONT(RobotoRegular));
91 
92 BEGIN_ELEMENT(LabelOK, teeui::Label)
93 FontSize(DefaultFontSize());
94 LineHeight(20_dp);
95 NumberOfLines(2);
96 Dimension(LabelWidth, HeightFromLines);
97 Position(BorderWidth, PowerButtonCenter - dim_h / 2.0_px);
98 DefaultText("Wiggle your big toe to confirm");
99 RightJustified;
100 VerticallyCentered;
101 TextColor(ColorText());
102 Font(FONT(RobotoMedium));
103 TextID(TEXT_ID(TranslationId::CONFIRM_PWR_BUTTON_DOUBLE_PRESS));
104 END_ELEMENT();
105 
106 BEGIN_ELEMENT(IconPower, teeui::Button, ConvexObjectCount(2))
107 Dimension(BorderWidth, PowerButtonBottom() - PowerButtonTop());
108 Position(RightEdgeOfScreen() - BorderWidth, PowerButtonTop());
109 CornerRadius(3_dp);
110 ButtonColor(ColorButton());
111 RoundTopLeft;
112 RoundBottomLeft;
113 ConvexObjectColor(ColorButtonBG());
114 ConvexObjects(ARROW_SHAPE);
115 END_ELEMENT();
116 
117 BEGIN_ELEMENT(LabelCancel, teeui::Label)
118 FontSize(DefaultFontSize());
119 LineHeight(20_dp);
120 NumberOfLines(2);
121 Dimension(LabelWidth, HeightFromLines);
122 Position(BorderWidth, VolUpButtonCenter - dim_h / 2.0_px);
123 DefaultText("Wink left then right thrice to cancel");
124 RightJustified;
125 VerticallyCentered;
126 TextColor(ColorText());
127 Font(FONT(RobotoMedium));
128 TextID(TEXT_ID(TranslationId::CANCEL));
129 END_ELEMENT();
130 
131 BEGIN_ELEMENT(IconVolUp, teeui::Button, ConvexObjectCount(2))
132 Dimension(BorderWidth, VolUpButtonBottom() - VolUpButtonTop());
133 Position(RightEdgeOfScreen() - BorderWidth, VolUpButtonTop());
134 CornerRadius(5_dp);
135 ButtonColor(ColorButtonBG());
136 ConvexObjectColor(ColorButton());
137 ConvexObjects(ARROW_SHAPE);
138 END_ELEMENT();
139 
140 BEGIN_ELEMENT(IconShield, teeui::Label)
141 FontSize(24_dp);
142 LineHeight(24_dp);
143 NumberOfLines(1);
144 Dimension(LabelWidth, HeightFromLines);
145 Position(BorderWidth, BOTTOM_EDGE_OF(LabelCancel) + 40_dp);
146 DefaultText(
147         "A");  // ShieldTTF has just one glyph at the code point for capital A
148 TextColor(ShieldColor());
149 Font(FONT(Shield));
150 END_ELEMENT();
151 
152 BEGIN_ELEMENT(LabelTitle, teeui::Label)
153 FontSize(20_dp);
154 LineHeight(20_dp);
155 NumberOfLines(1);
156 Dimension(RightEdgeOfScreen() - BorderWidth, HeightFromLines);
157 Position(BorderWidth, BOTTOM_EDGE_OF(IconShield) + 12_dp);
158 DefaultText("Android Protected Confirmation");
159 Font(FONT(RobotoMedium));
160 VerticallyCentered;
161 TextColor(ColorText());
162 TextID(TEXT_ID(TranslationId::TITLE));
163 END_ELEMENT();
164 
165 BEGIN_ELEMENT(LabelHint, teeui::Label)
166 FontSize(DefaultFontSize());
167 LineHeight(DefaultFontSize() * 1.5_px);
168 NumberOfLines(4);
169 Dimension(LabelWidth, HeightFromLines);
170 Position(BorderWidth, BottomOfScreen() - BorderWidth - dim_h);
171 DefaultText(
172         "This confirmation provides an extra layer of security for the action you're "
173         "about to take.");
174 VerticalTextAlignment(Alignment::BOTTOM);
175 TextColor(ColorTextHint());
176 Font(DefaultFont);
177 TextID(TEXT_ID(TranslationId::DESCRIPTION));
178 END_ELEMENT();
179 
180 BEGIN_ELEMENT(LabelBody, teeui::Label)
181 FontSize(BodyFontSize());
182 LineHeight(BodyFontSize() * 1.4_px);
183 NumberOfLines(20);
184 Position(BorderWidth, BOTTOM_EDGE_OF(LabelTitle) + 18_dp);
185 Dimension(LabelWidth, LabelHint::pos_y - pos_y - 24_dp);
186 DefaultText(
187         "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456"
188         "78901234567890");
189 TextColor(ColorText());
190 Font(FONT(RobotoRegular));
191 END_ELEMENT();
192 
193 NEW_LAYOUT(ConfUILayout,
194            LabelOK,
195            IconPower,
196            LabelCancel,
197            IconVolUp,
198            IconShield,
199            LabelTitle,
200            LabelHint,
201            LabelBody);
202 
203 class DisplayLayout : public ILayout {
204 public:
205     layout_t<ConfUILayout> layoutInstance_ = {};
206 
DisplayLayout(bool inverted,const context<ConUIParameters> & ctx)207     DisplayLayout(bool inverted, const context<ConUIParameters>& ctx)
208             : ILayout(inverted) {
209         layoutInstance_ = instantiateLayout(ConfUILayout(), ctx);
210     };
211 
setLanguage(const char * language_id)212     void setLanguage(const char* language_id) override {
213         teeui::localization::selectLangId(language_id);
214         translate(&std::get<LabelOK>(layoutInstance_));
215         translate(&std::get<LabelCancel>(layoutInstance_));
216         translate(&std::get<LabelTitle>(layoutInstance_));
217         translate(&std::get<LabelHint>(layoutInstance_));
218     }
219 
setConfirmationMessage(const char * prompt)220     void setConfirmationMessage(const char* prompt) override {
221         std::get<LabelBody>(layoutInstance_)
222                 .setText({prompt, prompt + strlen(prompt)});
223     }
224 
showInstructions(bool enable)225     void showInstructions(bool enable) override {
226         Color color;
227 
228         if (enable) {
229             color = inverted_ ? kColorEnabledInv : kColorEnabled;
230         } else {
231             color = inverted_ ? kColorDisabledInv : kColorDisabled;
232         }
233 
234         std::get<LabelOK>(layoutInstance_).setTextColor(color);
235         std::get<LabelCancel>(layoutInstance_).setTextColor(color);
236     }
237 
drawElements(const teeui::PixelDrawer & drawPixel)238     teeui::Error drawElements(const teeui::PixelDrawer& drawPixel) override {
239         return drawElements(layoutInstance_, drawPixel);
240     }
241 
242 private:
translate(LabelImpl * label)243     void translate(LabelImpl* label) {
244         uint64_t textId = label->textId();
245         const char* translation = localization::lookup(
246                 static_cast<localization::TranslationId>(textId));
247         label->setText({&translation[0], &translation[strlen(translation)]});
248     }
249 
250     template <typename... Elements>
drawElements(std::tuple<Elements...> & layout,const teeui::PixelDrawer & drawPixel)251     teeui::Error drawElements(std::tuple<Elements...>& layout,
252                               const teeui::PixelDrawer& drawPixel) {
253         // Error::operator|| is overloaded, so we don't get short circuit
254         // evaluation. But we get the first error that occurs. We will still try
255         // and draw the remaining elements in the order they appear in the
256         // layout tuple.
257         return (std::get<Elements>(layout).draw(drawPixel) || ...);
258     }
259 };
260 
261 }  // namespace layouts
262 }  // namespace teeui
263