blob: 03e23ca42c3a40fea0eb4d760f75ac6b450c29a4 [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>
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070018
Tao Bao6cd81682018-05-03 21:53:11 -070019#include <functional>
20#include <map>
21#include <memory>
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070022#include <string>
Tao Bao1fe1afe2018-05-01 15:56:05 -070023#include <vector>
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070024
Tao Bao6cd81682018-05-03 21:53:11 -070025#include <android-base/logging.h>
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070026#include <gtest/gtest.h>
27
Tao Bao6cd81682018-05-03 21:53:11 -070028#include "common/test_constants.h"
29#include "device.h"
30#include "otautil/paths.h"
31#include "private/resources.h"
Tao Bao1fe1afe2018-05-01 15:56:05 -070032#include "screen_ui.h"
33
34static const std::vector<std::string> HEADERS{ "header" };
35static const std::vector<std::string> ITEMS{ "item1", "item2", "item3", "item4", "1234567890" };
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070036
37TEST(ScreenUITest, StartPhoneMenuSmoke) {
Tao Bao1fe1afe2018-05-01 15:56:05 -070038 Menu menu(false, 10, 20, HEADERS, ITEMS, 0);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070039 ASSERT_FALSE(menu.scrollable());
Tao Bao1fe1afe2018-05-01 15:56:05 -070040 ASSERT_EQ(HEADERS[0], menu.text_headers()[0]);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070041 ASSERT_EQ(5u, menu.ItemsCount());
42
43 std::string message;
44 ASSERT_FALSE(menu.ItemsOverflow(&message));
45 for (size_t i = 0; i < menu.ItemsCount(); i++) {
46 ASSERT_EQ(ITEMS[i], menu.TextItem(i));
47 }
48
49 ASSERT_EQ(0, menu.selection());
50}
51
52TEST(ScreenUITest, StartWearMenuSmoke) {
Tao Bao1fe1afe2018-05-01 15:56:05 -070053 Menu menu(true, 10, 8, HEADERS, ITEMS, 1);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070054 ASSERT_TRUE(menu.scrollable());
Tao Bao1fe1afe2018-05-01 15:56:05 -070055 ASSERT_EQ(HEADERS[0], menu.text_headers()[0]);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070056 ASSERT_EQ(5u, menu.ItemsCount());
57
58 std::string message;
59 ASSERT_FALSE(menu.ItemsOverflow(&message));
60 for (size_t i = 0; i < menu.ItemsCount() - 1; i++) {
61 ASSERT_EQ(ITEMS[i], menu.TextItem(i));
62 }
63 // Test of the last item is truncated
64 ASSERT_EQ("12345678", menu.TextItem(4));
65 ASSERT_EQ(1, menu.selection());
66}
67
68TEST(ScreenUITest, StartPhoneMenuItemsOverflow) {
Tao Bao1fe1afe2018-05-01 15:56:05 -070069 Menu menu(false, 1, 20, HEADERS, ITEMS, 0);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070070 ASSERT_FALSE(menu.scrollable());
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070071 ASSERT_EQ(1u, menu.ItemsCount());
72
73 std::string message;
74 ASSERT_FALSE(menu.ItemsOverflow(&message));
75 for (size_t i = 0; i < menu.ItemsCount(); i++) {
76 ASSERT_EQ(ITEMS[i], menu.TextItem(i));
77 }
78
79 ASSERT_EQ(0u, menu.MenuStart());
80 ASSERT_EQ(1u, menu.MenuEnd());
81}
82
83TEST(ScreenUITest, StartWearMenuItemsOverflow) {
Tao Bao1fe1afe2018-05-01 15:56:05 -070084 Menu menu(true, 1, 20, HEADERS, ITEMS, 0);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070085 ASSERT_TRUE(menu.scrollable());
Tianjie Xu5fe5eb62018-03-20 16:07:39 -070086 ASSERT_EQ(5u, menu.ItemsCount());
87
88 std::string message;
89 ASSERT_TRUE(menu.ItemsOverflow(&message));
90 ASSERT_EQ("Current item: 1/5", message);
91
92 for (size_t i = 0; i < menu.ItemsCount(); i++) {
93 ASSERT_EQ(ITEMS[i], menu.TextItem(i));
94 }
95
96 ASSERT_EQ(0u, menu.MenuStart());
97 ASSERT_EQ(1u, menu.MenuEnd());
98}
99
100TEST(ScreenUITest, PhoneMenuSelectSmoke) {
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700101 int sel = 0;
Tao Bao1fe1afe2018-05-01 15:56:05 -0700102 Menu menu(false, 10, 20, HEADERS, ITEMS, sel);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700103 // Mimic down button 10 times (2 * items size)
104 for (int i = 0; i < 10; i++) {
105 sel = menu.Select(++sel);
106 ASSERT_EQ(sel, menu.selection());
107
108 // Wraps the selection for unscrollable menu when it reaches the boundary.
109 int expected = (i + 1) % 5;
110 ASSERT_EQ(expected, menu.selection());
111
112 ASSERT_EQ(0u, menu.MenuStart());
113 ASSERT_EQ(5u, menu.MenuEnd());
114 }
115
116 // Mimic up button 10 times
117 for (int i = 0; i < 10; i++) {
118 sel = menu.Select(--sel);
119 ASSERT_EQ(sel, menu.selection());
120
121 int expected = (9 - i) % 5;
122 ASSERT_EQ(expected, menu.selection());
123
124 ASSERT_EQ(0u, menu.MenuStart());
125 ASSERT_EQ(5u, menu.MenuEnd());
126 }
127}
128
129TEST(ScreenUITest, WearMenuSelectSmoke) {
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700130 int sel = 0;
Tao Bao1fe1afe2018-05-01 15:56:05 -0700131 Menu menu(true, 10, 20, HEADERS, ITEMS, sel);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700132 // Mimic pressing down button 10 times (2 * items size)
133 for (int i = 0; i < 10; i++) {
134 sel = menu.Select(++sel);
135 ASSERT_EQ(sel, menu.selection());
136
137 // Stops the selection at the boundary if the menu is scrollable.
138 int expected = std::min(i + 1, 4);
139 ASSERT_EQ(expected, menu.selection());
140
141 ASSERT_EQ(0u, menu.MenuStart());
142 ASSERT_EQ(5u, menu.MenuEnd());
143 }
144
145 // Mimic pressing up button 10 times
146 for (int i = 0; i < 10; i++) {
147 sel = menu.Select(--sel);
148 ASSERT_EQ(sel, menu.selection());
149
150 int expected = std::max(3 - i, 0);
151 ASSERT_EQ(expected, menu.selection());
152
153 ASSERT_EQ(0u, menu.MenuStart());
154 ASSERT_EQ(5u, menu.MenuEnd());
155 }
156}
157
158TEST(ScreenUITest, WearMenuSelectItemsOverflow) {
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700159 int sel = 1;
Tao Bao1fe1afe2018-05-01 15:56:05 -0700160 Menu menu(true, 3, 20, HEADERS, ITEMS, sel);
Tianjie Xu5fe5eb62018-03-20 16:07:39 -0700161 ASSERT_EQ(5u, menu.ItemsCount());
162
163 // Scroll the menu to the end, and check the start & end of menu.
164 for (int i = 0; i < 3; i++) {
165 sel = menu.Select(++sel);
166 ASSERT_EQ(i + 2, sel);
167 ASSERT_EQ(static_cast<size_t>(i), menu.MenuStart());
168 ASSERT_EQ(static_cast<size_t>(i + 3), menu.MenuEnd());
169 }
170
171 // Press down button one more time won't change the MenuStart() and MenuEnd().
172 sel = menu.Select(++sel);
173 ASSERT_EQ(4, sel);
174 ASSERT_EQ(2u, menu.MenuStart());
175 ASSERT_EQ(5u, menu.MenuEnd());
176
177 // Scroll the menu to the top.
178 // The expected menu sel, start & ends are:
179 // sel 3, start 2, end 5
180 // sel 2, start 2, end 5
181 // sel 1, start 1, end 4
182 // sel 0, start 0, end 3
183 for (int i = 0; i < 4; i++) {
184 sel = menu.Select(--sel);
185 ASSERT_EQ(3 - i, sel);
186 ASSERT_EQ(static_cast<size_t>(std::min(3 - i, 2)), menu.MenuStart());
187 ASSERT_EQ(static_cast<size_t>(std::min(6 - i, 5)), menu.MenuEnd());
188 }
189
190 // Press up button one more time won't change the MenuStart() and MenuEnd().
191 sel = menu.Select(--sel);
192 ASSERT_EQ(0, sel);
193 ASSERT_EQ(0u, menu.MenuStart());
194 ASSERT_EQ(3u, menu.MenuEnd());
195}
Tao Bao6cd81682018-05-03 21:53:11 -0700196
197static constexpr int kMagicAction = 101;
198
199enum class KeyCode : int {
200 TIMEOUT = -1,
201 NO_OP = 0,
202 UP = 1,
203 DOWN = 2,
204 ENTER = 3,
205 MAGIC = 1001,
206 LAST,
207};
208
209static const std::map<KeyCode, int> kKeyMapping{
210 // clang-format off
211 { KeyCode::NO_OP, Device::kNoAction },
212 { KeyCode::UP, Device::kHighlightUp },
213 { KeyCode::DOWN, Device::kHighlightDown },
214 { KeyCode::ENTER, Device::kInvokeItem },
215 { KeyCode::MAGIC, kMagicAction },
216 // clang-format on
217};
218
219class TestableScreenRecoveryUI : public ScreenRecoveryUI {
220 public:
221 int WaitKey() override;
222
223 void SetKeyBuffer(const std::vector<KeyCode>& buffer);
224
225 int KeyHandler(int key, bool visible) const;
226
227 bool GetRtlLocale() const {
228 return rtl_locale_;
229 }
230
231 private:
232 std::vector<KeyCode> key_buffer_;
233 size_t key_buffer_index_;
234};
235
236void TestableScreenRecoveryUI::SetKeyBuffer(const std::vector<KeyCode>& buffer) {
237 key_buffer_ = buffer;
238 key_buffer_index_ = 0;
239}
240
241int TestableScreenRecoveryUI::KeyHandler(int key, bool) const {
242 KeyCode key_code = static_cast<KeyCode>(key);
243 if (kKeyMapping.find(key_code) != kKeyMapping.end()) {
244 return kKeyMapping.at(key_code);
245 }
246 return Device::kNoAction;
247}
248
249int TestableScreenRecoveryUI::WaitKey() {
250 CHECK_LT(key_buffer_index_, key_buffer_.size());
251 return static_cast<int>(key_buffer_[key_buffer_index_++]);
252}
253
254class ScreenRecoveryUITest : public ::testing::Test {
255 protected:
256 const std::string kTestLocale = "en-US";
257 const std::string kTestRtlLocale = "ar";
Tao Bao347a6592018-05-08 15:58:29 -0700258 const std::string kTestRtlLocaleWithSuffix = "ar-EG";
Tao Bao6cd81682018-05-03 21:53:11 -0700259
260 void SetUp() override {
261 ui_ = std::make_unique<TestableScreenRecoveryUI>();
262
263 std::string testdata_dir = from_testdata_base("");
264 Paths::Get().set_resource_dir(testdata_dir);
265 res_set_resource_dir(testdata_dir);
266
267 ASSERT_TRUE(ui_->Init(kTestLocale));
268 }
269
270 std::unique_ptr<TestableScreenRecoveryUI> ui_;
271};
272
273TEST_F(ScreenRecoveryUITest, Init) {
274 ASSERT_EQ(kTestLocale, ui_->GetLocale());
275 ASSERT_FALSE(ui_->GetRtlLocale());
276 ASSERT_FALSE(ui_->IsTextVisible());
277 ASSERT_FALSE(ui_->WasTextEverVisible());
278}
279
280TEST_F(ScreenRecoveryUITest, ShowText) {
281 ASSERT_FALSE(ui_->IsTextVisible());
282 ui_->ShowText(true);
283 ASSERT_TRUE(ui_->IsTextVisible());
284 ASSERT_TRUE(ui_->WasTextEverVisible());
285
286 ui_->ShowText(false);
287 ASSERT_FALSE(ui_->IsTextVisible());
288 ASSERT_TRUE(ui_->WasTextEverVisible());
289}
290
291TEST_F(ScreenRecoveryUITest, RtlLocale) {
292 ASSERT_TRUE(ui_->Init(kTestRtlLocale));
293 ASSERT_TRUE(ui_->GetRtlLocale());
294
295 ASSERT_TRUE(ui_->Init(kTestRtlLocaleWithSuffix));
296 ASSERT_TRUE(ui_->GetRtlLocale());
297}
298
299TEST_F(ScreenRecoveryUITest, ShowMenu) {
300 ui_->SetKeyBuffer({
301 KeyCode::UP,
302 KeyCode::DOWN,
303 KeyCode::UP,
304 KeyCode::DOWN,
305 KeyCode::ENTER,
306 });
307 ASSERT_EQ(3u, ui_->ShowMenu(HEADERS, ITEMS, 3, true,
308 std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
309 std::placeholders::_1, std::placeholders::_2)));
310
311 ui_->SetKeyBuffer({
312 KeyCode::UP,
313 KeyCode::UP,
314 KeyCode::NO_OP,
315 KeyCode::NO_OP,
316 KeyCode::UP,
317 KeyCode::ENTER,
318 });
319 ASSERT_EQ(2u, ui_->ShowMenu(HEADERS, ITEMS, 0, true,
320 std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
321 std::placeholders::_1, std::placeholders::_2)));
322}
323
324TEST_F(ScreenRecoveryUITest, ShowMenu_NotMenuOnly) {
325 ui_->SetKeyBuffer({
326 KeyCode::MAGIC,
327 });
328 ASSERT_EQ(static_cast<size_t>(kMagicAction),
329 ui_->ShowMenu(HEADERS, ITEMS, 3, false,
330 std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
331 std::placeholders::_1, std::placeholders::_2)));
332}
333
334TEST_F(ScreenRecoveryUITest, ShowMenu_TimedOut) {
335 ui_->SetKeyBuffer({
336 KeyCode::TIMEOUT,
337 });
338 ASSERT_EQ(static_cast<size_t>(-1), ui_->ShowMenu(HEADERS, ITEMS, 3, true, nullptr));
339}
340
341TEST_F(ScreenRecoveryUITest, ShowMenu_TimedOut_TextWasEverVisible) {
342 ui_->ShowText(true);
343 ui_->ShowText(false);
344 ASSERT_TRUE(ui_->WasTextEverVisible());
345
346 ui_->SetKeyBuffer({
347 KeyCode::TIMEOUT,
348 KeyCode::DOWN,
349 KeyCode::ENTER,
350 });
351 ASSERT_EQ(4u, ui_->ShowMenu(HEADERS, ITEMS, 3, true,
352 std::bind(&TestableScreenRecoveryUI::KeyHandler, ui_.get(),
353 std::placeholders::_1, std::placeholders::_2)));
354}