blob: 0014e45f14120c342b160b2f7d206f8cf4aae1c6 [file] [log] [blame]
Tianjie Xu5fe5eb62018-03-20 16:07:39 -07001/*
2 * Copyright (C) 2018 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
Tao Bao1fe1afe2018-05-01 15:56:05 -070017#include <stddef.h>
Tao Bao152e0eb2018-05-13 00:34:45 -070018#include <stdio.h>
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070019
Tao Bao6cd81682018-05-03 21:53:11 -070020#include <functional>
21#include <map>
22#include <memory>
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070023#include <string>
Tao Bao1fe1afe2018-05-01 15:56:05 -070024#include <vector>
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070025
Tao Bao6cd81682018-05-03 21:53:11 -070026#include <android-base/logging.h>
Tao Bao152e0eb2018-05-13 00:34:45 -070027#include <android-base/stringprintf.h>
28#include <android-base/test_utils.h>
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070029#include <gtest/gtest.h>
30
Tao Bao6cd81682018-05-03 21:53:11 -070031#include "common/test_constants.h"
32#include "device.h"
Tao Bao51f16ec2018-06-04 11:40:20 -070033#include "minui/minui.h"
Tao Bao6cd81682018-05-03 21:53:11 -070034#include "otautil/paths.h"
35#include "private/resources.h"
Tao Bao1fe1afe2018-05-01 15:56:05 -070036#include "screen_ui.h"
37
38static const std::vector<std::string> HEADERS{ "header" };
39static const std::vector<std::string> ITEMS{ "item1", "item2", "item3", "item4", "1234567890" };
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070040
Tianjie Xu66dbf632018-10-11 16:54:50 -070041// TODO(xunchang) check if some draw functions are called when drawing menus.
42class MockDrawFunctions : public DrawInterface {
43 void SetColor(UIElement /* element */) const override {}
44 void DrawHighlightBar(int /* x */, int /* y */, int /* width */,
Tao Bao65815b62018-10-23 10:54:02 -070045 int /* height */) const override {}
Tianjie Xu66dbf632018-10-11 16:54:50 -070046 int DrawHorizontalRule(int /* y */) const override {
47 return 0;
Tao Bao65815b62018-10-23 10:54:02 -070048 }
Tianjie Xu66dbf632018-10-11 16:54:50 -070049 int DrawTextLine(int /* x */, int /* y */, const std::string& /* line */,
50 bool /* bold */) const override {
51 return 0;
Tao Bao65815b62018-10-23 10:54:02 -070052 }
53 void DrawSurface(const GRSurface* /* surface */, int /* sx */, int /* sy */, int /* w */,
54 int /* h */, int /* dx */, int /* dy */) const override {}
55 void DrawFill(int /* x */, int /* y */, int /* w */, int /* h */) const override {}
56 void DrawTextIcon(int /* x */, int /* y */, const GRSurface* /* surface */) const override {}
Tianjie Xu66dbf632018-10-11 16:54:50 -070057 int DrawTextLines(int /* x */, int /* y */,
58 const std::vector<std::string>& /* lines */) const override {
59 return 0;
Tao Bao65815b62018-10-23 10:54:02 -070060 }
Tianjie Xu66dbf632018-10-11 16:54:50 -070061 int DrawWrappedTextLines(int /* x */, int /* y */,
62 const std::vector<std::string>& /* lines */) const override {
63 return 0;
Tao Bao65815b62018-10-23 10:54:02 -070064 }
Tianjie Xu66dbf632018-10-11 16:54:50 -070065};
66
67class ScreenUITest : public testing::Test {
68 protected:
69 MockDrawFunctions draw_funcs_;
70};
71
Tianjie Xu1e10cc42018-10-23 12:10:46 -070072// TODO(xunchang) Create a constructor.
73static GRSurface CreateFakeGRSurface(int width, int height, int row_bytes, int pixel_bytes) {
74 GRSurface fake_surface;
75 fake_surface.width = width;
76 fake_surface.height = height;
77 fake_surface.row_bytes = row_bytes;
78 fake_surface.pixel_bytes = pixel_bytes;
79
80 return fake_surface;
81}
82
Tianjie Xu66dbf632018-10-11 16:54:50 -070083TEST_F(ScreenUITest, StartPhoneMenuSmoke) {
84 TextMenu menu(false, 10, 20, HEADERS, ITEMS, 0, 20, draw_funcs_);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070085 ASSERT_FALSE(menu.scrollable());
Tao Bao1fe1afe2018-05-01 15:56:05 -070086 ASSERT_EQ(HEADERS[0], menu.text_headers()[0]);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070087 ASSERT_EQ(5u, menu.ItemsCount());
88
89 std::string message;
90 ASSERT_FALSE(menu.ItemsOverflow(&message));
91 for (size_t i = 0; i < menu.ItemsCount(); i++) {
92 ASSERT_EQ(ITEMS[i], menu.TextItem(i));
93 }
94
95 ASSERT_EQ(0, menu.selection());
96}
97
Tianjie Xu66dbf632018-10-11 16:54:50 -070098TEST_F(ScreenUITest, StartWearMenuSmoke) {
99 TextMenu menu(true, 10, 8, HEADERS, ITEMS, 1, 20, draw_funcs_);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700100 ASSERT_TRUE(menu.scrollable());
Tao Bao1fe1afe2018-05-01 15:56:05 -0700101 ASSERT_EQ(HEADERS[0], menu.text_headers()[0]);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700102 ASSERT_EQ(5u, menu.ItemsCount());
103
104 std::string message;
105 ASSERT_FALSE(menu.ItemsOverflow(&message));
106 for (size_t i = 0; i < menu.ItemsCount() - 1; i++) {
107 ASSERT_EQ(ITEMS[i], menu.TextItem(i));
108 }
109 // Test of the last item is truncated
110 ASSERT_EQ("12345678", menu.TextItem(4));
111 ASSERT_EQ(1, menu.selection());
112}
113
Tianjie Xu66dbf632018-10-11 16:54:50 -0700114TEST_F(ScreenUITest, StartPhoneMenuItemsOverflow) {
115 TextMenu menu(false, 1, 20, HEADERS, ITEMS, 0, 20, draw_funcs_);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700116 ASSERT_FALSE(menu.scrollable());
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700117 ASSERT_EQ(1u, menu.ItemsCount());
118
119 std::string message;
120 ASSERT_FALSE(menu.ItemsOverflow(&message));
121 for (size_t i = 0; i < menu.ItemsCount(); i++) {
122 ASSERT_EQ(ITEMS[i], menu.TextItem(i));
123 }
124
125 ASSERT_EQ(0u, menu.MenuStart());
126 ASSERT_EQ(1u, menu.MenuEnd());
127}
128
Tianjie Xu66dbf632018-10-11 16:54:50 -0700129TEST_F(ScreenUITest, StartWearMenuItemsOverflow) {
130 TextMenu menu(true, 1, 20, HEADERS, ITEMS, 0, 20, draw_funcs_);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700131 ASSERT_TRUE(menu.scrollable());
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700132 ASSERT_EQ(5u, menu.ItemsCount());
133
134 std::string message;
135 ASSERT_TRUE(menu.ItemsOverflow(&message));
136 ASSERT_EQ("Current item: 1/5", message);
137
138 for (size_t i = 0; i < menu.ItemsCount(); i++) {
139 ASSERT_EQ(ITEMS[i], menu.TextItem(i));
140 }
141
142 ASSERT_EQ(0u, menu.MenuStart());
143 ASSERT_EQ(1u, menu.MenuEnd());
144}
145
Tianjie Xu66dbf632018-10-11 16:54:50 -0700146TEST_F(ScreenUITest, PhoneMenuSelectSmoke) {
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700147 int sel = 0;
Tianjie Xu66dbf632018-10-11 16:54:50 -0700148 TextMenu menu(false, 10, 20, HEADERS, ITEMS, sel, 20, draw_funcs_);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700149 // Mimic down button 10 times (2 * items size)
150 for (int i = 0; i < 10; i++) {
151 sel = menu.Select(++sel);
152 ASSERT_EQ(sel, menu.selection());
153
154 // Wraps the selection for unscrollable menu when it reaches the boundary.
155 int expected = (i + 1) % 5;
156 ASSERT_EQ(expected, menu.selection());
157
158 ASSERT_EQ(0u, menu.MenuStart());
159 ASSERT_EQ(5u, menu.MenuEnd());
160 }
161
162 // Mimic up button 10 times
163 for (int i = 0; i < 10; i++) {
164 sel = menu.Select(--sel);
165 ASSERT_EQ(sel, menu.selection());
166
167 int expected = (9 - i) % 5;
168 ASSERT_EQ(expected, menu.selection());
169
170 ASSERT_EQ(0u, menu.MenuStart());
171 ASSERT_EQ(5u, menu.MenuEnd());
172 }
173}
174
Tianjie Xu66dbf632018-10-11 16:54:50 -0700175TEST_F(ScreenUITest, WearMenuSelectSmoke) {
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700176 int sel = 0;
Tianjie Xu66dbf632018-10-11 16:54:50 -0700177 TextMenu menu(true, 10, 20, HEADERS, ITEMS, sel, 20, draw_funcs_);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700178 // Mimic pressing down button 10 times (2 * items size)
179 for (int i = 0; i < 10; i++) {
180 sel = menu.Select(++sel);
181 ASSERT_EQ(sel, menu.selection());
182
183 // Stops the selection at the boundary if the menu is scrollable.
184 int expected = std::min(i + 1, 4);
185 ASSERT_EQ(expected, menu.selection());
186
187 ASSERT_EQ(0u, menu.MenuStart());
188 ASSERT_EQ(5u, menu.MenuEnd());
189 }
190
191 // Mimic pressing up button 10 times
192 for (int i = 0; i < 10; i++) {
193 sel = menu.Select(--sel);
194 ASSERT_EQ(sel, menu.selection());
195
196 int expected = std::max(3 - i, 0);
197 ASSERT_EQ(expected, menu.selection());
198
199 ASSERT_EQ(0u, menu.MenuStart());
200 ASSERT_EQ(5u, menu.MenuEnd());
201 }
202}
203
Tianjie Xu66dbf632018-10-11 16:54:50 -0700204TEST_F(ScreenUITest, WearMenuSelectItemsOverflow) {
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700205 int sel = 1;
Tianjie Xu66dbf632018-10-11 16:54:50 -0700206 TextMenu menu(true, 3, 20, HEADERS, ITEMS, sel, 20, draw_funcs_);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700207 ASSERT_EQ(5u, menu.ItemsCount());
208
209 // Scroll the menu to the end, and check the start & end of menu.
210 for (int i = 0; i < 3; i++) {
211 sel = menu.Select(++sel);
212 ASSERT_EQ(i + 2, sel);
213 ASSERT_EQ(static_cast<size_t>(i), menu.MenuStart());
214 ASSERT_EQ(static_cast<size_t>(i + 3), menu.MenuEnd());
215 }
216
217 // Press down button one more time won't change the MenuStart() and MenuEnd().
218 sel = menu.Select(++sel);
219 ASSERT_EQ(4, sel);
220 ASSERT_EQ(2u, menu.MenuStart());
221 ASSERT_EQ(5u, menu.MenuEnd());
222
223 // Scroll the menu to the top.
224 // The expected menu sel, start & ends are:
225 // sel 3, start 2, end 5
226 // sel 2, start 2, end 5
227 // sel 1, start 1, end 4
228 // sel 0, start 0, end 3
229 for (int i = 0; i < 4; i++) {
230 sel = menu.Select(--sel);
231 ASSERT_EQ(3 - i, sel);
232 ASSERT_EQ(static_cast<size_t>(std::min(3 - i, 2)), menu.MenuStart());
233 ASSERT_EQ(static_cast<size_t>(std::min(6 - i, 5)), menu.MenuEnd());
234 }
235
236 // Press up button one more time won't change the MenuStart() and MenuEnd().
237 sel = menu.Select(--sel);
238 ASSERT_EQ(0, sel);
239 ASSERT_EQ(0u, menu.MenuStart());
240 ASSERT_EQ(3u, menu.MenuEnd());
241}
Tao Bao6cd81682018-05-03 21:53:11 -0700242
Tianjie Xub99e6062018-10-16 15:13:09 -0700243TEST_F(ScreenUITest, GraphicMenuSelection) {
Tianjie Xu1e10cc42018-10-23 12:10:46 -0700244 auto fake_surface = CreateFakeGRSurface(50, 50, 50, 1);
Tianjie Xub99e6062018-10-16 15:13:09 -0700245 std::vector<GRSurface*> items = { &fake_surface, &fake_surface, &fake_surface };
246 GraphicMenu menu(&fake_surface, items, 0, draw_funcs_);
247
248 ASSERT_EQ(0, menu.selection());
249
250 int sel = 0;
251 for (int i = 0; i < 3; i++) {
252 sel = menu.Select(++sel);
253 ASSERT_EQ((i + 1) % 3, sel);
254 ASSERT_EQ(sel, menu.selection());
255 }
256
257 sel = 0;
258 for (int i = 0; i < 3; i++) {
259 sel = menu.Select(--sel);
260 ASSERT_EQ(2 - i, sel);
261 ASSERT_EQ(sel, menu.selection());
262 }
263}
264
265TEST_F(ScreenUITest, GraphicMenuValidate) {
Tianjie Xu1e10cc42018-10-23 12:10:46 -0700266 auto fake_surface = CreateFakeGRSurface(50, 50, 50, 1);
Tianjie Xub99e6062018-10-16 15:13:09 -0700267 std::vector<GRSurface*> items = { &fake_surface, &fake_surface, &fake_surface };
268
269 ASSERT_TRUE(GraphicMenu::Validate(200, 200, &fake_surface, items));
270
271 // Menu exceeds the horizontal boundary.
Tianjie Xu1e10cc42018-10-23 12:10:46 -0700272 auto wide_surface = CreateFakeGRSurface(300, 50, 300, 1);
Tianjie Xub99e6062018-10-16 15:13:09 -0700273 ASSERT_FALSE(GraphicMenu::Validate(299, 200, &wide_surface, items));
274
275 // Menu exceeds the vertical boundary.
276 items.push_back(&fake_surface);
277 ASSERT_FALSE(GraphicMenu::Validate(200, 249, &fake_surface, items));
278}
279
Tao Bao6cd81682018-05-03 21:53:11 -0700280static constexpr int kMagicAction = 101;
281
282enum class KeyCode : int {
283 TIMEOUT = -1,
284 NO_OP = 0,
285 UP = 1,
286 DOWN = 2,
287 ENTER = 3,
288 MAGIC = 1001,
289 LAST,
290};
291
292static const std::map<KeyCode, int> kKeyMapping{
293 // clang-format off
294 { KeyCode::NO_OP, Device::kNoAction },
295 { KeyCode::UP, Device::kHighlightUp },
296 { KeyCode::DOWN, Device::kHighlightDown },
297 { KeyCode::ENTER, Device::kInvokeItem },
298 { KeyCode::MAGIC, kMagicAction },
299 // clang-format on
300};
301
302class TestableScreenRecoveryUI : public ScreenRecoveryUI {
303 public:
304 int WaitKey() override;
305
306 void SetKeyBuffer(const std::vector<KeyCode>& buffer);
307
308 int KeyHandler(int key, bool visible) const;
309
Tao Bao152e0eb2018-05-13 00:34:45 -0700310 // The following functions expose the protected members for test purpose.
311 void RunLoadAnimation() {
312 LoadAnimation();
313 }
314
315 size_t GetLoopFrames() const {
316 return loop_frames;
317 }
318
319 size_t GetIntroFrames() const {
320 return intro_frames;
321 }
322
Tao Bao6cd81682018-05-03 21:53:11 -0700323 bool GetRtlLocale() const {
324 return rtl_locale_;
325 }
326
327 private:
328 std::vector<KeyCode> key_buffer_;
329 size_t key_buffer_index_;
330};
331
332void TestableScreenRecoveryUI::SetKeyBuffer(const std::vector<KeyCode>& buffer) {
333 key_buffer_ = buffer;
334 key_buffer_index_ = 0;
335}
336
337int TestableScreenRecoveryUI::KeyHandler(int key, bool) const {
338 KeyCode key_code = static_cast<KeyCode>(key);
339 if (kKeyMapping.find(key_code) != kKeyMapping.end()) {
340 return kKeyMapping.at(key_code);
341 }
342 return Device::kNoAction;
343}
344
345int TestableScreenRecoveryUI::WaitKey() {
Jerry Zhangb76af932018-05-22 12:08:35 -0700346 if (IsKeyInterrupted()) {
347 return static_cast<int>(RecoveryUI::KeyError::INTERRUPTED);
348 }
349
Tao Bao6cd81682018-05-03 21:53:11 -0700350 CHECK_LT(key_buffer_index_, key_buffer_.size());
351 return static_cast<int>(key_buffer_[key_buffer_index_++]);
352}
353
354class ScreenRecoveryUITest : public ::testing::Test {
355 protected:
356 const std::string kTestLocale = "en-US";
357 const std::string kTestRtlLocale = "ar";
Tao Bao347a6592018-05-08 15:58:29 -0700358 const std::string kTestRtlLocaleWithSuffix = "ar-EG";
Tao Bao6cd81682018-05-03 21:53:11 -0700359
360 void SetUp() override {
Tao Bao51f16ec2018-06-04 11:40:20 -0700361 has_graphics_ = gr_init() == 0;
362 gr_exit();
363
364 if (has_graphics_) {
365 ui_ = std::make_unique<TestableScreenRecoveryUI>();
366 }
Tao Bao6cd81682018-05-03 21:53:11 -0700367
Tao Bao152e0eb2018-05-13 00:34:45 -0700368 testdata_dir_ = from_testdata_base("");
369 Paths::Get().set_resource_dir(testdata_dir_);
370 res_set_resource_dir(testdata_dir_);
Tao Bao6cd81682018-05-03 21:53:11 -0700371 }
372
Tao Bao51f16ec2018-06-04 11:40:20 -0700373 bool has_graphics_;
Tao Bao6cd81682018-05-03 21:53:11 -0700374 std::unique_ptr<TestableScreenRecoveryUI> ui_;
Tao Bao152e0eb2018-05-13 00:34:45 -0700375 std::string testdata_dir_;
Tao Bao6cd81682018-05-03 21:53:11 -0700376};
377
Tao Bao51f16ec2018-06-04 11:40:20 -0700378#define RETURN_IF_NO_GRAPHICS \
379 do { \
380 if (!has_graphics_) { \
381 GTEST_LOG_(INFO) << "Test skipped due to no available graphics device"; \
382 return; \
383 } \
384 } while (false)
385
Tao Bao6cd81682018-05-03 21:53:11 -0700386TEST_F(ScreenRecoveryUITest, Init) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700387 RETURN_IF_NO_GRAPHICS;
388
Tao Bao26ea9592018-05-09 16:32:02 -0700389 ASSERT_TRUE(ui_->Init(kTestLocale));
Tao Bao6cd81682018-05-03 21:53:11 -0700390 ASSERT_EQ(kTestLocale, ui_->GetLocale());
391 ASSERT_FALSE(ui_->GetRtlLocale());
392 ASSERT_FALSE(ui_->IsTextVisible());
393 ASSERT_FALSE(ui_->WasTextEverVisible());
394}
395
Tao Bao94371fd2018-06-06 07:38:54 -0700396TEST_F(ScreenRecoveryUITest, dtor_NotCallingInit) {
397 ui_.reset();
398 ASSERT_FALSE(ui_);
399}
400
Tao Bao6cd81682018-05-03 21:53:11 -0700401TEST_F(ScreenRecoveryUITest, ShowText) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700402 RETURN_IF_NO_GRAPHICS;
403
Tao Bao26ea9592018-05-09 16:32:02 -0700404 ASSERT_TRUE(ui_->Init(kTestLocale));
Tao Bao6cd81682018-05-03 21:53:11 -0700405 ASSERT_FALSE(ui_->IsTextVisible());
406 ui_->ShowText(true);
407 ASSERT_TRUE(ui_->IsTextVisible());
408 ASSERT_TRUE(ui_->WasTextEverVisible());
409
410 ui_->ShowText(false);
411 ASSERT_FALSE(ui_->IsTextVisible());
412 ASSERT_TRUE(ui_->WasTextEverVisible());
413}
414
415TEST_F(ScreenRecoveryUITest, RtlLocale) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700416 RETURN_IF_NO_GRAPHICS;
417
Tao Bao6cd81682018-05-03 21:53:11 -0700418 ASSERT_TRUE(ui_->Init(kTestRtlLocale));
419 ASSERT_TRUE(ui_->GetRtlLocale());
Tao Bao26ea9592018-05-09 16:32:02 -0700420}
Tao Bao6cd81682018-05-03 21:53:11 -0700421
Tao Bao26ea9592018-05-09 16:32:02 -0700422TEST_F(ScreenRecoveryUITest, RtlLocaleWithSuffix) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700423 RETURN_IF_NO_GRAPHICS;
424
Tao Bao6cd81682018-05-03 21:53:11 -0700425 ASSERT_TRUE(ui_->Init(kTestRtlLocaleWithSuffix));
426 ASSERT_TRUE(ui_->GetRtlLocale());
427}
428
429TEST_F(ScreenRecoveryUITest, ShowMenu) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700430 RETURN_IF_NO_GRAPHICS;
431
Tao Bao26ea9592018-05-09 16:32:02 -0700432 ASSERT_TRUE(ui_->Init(kTestLocale));
Tao Bao6cd81682018-05-03 21:53:11 -0700433 ui_->SetKeyBuffer({
434 KeyCode::UP,
435 KeyCode::DOWN,
436 KeyCode::UP,
437 KeyCode::DOWN,
438 KeyCode::ENTER,
439 });
440 ASSERT_EQ(3u, ui_->ShowMenu(HEADERS, ITEMS, 3, true,
441 std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
442 std::placeholders::_1, std::placeholders::_2)));
443
444 ui_->SetKeyBuffer({
445 KeyCode::UP,
446 KeyCode::UP,
447 KeyCode::NO_OP,
448 KeyCode::NO_OP,
449 KeyCode::UP,
450 KeyCode::ENTER,
451 });
452 ASSERT_EQ(2u, ui_->ShowMenu(HEADERS, ITEMS, 0, true,
453 std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
454 std::placeholders::_1, std::placeholders::_2)));
455}
456
457TEST_F(ScreenRecoveryUITest, ShowMenu_NotMenuOnly) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700458 RETURN_IF_NO_GRAPHICS;
459
Tao Bao26ea9592018-05-09 16:32:02 -0700460 ASSERT_TRUE(ui_->Init(kTestLocale));
Tao Bao6cd81682018-05-03 21:53:11 -0700461 ui_->SetKeyBuffer({
462 KeyCode::MAGIC,
463 });
464 ASSERT_EQ(static_cast<size_t>(kMagicAction),
465 ui_->ShowMenu(HEADERS, ITEMS, 3, false,
466 std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
467 std::placeholders::_1, std::placeholders::_2)));
468}
469
470TEST_F(ScreenRecoveryUITest, ShowMenu_TimedOut) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700471 RETURN_IF_NO_GRAPHICS;
472
Tao Bao26ea9592018-05-09 16:32:02 -0700473 ASSERT_TRUE(ui_->Init(kTestLocale));
Tao Bao6cd81682018-05-03 21:53:11 -0700474 ui_->SetKeyBuffer({
475 KeyCode::TIMEOUT,
476 });
Jerry Zhangb76af932018-05-22 12:08:35 -0700477 ASSERT_EQ(static_cast<size_t>(RecoveryUI::KeyError::TIMED_OUT),
478 ui_->ShowMenu(HEADERS, ITEMS, 3, true, nullptr));
Tao Bao6cd81682018-05-03 21:53:11 -0700479}
480
481TEST_F(ScreenRecoveryUITest, ShowMenu_TimedOut_TextWasEverVisible) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700482 RETURN_IF_NO_GRAPHICS;
483
Tao Bao26ea9592018-05-09 16:32:02 -0700484 ASSERT_TRUE(ui_->Init(kTestLocale));
Tao Bao6cd81682018-05-03 21:53:11 -0700485 ui_->ShowText(true);
486 ui_->ShowText(false);
487 ASSERT_TRUE(ui_->WasTextEverVisible());
488
489 ui_->SetKeyBuffer({
490 KeyCode::TIMEOUT,
491 KeyCode::DOWN,
492 KeyCode::ENTER,
493 });
494 ASSERT_EQ(4u, ui_->ShowMenu(HEADERS, ITEMS, 3, true,
495 std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
496 std::placeholders::_1, std::placeholders::_2)));
497}
Tao Bao152e0eb2018-05-13 00:34:45 -0700498
Jerry Zhangb76af932018-05-22 12:08:35 -0700499TEST_F(ScreenRecoveryUITest, ShowMenuWithInterrupt) {
500 RETURN_IF_NO_GRAPHICS;
501
502 ASSERT_TRUE(ui_->Init(kTestLocale));
503 ui_->SetKeyBuffer({
504 KeyCode::UP,
505 KeyCode::DOWN,
506 KeyCode::UP,
507 KeyCode::DOWN,
508 KeyCode::ENTER,
509 });
510
511 ui_->InterruptKey();
512 ASSERT_EQ(static_cast<size_t>(RecoveryUI::KeyError::INTERRUPTED),
513 ui_->ShowMenu(HEADERS, ITEMS, 3, true,
514 std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
515 std::placeholders::_1, std::placeholders::_2)));
516
517 ui_->SetKeyBuffer({
518 KeyCode::UP,
519 KeyCode::UP,
520 KeyCode::NO_OP,
521 KeyCode::NO_OP,
522 KeyCode::UP,
523 KeyCode::ENTER,
524 });
525 ASSERT_EQ(static_cast<size_t>(RecoveryUI::KeyError::INTERRUPTED),
526 ui_->ShowMenu(HEADERS, ITEMS, 0, true,
527 std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
528 std::placeholders::_1, std::placeholders::_2)));
529}
530
Tao Bao152e0eb2018-05-13 00:34:45 -0700531TEST_F(ScreenRecoveryUITest, LoadAnimation) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700532 RETURN_IF_NO_GRAPHICS;
533
Tao Bao26ea9592018-05-09 16:32:02 -0700534 ASSERT_TRUE(ui_->Init(kTestLocale));
Tao Bao152e0eb2018-05-13 00:34:45 -0700535 // Make a few copies of loop00000.png from testdata.
536 std::string image_data;
537 ASSERT_TRUE(android::base::ReadFileToString(testdata_dir_ + "/loop00000.png", &image_data));
538
539 std::vector<std::string> tempfiles;
540 TemporaryDir resource_dir;
541 for (const auto& name : { "00002", "00100", "00050" }) {
542 tempfiles.push_back(android::base::StringPrintf("%s/loop%s.png", resource_dir.path, name));
543 ASSERT_TRUE(android::base::WriteStringToFile(image_data, tempfiles.back()));
544 }
545 for (const auto& name : { "00", "01" }) {
546 tempfiles.push_back(android::base::StringPrintf("%s/intro%s.png", resource_dir.path, name));
547 ASSERT_TRUE(android::base::WriteStringToFile(image_data, tempfiles.back()));
548 }
549 Paths::Get().set_resource_dir(resource_dir.path);
550
551 ui_->RunLoadAnimation();
552
553 ASSERT_EQ(2u, ui_->GetIntroFrames());
554 ASSERT_EQ(3u, ui_->GetLoopFrames());
555
556 for (const auto& name : tempfiles) {
557 ASSERT_EQ(0, unlink(name.c_str()));
558 }
559}
560
561TEST_F(ScreenRecoveryUITest, LoadAnimation_MissingAnimation) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700562 RETURN_IF_NO_GRAPHICS;
563
Tao Bao26ea9592018-05-09 16:32:02 -0700564 ASSERT_TRUE(ui_->Init(kTestLocale));
Tao Baob1c5b622018-07-12 11:49:05 -0700565 // We need a dir that doesn't contain any animation. However, using TemporaryDir will give
566 // leftovers since this is a death test where TemporaryDir::~TemporaryDir() won't be called.
567 Paths::Get().set_resource_dir("/proc/self");
Tao Bao42be0d42018-06-05 14:03:34 -0700568
569 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
Tao Bao152e0eb2018-05-13 00:34:45 -0700570 ASSERT_EXIT(ui_->RunLoadAnimation(), ::testing::KilledBySignal(SIGABRT), "");
571}
Tao Bao51f16ec2018-06-04 11:40:20 -0700572
573#undef RETURN_IF_NO_GRAPHICS