blob: 09c49977f90eb58d391465593f2bf85b03644b13 [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
Mark Salyzyn8b54bc52018-11-14 15:18:30 -080026#include <android-base/file.h>
Tao Bao6cd81682018-05-03 21:53:11 -070027#include <android-base/logging.h>
Tao Bao152e0eb2018-05-13 00:34:45 -070028#include <android-base/stringprintf.h>
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070029#include <gtest/gtest.h>
Tao Bao929e4812018-06-06 14:28:35 -070030#include <gtest/gtest_prod.h>
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070031
Tao Bao6cd81682018-05-03 21:53:11 -070032#include "common/test_constants.h"
33#include "device.h"
Tao Bao51f16ec2018-06-04 11:40:20 -070034#include "minui/minui.h"
Tao Bao6cd81682018-05-03 21:53:11 -070035#include "otautil/paths.h"
36#include "private/resources.h"
Tao Bao1fe1afe2018-05-01 15:56:05 -070037#include "screen_ui.h"
38
39static const std::vector<std::string> HEADERS{ "header" };
40static const std::vector<std::string> ITEMS{ "item1", "item2", "item3", "item4", "1234567890" };
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070041
Tianjie Xu66dbf632018-10-11 16:54:50 -070042// TODO(xunchang) check if some draw functions are called when drawing menus.
43class MockDrawFunctions : public DrawInterface {
44 void SetColor(UIElement /* element */) const override {}
45 void DrawHighlightBar(int /* x */, int /* y */, int /* width */,
Tao Bao65815b62018-10-23 10:54:02 -070046 int /* height */) const override {}
Tianjie Xu66dbf632018-10-11 16:54:50 -070047 int DrawHorizontalRule(int /* y */) const override {
48 return 0;
Tao Bao65815b62018-10-23 10:54:02 -070049 }
Tianjie Xu66dbf632018-10-11 16:54:50 -070050 int DrawTextLine(int /* x */, int /* y */, const std::string& /* line */,
51 bool /* bold */) const override {
52 return 0;
Tao Bao65815b62018-10-23 10:54:02 -070053 }
54 void DrawSurface(const GRSurface* /* surface */, int /* sx */, int /* sy */, int /* w */,
55 int /* h */, int /* dx */, int /* dy */) const override {}
56 void DrawFill(int /* x */, int /* y */, int /* w */, int /* h */) const override {}
57 void DrawTextIcon(int /* x */, int /* y */, const GRSurface* /* surface */) const override {}
Tianjie Xu66dbf632018-10-11 16:54:50 -070058 int DrawTextLines(int /* x */, int /* y */,
59 const std::vector<std::string>& /* lines */) const override {
60 return 0;
Tao Bao65815b62018-10-23 10:54:02 -070061 }
Tianjie Xu66dbf632018-10-11 16:54:50 -070062 int DrawWrappedTextLines(int /* x */, int /* y */,
63 const std::vector<std::string>& /* lines */) const override {
64 return 0;
Tao Bao65815b62018-10-23 10:54:02 -070065 }
Tianjie Xu66dbf632018-10-11 16:54:50 -070066};
67
68class ScreenUITest : public testing::Test {
69 protected:
70 MockDrawFunctions draw_funcs_;
71};
72
73TEST_F(ScreenUITest, StartPhoneMenuSmoke) {
74 TextMenu menu(false, 10, 20, HEADERS, ITEMS, 0, 20, draw_funcs_);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070075 ASSERT_FALSE(menu.scrollable());
Tao Bao1fe1afe2018-05-01 15:56:05 -070076 ASSERT_EQ(HEADERS[0], menu.text_headers()[0]);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070077 ASSERT_EQ(5u, menu.ItemsCount());
78
79 std::string message;
80 ASSERT_FALSE(menu.ItemsOverflow(&message));
81 for (size_t i = 0; i < menu.ItemsCount(); i++) {
82 ASSERT_EQ(ITEMS[i], menu.TextItem(i));
83 }
84
85 ASSERT_EQ(0, menu.selection());
86}
87
Tianjie Xu66dbf632018-10-11 16:54:50 -070088TEST_F(ScreenUITest, StartWearMenuSmoke) {
89 TextMenu menu(true, 10, 8, HEADERS, ITEMS, 1, 20, draw_funcs_);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070090 ASSERT_TRUE(menu.scrollable());
Tao Bao1fe1afe2018-05-01 15:56:05 -070091 ASSERT_EQ(HEADERS[0], menu.text_headers()[0]);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070092 ASSERT_EQ(5u, menu.ItemsCount());
93
94 std::string message;
95 ASSERT_FALSE(menu.ItemsOverflow(&message));
96 for (size_t i = 0; i < menu.ItemsCount() - 1; i++) {
97 ASSERT_EQ(ITEMS[i], menu.TextItem(i));
98 }
99 // Test of the last item is truncated
100 ASSERT_EQ("12345678", menu.TextItem(4));
101 ASSERT_EQ(1, menu.selection());
102}
103
Tianjie Xu66dbf632018-10-11 16:54:50 -0700104TEST_F(ScreenUITest, StartPhoneMenuItemsOverflow) {
105 TextMenu menu(false, 1, 20, HEADERS, ITEMS, 0, 20, draw_funcs_);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700106 ASSERT_FALSE(menu.scrollable());
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700107 ASSERT_EQ(1u, menu.ItemsCount());
108
109 std::string message;
110 ASSERT_FALSE(menu.ItemsOverflow(&message));
111 for (size_t i = 0; i < menu.ItemsCount(); i++) {
112 ASSERT_EQ(ITEMS[i], menu.TextItem(i));
113 }
114
115 ASSERT_EQ(0u, menu.MenuStart());
116 ASSERT_EQ(1u, menu.MenuEnd());
117}
118
Tianjie Xu66dbf632018-10-11 16:54:50 -0700119TEST_F(ScreenUITest, StartWearMenuItemsOverflow) {
120 TextMenu menu(true, 1, 20, HEADERS, ITEMS, 0, 20, draw_funcs_);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700121 ASSERT_TRUE(menu.scrollable());
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700122 ASSERT_EQ(5u, menu.ItemsCount());
123
124 std::string message;
125 ASSERT_TRUE(menu.ItemsOverflow(&message));
126 ASSERT_EQ("Current item: 1/5", message);
127
128 for (size_t i = 0; i < menu.ItemsCount(); i++) {
129 ASSERT_EQ(ITEMS[i], menu.TextItem(i));
130 }
131
132 ASSERT_EQ(0u, menu.MenuStart());
133 ASSERT_EQ(1u, menu.MenuEnd());
134}
135
Tianjie Xu66dbf632018-10-11 16:54:50 -0700136TEST_F(ScreenUITest, PhoneMenuSelectSmoke) {
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700137 int sel = 0;
Tianjie Xu66dbf632018-10-11 16:54:50 -0700138 TextMenu menu(false, 10, 20, HEADERS, ITEMS, sel, 20, draw_funcs_);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700139 // Mimic down button 10 times (2 * items size)
140 for (int i = 0; i < 10; i++) {
141 sel = menu.Select(++sel);
142 ASSERT_EQ(sel, menu.selection());
143
144 // Wraps the selection for unscrollable menu when it reaches the boundary.
145 int expected = (i + 1) % 5;
146 ASSERT_EQ(expected, menu.selection());
147
148 ASSERT_EQ(0u, menu.MenuStart());
149 ASSERT_EQ(5u, menu.MenuEnd());
150 }
151
152 // Mimic up button 10 times
153 for (int i = 0; i < 10; i++) {
154 sel = menu.Select(--sel);
155 ASSERT_EQ(sel, menu.selection());
156
157 int expected = (9 - i) % 5;
158 ASSERT_EQ(expected, menu.selection());
159
160 ASSERT_EQ(0u, menu.MenuStart());
161 ASSERT_EQ(5u, menu.MenuEnd());
162 }
163}
164
Tianjie Xu66dbf632018-10-11 16:54:50 -0700165TEST_F(ScreenUITest, WearMenuSelectSmoke) {
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700166 int sel = 0;
Tianjie Xu66dbf632018-10-11 16:54:50 -0700167 TextMenu menu(true, 10, 20, HEADERS, ITEMS, sel, 20, draw_funcs_);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700168 // Mimic pressing down button 10 times (2 * items size)
169 for (int i = 0; i < 10; i++) {
170 sel = menu.Select(++sel);
171 ASSERT_EQ(sel, menu.selection());
172
173 // Stops the selection at the boundary if the menu is scrollable.
174 int expected = std::min(i + 1, 4);
175 ASSERT_EQ(expected, menu.selection());
176
177 ASSERT_EQ(0u, menu.MenuStart());
178 ASSERT_EQ(5u, menu.MenuEnd());
179 }
180
181 // Mimic pressing up button 10 times
182 for (int i = 0; i < 10; i++) {
183 sel = menu.Select(--sel);
184 ASSERT_EQ(sel, menu.selection());
185
186 int expected = std::max(3 - i, 0);
187 ASSERT_EQ(expected, menu.selection());
188
189 ASSERT_EQ(0u, menu.MenuStart());
190 ASSERT_EQ(5u, menu.MenuEnd());
191 }
192}
193
Tianjie Xu66dbf632018-10-11 16:54:50 -0700194TEST_F(ScreenUITest, WearMenuSelectItemsOverflow) {
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700195 int sel = 1;
Tianjie Xu66dbf632018-10-11 16:54:50 -0700196 TextMenu menu(true, 3, 20, HEADERS, ITEMS, sel, 20, draw_funcs_);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700197 ASSERT_EQ(5u, menu.ItemsCount());
198
199 // Scroll the menu to the end, and check the start & end of menu.
200 for (int i = 0; i < 3; i++) {
201 sel = menu.Select(++sel);
202 ASSERT_EQ(i + 2, sel);
203 ASSERT_EQ(static_cast<size_t>(i), menu.MenuStart());
204 ASSERT_EQ(static_cast<size_t>(i + 3), menu.MenuEnd());
205 }
206
207 // Press down button one more time won't change the MenuStart() and MenuEnd().
208 sel = menu.Select(++sel);
209 ASSERT_EQ(4, sel);
210 ASSERT_EQ(2u, menu.MenuStart());
211 ASSERT_EQ(5u, menu.MenuEnd());
212
213 // Scroll the menu to the top.
214 // The expected menu sel, start & ends are:
215 // sel 3, start 2, end 5
216 // sel 2, start 2, end 5
217 // sel 1, start 1, end 4
218 // sel 0, start 0, end 3
219 for (int i = 0; i < 4; i++) {
220 sel = menu.Select(--sel);
221 ASSERT_EQ(3 - i, sel);
222 ASSERT_EQ(static_cast<size_t>(std::min(3 - i, 2)), menu.MenuStart());
223 ASSERT_EQ(static_cast<size_t>(std::min(6 - i, 5)), menu.MenuEnd());
224 }
225
226 // Press up button one more time won't change the MenuStart() and MenuEnd().
227 sel = menu.Select(--sel);
228 ASSERT_EQ(0, sel);
229 ASSERT_EQ(0u, menu.MenuStart());
230 ASSERT_EQ(3u, menu.MenuEnd());
231}
Tao Bao6cd81682018-05-03 21:53:11 -0700232
Tianjie Xub99e6062018-10-16 15:13:09 -0700233TEST_F(ScreenUITest, GraphicMenuSelection) {
Tao Baoda409fb2018-10-21 23:36:26 -0700234 auto image = GRSurface::Create(50, 50, 50, 1, 50 * 50);
235 auto header = image->Clone();
236 std::vector<const GRSurface*> items = {
237 image.get(),
238 image.get(),
239 image.get(),
Tao Bao44820ac2018-10-30 23:34:50 -0700240 };
241 GraphicMenu menu(header.get(), items, 0, draw_funcs_);
Tianjie Xub99e6062018-10-16 15:13:09 -0700242
243 ASSERT_EQ(0, menu.selection());
244
245 int sel = 0;
246 for (int i = 0; i < 3; i++) {
247 sel = menu.Select(++sel);
248 ASSERT_EQ((i + 1) % 3, sel);
249 ASSERT_EQ(sel, menu.selection());
250 }
251
252 sel = 0;
253 for (int i = 0; i < 3; i++) {
254 sel = menu.Select(--sel);
255 ASSERT_EQ(2 - i, sel);
256 ASSERT_EQ(sel, menu.selection());
257 }
258}
259
260TEST_F(ScreenUITest, GraphicMenuValidate) {
Tao Baoda409fb2018-10-21 23:36:26 -0700261 auto image = GRSurface::Create(50, 50, 50, 1, 50 * 50);
262 auto header = image->Clone();
263 std::vector<const GRSurface*> items = {
264 image.get(),
265 image.get(),
266 image.get(),
Tao Bao44820ac2018-10-30 23:34:50 -0700267 };
Tianjie Xub99e6062018-10-16 15:13:09 -0700268
Tao Bao44820ac2018-10-30 23:34:50 -0700269 ASSERT_TRUE(GraphicMenu::Validate(200, 200, header.get(), items));
Tianjie Xub99e6062018-10-16 15:13:09 -0700270
271 // Menu exceeds the horizontal boundary.
Tao Bao44820ac2018-10-30 23:34:50 -0700272 auto wide_surface = GRSurface::Create(300, 50, 300, 1, 300 * 50);
273 ASSERT_FALSE(GraphicMenu::Validate(299, 200, wide_surface.get(), items));
Tianjie Xub99e6062018-10-16 15:13:09 -0700274
275 // Menu exceeds the vertical boundary.
Tao Baoda409fb2018-10-21 23:36:26 -0700276 items.emplace_back(image.get());
Tao Bao44820ac2018-10-30 23:34:50 -0700277 ASSERT_FALSE(GraphicMenu::Validate(200, 249, header.get(), items));
Tianjie Xub99e6062018-10-16 15:13:09 -0700278}
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 Bao6cd81682018-05-03 21:53:11 -0700310 private:
Tao Bao929e4812018-06-06 14:28:35 -0700311 FRIEND_TEST(ScreenRecoveryUITest, Init);
312 FRIEND_TEST(ScreenRecoveryUITest, RtlLocale);
313 FRIEND_TEST(ScreenRecoveryUITest, RtlLocaleWithSuffix);
314 FRIEND_TEST(ScreenRecoveryUITest, LoadAnimation);
315 FRIEND_TEST(ScreenRecoveryUITest, LoadAnimation_MissingAnimation);
316
Tao Bao6cd81682018-05-03 21:53:11 -0700317 std::vector<KeyCode> key_buffer_;
318 size_t key_buffer_index_;
319};
320
321void TestableScreenRecoveryUI::SetKeyBuffer(const std::vector<KeyCode>& buffer) {
322 key_buffer_ = buffer;
323 key_buffer_index_ = 0;
324}
325
326int TestableScreenRecoveryUI::KeyHandler(int key, bool) const {
327 KeyCode key_code = static_cast<KeyCode>(key);
328 if (kKeyMapping.find(key_code) != kKeyMapping.end()) {
329 return kKeyMapping.at(key_code);
330 }
331 return Device::kNoAction;
332}
333
334int TestableScreenRecoveryUI::WaitKey() {
Jerry Zhangb76af932018-05-22 12:08:35 -0700335 if (IsKeyInterrupted()) {
336 return static_cast<int>(RecoveryUI::KeyError::INTERRUPTED);
337 }
338
Tao Bao6cd81682018-05-03 21:53:11 -0700339 CHECK_LT(key_buffer_index_, key_buffer_.size());
340 return static_cast<int>(key_buffer_[key_buffer_index_++]);
341}
342
343class ScreenRecoveryUITest : public ::testing::Test {
344 protected:
345 const std::string kTestLocale = "en-US";
346 const std::string kTestRtlLocale = "ar";
Tao Bao347a6592018-05-08 15:58:29 -0700347 const std::string kTestRtlLocaleWithSuffix = "ar-EG";
Tao Bao6cd81682018-05-03 21:53:11 -0700348
349 void SetUp() override {
Tao Bao51f16ec2018-06-04 11:40:20 -0700350 has_graphics_ = gr_init() == 0;
351 gr_exit();
352
353 if (has_graphics_) {
354 ui_ = std::make_unique<TestableScreenRecoveryUI>();
355 }
Tao Bao6cd81682018-05-03 21:53:11 -0700356
Tao Bao152e0eb2018-05-13 00:34:45 -0700357 testdata_dir_ = from_testdata_base("");
358 Paths::Get().set_resource_dir(testdata_dir_);
359 res_set_resource_dir(testdata_dir_);
Tao Bao6cd81682018-05-03 21:53:11 -0700360 }
361
Tao Bao51f16ec2018-06-04 11:40:20 -0700362 bool has_graphics_;
Tao Bao6cd81682018-05-03 21:53:11 -0700363 std::unique_ptr<TestableScreenRecoveryUI> ui_;
Tao Bao152e0eb2018-05-13 00:34:45 -0700364 std::string testdata_dir_;
Tao Bao6cd81682018-05-03 21:53:11 -0700365};
366
Tao Bao51f16ec2018-06-04 11:40:20 -0700367#define RETURN_IF_NO_GRAPHICS \
368 do { \
369 if (!has_graphics_) { \
370 GTEST_LOG_(INFO) << "Test skipped due to no available graphics device"; \
371 return; \
372 } \
373 } while (false)
374
Tao Bao6cd81682018-05-03 21:53:11 -0700375TEST_F(ScreenRecoveryUITest, Init) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700376 RETURN_IF_NO_GRAPHICS;
377
Tao Bao26ea9592018-05-09 16:32:02 -0700378 ASSERT_TRUE(ui_->Init(kTestLocale));
Tao Bao6cd81682018-05-03 21:53:11 -0700379 ASSERT_EQ(kTestLocale, ui_->GetLocale());
Tao Bao929e4812018-06-06 14:28:35 -0700380 ASSERT_FALSE(ui_->rtl_locale_);
Tao Bao6cd81682018-05-03 21:53:11 -0700381 ASSERT_FALSE(ui_->IsTextVisible());
382 ASSERT_FALSE(ui_->WasTextEverVisible());
383}
384
Tao Bao94371fd2018-06-06 07:38:54 -0700385TEST_F(ScreenRecoveryUITest, dtor_NotCallingInit) {
386 ui_.reset();
387 ASSERT_FALSE(ui_);
388}
389
Tao Bao6cd81682018-05-03 21:53:11 -0700390TEST_F(ScreenRecoveryUITest, ShowText) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700391 RETURN_IF_NO_GRAPHICS;
392
Tao Bao26ea9592018-05-09 16:32:02 -0700393 ASSERT_TRUE(ui_->Init(kTestLocale));
Tao Bao6cd81682018-05-03 21:53:11 -0700394 ASSERT_FALSE(ui_->IsTextVisible());
395 ui_->ShowText(true);
396 ASSERT_TRUE(ui_->IsTextVisible());
397 ASSERT_TRUE(ui_->WasTextEverVisible());
398
399 ui_->ShowText(false);
400 ASSERT_FALSE(ui_->IsTextVisible());
401 ASSERT_TRUE(ui_->WasTextEverVisible());
402}
403
404TEST_F(ScreenRecoveryUITest, RtlLocale) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700405 RETURN_IF_NO_GRAPHICS;
406
Tao Bao6cd81682018-05-03 21:53:11 -0700407 ASSERT_TRUE(ui_->Init(kTestRtlLocale));
Tao Bao929e4812018-06-06 14:28:35 -0700408 ASSERT_TRUE(ui_->rtl_locale_);
Tao Bao26ea9592018-05-09 16:32:02 -0700409}
Tao Bao6cd81682018-05-03 21:53:11 -0700410
Tao Bao26ea9592018-05-09 16:32:02 -0700411TEST_F(ScreenRecoveryUITest, RtlLocaleWithSuffix) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700412 RETURN_IF_NO_GRAPHICS;
413
Tao Bao6cd81682018-05-03 21:53:11 -0700414 ASSERT_TRUE(ui_->Init(kTestRtlLocaleWithSuffix));
Tao Bao929e4812018-06-06 14:28:35 -0700415 ASSERT_TRUE(ui_->rtl_locale_);
Tao Bao6cd81682018-05-03 21:53:11 -0700416}
417
418TEST_F(ScreenRecoveryUITest, ShowMenu) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700419 RETURN_IF_NO_GRAPHICS;
420
Tao Bao26ea9592018-05-09 16:32:02 -0700421 ASSERT_TRUE(ui_->Init(kTestLocale));
Tao Bao6cd81682018-05-03 21:53:11 -0700422 ui_->SetKeyBuffer({
423 KeyCode::UP,
424 KeyCode::DOWN,
425 KeyCode::UP,
426 KeyCode::DOWN,
427 KeyCode::ENTER,
428 });
429 ASSERT_EQ(3u, ui_->ShowMenu(HEADERS, ITEMS, 3, true,
430 std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
431 std::placeholders::_1, std::placeholders::_2)));
432
433 ui_->SetKeyBuffer({
434 KeyCode::UP,
435 KeyCode::UP,
436 KeyCode::NO_OP,
437 KeyCode::NO_OP,
438 KeyCode::UP,
439 KeyCode::ENTER,
440 });
441 ASSERT_EQ(2u, ui_->ShowMenu(HEADERS, ITEMS, 0, true,
442 std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
443 std::placeholders::_1, std::placeholders::_2)));
444}
445
446TEST_F(ScreenRecoveryUITest, ShowMenu_NotMenuOnly) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700447 RETURN_IF_NO_GRAPHICS;
448
Tao Bao26ea9592018-05-09 16:32:02 -0700449 ASSERT_TRUE(ui_->Init(kTestLocale));
Tao Bao6cd81682018-05-03 21:53:11 -0700450 ui_->SetKeyBuffer({
451 KeyCode::MAGIC,
452 });
453 ASSERT_EQ(static_cast<size_t>(kMagicAction),
454 ui_->ShowMenu(HEADERS, ITEMS, 3, false,
455 std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
456 std::placeholders::_1, std::placeholders::_2)));
457}
458
459TEST_F(ScreenRecoveryUITest, ShowMenu_TimedOut) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700460 RETURN_IF_NO_GRAPHICS;
461
Tao Bao26ea9592018-05-09 16:32:02 -0700462 ASSERT_TRUE(ui_->Init(kTestLocale));
Tao Bao6cd81682018-05-03 21:53:11 -0700463 ui_->SetKeyBuffer({
464 KeyCode::TIMEOUT,
465 });
Jerry Zhangb76af932018-05-22 12:08:35 -0700466 ASSERT_EQ(static_cast<size_t>(RecoveryUI::KeyError::TIMED_OUT),
467 ui_->ShowMenu(HEADERS, ITEMS, 3, true, nullptr));
Tao Bao6cd81682018-05-03 21:53:11 -0700468}
469
470TEST_F(ScreenRecoveryUITest, ShowMenu_TimedOut_TextWasEverVisible) {
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_->ShowText(true);
475 ui_->ShowText(false);
476 ASSERT_TRUE(ui_->WasTextEverVisible());
477
478 ui_->SetKeyBuffer({
479 KeyCode::TIMEOUT,
480 KeyCode::DOWN,
481 KeyCode::ENTER,
482 });
483 ASSERT_EQ(4u, ui_->ShowMenu(HEADERS, ITEMS, 3, true,
484 std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
485 std::placeholders::_1, std::placeholders::_2)));
486}
Tao Bao152e0eb2018-05-13 00:34:45 -0700487
Jerry Zhangb76af932018-05-22 12:08:35 -0700488TEST_F(ScreenRecoveryUITest, ShowMenuWithInterrupt) {
489 RETURN_IF_NO_GRAPHICS;
490
491 ASSERT_TRUE(ui_->Init(kTestLocale));
492 ui_->SetKeyBuffer({
493 KeyCode::UP,
494 KeyCode::DOWN,
495 KeyCode::UP,
496 KeyCode::DOWN,
497 KeyCode::ENTER,
498 });
499
500 ui_->InterruptKey();
501 ASSERT_EQ(static_cast<size_t>(RecoveryUI::KeyError::INTERRUPTED),
502 ui_->ShowMenu(HEADERS, ITEMS, 3, true,
503 std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
504 std::placeholders::_1, std::placeholders::_2)));
505
506 ui_->SetKeyBuffer({
507 KeyCode::UP,
508 KeyCode::UP,
509 KeyCode::NO_OP,
510 KeyCode::NO_OP,
511 KeyCode::UP,
512 KeyCode::ENTER,
513 });
514 ASSERT_EQ(static_cast<size_t>(RecoveryUI::KeyError::INTERRUPTED),
515 ui_->ShowMenu(HEADERS, ITEMS, 0, true,
516 std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
517 std::placeholders::_1, std::placeholders::_2)));
518}
519
Tao Bao152e0eb2018-05-13 00:34:45 -0700520TEST_F(ScreenRecoveryUITest, LoadAnimation) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700521 RETURN_IF_NO_GRAPHICS;
522
Tao Bao26ea9592018-05-09 16:32:02 -0700523 ASSERT_TRUE(ui_->Init(kTestLocale));
Tao Bao152e0eb2018-05-13 00:34:45 -0700524 // Make a few copies of loop00000.png from testdata.
525 std::string image_data;
526 ASSERT_TRUE(android::base::ReadFileToString(testdata_dir_ + "/loop00000.png", &image_data));
527
528 std::vector<std::string> tempfiles;
529 TemporaryDir resource_dir;
530 for (const auto& name : { "00002", "00100", "00050" }) {
531 tempfiles.push_back(android::base::StringPrintf("%s/loop%s.png", resource_dir.path, name));
532 ASSERT_TRUE(android::base::WriteStringToFile(image_data, tempfiles.back()));
533 }
534 for (const auto& name : { "00", "01" }) {
535 tempfiles.push_back(android::base::StringPrintf("%s/intro%s.png", resource_dir.path, name));
536 ASSERT_TRUE(android::base::WriteStringToFile(image_data, tempfiles.back()));
537 }
538 Paths::Get().set_resource_dir(resource_dir.path);
539
Tao Bao929e4812018-06-06 14:28:35 -0700540 ui_->LoadAnimation();
Tao Bao152e0eb2018-05-13 00:34:45 -0700541
Tao Baoda409fb2018-10-21 23:36:26 -0700542 ASSERT_EQ(2u, ui_->intro_frames_.size());
543 ASSERT_EQ(3u, ui_->loop_frames_.size());
Tao Bao152e0eb2018-05-13 00:34:45 -0700544
545 for (const auto& name : tempfiles) {
546 ASSERT_EQ(0, unlink(name.c_str()));
547 }
548}
549
550TEST_F(ScreenRecoveryUITest, LoadAnimation_MissingAnimation) {
Tao Bao51f16ec2018-06-04 11:40:20 -0700551 RETURN_IF_NO_GRAPHICS;
552
Tao Bao26ea9592018-05-09 16:32:02 -0700553 ASSERT_TRUE(ui_->Init(kTestLocale));
Tao Baob1c5b622018-07-12 11:49:05 -0700554 // We need a dir that doesn't contain any animation. However, using TemporaryDir will give
555 // leftovers since this is a death test where TemporaryDir::~TemporaryDir() won't be called.
556 Paths::Get().set_resource_dir("/proc/self");
Tao Bao42be0d42018-06-05 14:03:34 -0700557
558 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
Tao Bao929e4812018-06-06 14:28:35 -0700559 ASSERT_EXIT(ui_->LoadAnimation(), ::testing::KilledBySignal(SIGABRT), "");
Tao Bao152e0eb2018-05-13 00:34:45 -0700560}
Tao Bao51f16ec2018-06-04 11:40:20 -0700561
562#undef RETURN_IF_NO_GRAPHICS