1 /*
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 
17 #include <stddef.h>
18 #include <stdio.h>
19 
20 #include <functional>
21 #include <map>
22 #include <memory>
23 #include <string>
24 #include <vector>
25 
26 #include <android-base/file.h>
27 #include <android-base/logging.h>
28 #include <android-base/stringprintf.h>
29 #include <gtest/gtest.h>
30 #include <gtest/gtest_prod.h>
31 
32 #include "common/test_constants.h"
33 #include "minui/minui.h"
34 #include "otautil/paths.h"
35 #include "private/resources.h"
36 #include "recovery_ui/device.h"
37 #include "recovery_ui/screen_ui.h"
38 
39 static const std::vector<std::string> HEADERS{ "header" };
40 static const std::vector<std::string> ITEMS{ "item1", "item2", "item3", "item4", "1234567890" };
41 
42 // TODO(xunchang) check if some draw functions are called when drawing menus.
43 class MockDrawFunctions : public DrawInterface {
SetColor(UIElement) const44   void SetColor(UIElement /* element */) const override {}
DrawHighlightBar(int,int,int,int) const45   void DrawHighlightBar(int /* x */, int /* y */, int /* width */,
46                         int /* height */) const override {}
DrawHorizontalRule(int) const47   int DrawHorizontalRule(int /* y */) const override {
48     return 0;
49   }
DrawTextLine(int,int,const std::string &,bool) const50   int DrawTextLine(int /* x */, int /* y */, const std::string& /* line */,
51                    bool /* bold */) const override {
52     return 0;
53   }
DrawSurface(const GRSurface *,int,int,int,int,int,int) const54   void DrawSurface(const GRSurface* /* surface */, int /* sx */, int /* sy */, int /* w */,
55                    int /* h */, int /* dx */, int /* dy */) const override {}
DrawFill(int,int,int,int) const56   void DrawFill(int /* x */, int /* y */, int /* w */, int /* h */) const override {}
DrawTextIcon(int,int,const GRSurface *) const57   void DrawTextIcon(int /* x */, int /* y */, const GRSurface* /* surface */) const override {}
DrawTextLines(int,int,const std::vector<std::string> &) const58   int DrawTextLines(int /* x */, int /* y */,
59                     const std::vector<std::string>& /* lines */) const override {
60     return 0;
61   }
DrawWrappedTextLines(int,int,const std::vector<std::string> &) const62   int DrawWrappedTextLines(int /* x */, int /* y */,
63                            const std::vector<std::string>& /* lines */) const override {
64     return 0;
65   }
66 };
67 
68 class ScreenUITest : public testing::Test {
69  protected:
70   MockDrawFunctions draw_funcs_;
71 };
72 
TEST_F(ScreenUITest,StartPhoneMenuSmoke)73 TEST_F(ScreenUITest, StartPhoneMenuSmoke) {
74   TextMenu menu(false, 10, 20, HEADERS, ITEMS, 0, 20, draw_funcs_);
75   ASSERT_FALSE(menu.scrollable());
76   ASSERT_EQ(HEADERS[0], menu.text_headers()[0]);
77   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 
TEST_F(ScreenUITest,StartWearMenuSmoke)88 TEST_F(ScreenUITest, StartWearMenuSmoke) {
89   TextMenu menu(true, 10, 8, HEADERS, ITEMS, 1, 20, draw_funcs_);
90   ASSERT_TRUE(menu.scrollable());
91   ASSERT_EQ(HEADERS[0], menu.text_headers()[0]);
92   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 
TEST_F(ScreenUITest,StartPhoneMenuItemsOverflow)104 TEST_F(ScreenUITest, StartPhoneMenuItemsOverflow) {
105   TextMenu menu(false, 1, 20, HEADERS, ITEMS, 0, 20, draw_funcs_);
106   ASSERT_FALSE(menu.scrollable());
107   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 
TEST_F(ScreenUITest,StartWearMenuItemsOverflow)119 TEST_F(ScreenUITest, StartWearMenuItemsOverflow) {
120   TextMenu menu(true, 1, 20, HEADERS, ITEMS, 0, 20, draw_funcs_);
121   ASSERT_TRUE(menu.scrollable());
122   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 
TEST_F(ScreenUITest,PhoneMenuSelectSmoke)136 TEST_F(ScreenUITest, PhoneMenuSelectSmoke) {
137   int sel = 0;
138   TextMenu menu(false, 10, 20, HEADERS, ITEMS, sel, 20, draw_funcs_);
139   // 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 
TEST_F(ScreenUITest,WearMenuSelectSmoke)165 TEST_F(ScreenUITest, WearMenuSelectSmoke) {
166   int sel = 0;
167   TextMenu menu(true, 10, 20, HEADERS, ITEMS, sel, 20, draw_funcs_);
168   // 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 
TEST_F(ScreenUITest,WearMenuSelectItemsOverflow)194 TEST_F(ScreenUITest, WearMenuSelectItemsOverflow) {
195   int sel = 1;
196   TextMenu menu(true, 3, 20, HEADERS, ITEMS, sel, 20, draw_funcs_);
197   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 }
232 
TEST_F(ScreenUITest,GraphicMenuSelection)233 TEST_F(ScreenUITest, GraphicMenuSelection) {
234   auto image = GRSurface::Create(50, 50, 50, 1);
235   auto header = image->Clone();
236   std::vector<const GRSurface*> items = {
237     image.get(),
238     image.get(),
239     image.get(),
240   };
241   GraphicMenu menu(header.get(), items, 0, draw_funcs_);
242 
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 
TEST_F(ScreenUITest,GraphicMenuValidate)260 TEST_F(ScreenUITest, GraphicMenuValidate) {
261   auto image = GRSurface::Create(50, 50, 50, 1);
262   auto header = image->Clone();
263   std::vector<const GRSurface*> items = {
264     image.get(),
265     image.get(),
266     image.get(),
267   };
268 
269   ASSERT_TRUE(GraphicMenu::Validate(200, 200, header.get(), items));
270 
271   // Menu exceeds the horizontal boundary.
272   auto wide_surface = GRSurface::Create(300, 50, 300, 1);
273   ASSERT_FALSE(GraphicMenu::Validate(299, 200, wide_surface.get(), items));
274 
275   // Menu exceeds the vertical boundary.
276   items.emplace_back(image.get());
277   ASSERT_FALSE(GraphicMenu::Validate(200, 249, header.get(), items));
278 }
279 
280 static constexpr int kMagicAction = 101;
281 
282 enum 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 
292 static 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 
302 class 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 
310  private:
311   FRIEND_TEST(DISABLED_ScreenRecoveryUITest, Init);
312   FRIEND_TEST(DISABLED_ScreenRecoveryUITest, RtlLocale);
313   FRIEND_TEST(DISABLED_ScreenRecoveryUITest, RtlLocaleWithSuffix);
314   FRIEND_TEST(DISABLED_ScreenRecoveryUITest, LoadAnimation);
315   FRIEND_TEST(DISABLED_ScreenRecoveryUITest, LoadAnimation_MissingAnimation);
316 
317   std::vector<KeyCode> key_buffer_;
318   size_t key_buffer_index_;
319 };
320 
SetKeyBuffer(const std::vector<KeyCode> & buffer)321 void TestableScreenRecoveryUI::SetKeyBuffer(const std::vector<KeyCode>& buffer) {
322   key_buffer_ = buffer;
323   key_buffer_index_ = 0;
324 }
325 
KeyHandler(int key,bool) const326 int 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 
WaitKey()334 int TestableScreenRecoveryUI::WaitKey() {
335   if (IsKeyInterrupted()) {
336     return static_cast<int>(RecoveryUI::KeyError::INTERRUPTED);
337   }
338 
339   CHECK_LT(key_buffer_index_, key_buffer_.size());
340   return static_cast<int>(key_buffer_[key_buffer_index_++]);
341 }
342 
343 class DISABLED_ScreenRecoveryUITest : public ::testing::Test {
344  protected:
345   const std::string kTestLocale = "en-US";
346   const std::string kTestRtlLocale = "ar";
347   const std::string kTestRtlLocaleWithSuffix = "ar-EG";
348 
SetUp()349   void SetUp() override {
350     has_graphics_ = gr_init() == 0;
351     gr_exit();
352 
353     if (has_graphics_) {
354       ui_ = std::make_unique<TestableScreenRecoveryUI>();
355     }
356 
357     testdata_dir_ = from_testdata_base("");
358     Paths::Get().set_resource_dir(testdata_dir_);
359     res_set_resource_dir(testdata_dir_);
360   }
361 
362   bool has_graphics_;
363   std::unique_ptr<TestableScreenRecoveryUI> ui_;
364   std::string testdata_dir_;
365 };
366 
367 #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 
TEST_F(DISABLED_ScreenRecoveryUITest,Init)375 TEST_F(DISABLED_ScreenRecoveryUITest, Init) {
376   RETURN_IF_NO_GRAPHICS;
377 
378   ASSERT_TRUE(ui_->Init(kTestLocale));
379   ASSERT_EQ(kTestLocale, ui_->GetLocale());
380   ASSERT_FALSE(ui_->rtl_locale_);
381   ASSERT_FALSE(ui_->IsTextVisible());
382   ASSERT_FALSE(ui_->WasTextEverVisible());
383 }
384 
TEST_F(DISABLED_ScreenRecoveryUITest,dtor_NotCallingInit)385 TEST_F(DISABLED_ScreenRecoveryUITest, dtor_NotCallingInit) {
386   ui_.reset();
387   ASSERT_FALSE(ui_);
388 }
389 
TEST_F(DISABLED_ScreenRecoveryUITest,ShowText)390 TEST_F(DISABLED_ScreenRecoveryUITest, ShowText) {
391   RETURN_IF_NO_GRAPHICS;
392 
393   ASSERT_TRUE(ui_->Init(kTestLocale));
394   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 
TEST_F(DISABLED_ScreenRecoveryUITest,RtlLocale)404 TEST_F(DISABLED_ScreenRecoveryUITest, RtlLocale) {
405   RETURN_IF_NO_GRAPHICS;
406 
407   ASSERT_TRUE(ui_->Init(kTestRtlLocale));
408   ASSERT_TRUE(ui_->rtl_locale_);
409 }
410 
TEST_F(DISABLED_ScreenRecoveryUITest,RtlLocaleWithSuffix)411 TEST_F(DISABLED_ScreenRecoveryUITest, RtlLocaleWithSuffix) {
412   RETURN_IF_NO_GRAPHICS;
413 
414   ASSERT_TRUE(ui_->Init(kTestRtlLocaleWithSuffix));
415   ASSERT_TRUE(ui_->rtl_locale_);
416 }
417 
TEST_F(DISABLED_ScreenRecoveryUITest,ShowMenu)418 TEST_F(DISABLED_ScreenRecoveryUITest, ShowMenu) {
419   RETURN_IF_NO_GRAPHICS;
420 
421   ASSERT_TRUE(ui_->Init(kTestLocale));
422   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 
TEST_F(DISABLED_ScreenRecoveryUITest,ShowMenu_NotMenuOnly)446 TEST_F(DISABLED_ScreenRecoveryUITest, ShowMenu_NotMenuOnly) {
447   RETURN_IF_NO_GRAPHICS;
448 
449   ASSERT_TRUE(ui_->Init(kTestLocale));
450   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 
TEST_F(DISABLED_ScreenRecoveryUITest,ShowMenu_TimedOut)459 TEST_F(DISABLED_ScreenRecoveryUITest, ShowMenu_TimedOut) {
460   RETURN_IF_NO_GRAPHICS;
461 
462   ASSERT_TRUE(ui_->Init(kTestLocale));
463   ui_->SetKeyBuffer({
464       KeyCode::TIMEOUT,
465   });
466   ASSERT_EQ(static_cast<size_t>(RecoveryUI::KeyError::TIMED_OUT),
467             ui_->ShowMenu(HEADERS, ITEMS, 3, true, nullptr));
468 }
469 
TEST_F(DISABLED_ScreenRecoveryUITest,ShowMenu_TimedOut_TextWasEverVisible)470 TEST_F(DISABLED_ScreenRecoveryUITest, ShowMenu_TimedOut_TextWasEverVisible) {
471   RETURN_IF_NO_GRAPHICS;
472 
473   ASSERT_TRUE(ui_->Init(kTestLocale));
474   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 }
487 
TEST_F(DISABLED_ScreenRecoveryUITest,ShowMenuWithInterrupt)488 TEST_F(DISABLED_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 
TEST_F(DISABLED_ScreenRecoveryUITest,LoadAnimation)520 TEST_F(DISABLED_ScreenRecoveryUITest, LoadAnimation) {
521   RETURN_IF_NO_GRAPHICS;
522 
523   ASSERT_TRUE(ui_->Init(kTestLocale));
524   // 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 
540   ui_->LoadAnimation();
541 
542   ASSERT_EQ(2u, ui_->intro_frames_.size());
543   ASSERT_EQ(3u, ui_->loop_frames_.size());
544 
545   for (const auto& name : tempfiles) {
546     ASSERT_EQ(0, unlink(name.c_str()));
547   }
548 }
549 
TEST_F(DISABLED_ScreenRecoveryUITest,LoadAnimation_MissingAnimation)550 TEST_F(DISABLED_ScreenRecoveryUITest, LoadAnimation_MissingAnimation) {
551   RETURN_IF_NO_GRAPHICS;
552 
553   ASSERT_TRUE(ui_->Init(kTestLocale));
554   // 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");
557 
558   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
559   ASSERT_EXIT(ui_->LoadAnimation(), ::testing::KilledBySignal(SIGABRT), "");
560 }
561 
562 #undef RETURN_IF_NO_GRAPHICS
563