1 /*
2  * Copyright (C) 2011 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 #ifndef RECOVERY_SCREEN_UI_H
18 #define RECOVERY_SCREEN_UI_H
19 
20 #include <stdio.h>
21 
22 #include <atomic>
23 #include <functional>
24 #include <memory>
25 #include <string>
26 #include <thread>
27 #include <vector>
28 
29 #include "ui.h"
30 
31 // From minui/minui.h.
32 class GRSurface;
33 
34 enum class UIElement {
35   HEADER,
36   MENU,
37   MENU_SEL_BG,
38   MENU_SEL_BG_ACTIVE,
39   MENU_SEL_FG,
40   LOG,
41   TEXT_FILL,
42   INFO
43 };
44 
45 // Interface to draw the UI elements on the screen.
46 class DrawInterface {
47  public:
48   virtual ~DrawInterface() = default;
49 
50   // Sets the color to the predefined value for |element|.
51   virtual void SetColor(UIElement element) const = 0;
52 
53   // Draws a highlight bar at (x, y) - (x + width, y + height).
54   virtual void DrawHighlightBar(int x, int y, int width, int height) const = 0;
55 
56   // Draws a horizontal rule at Y. Returns the offset it should be moving along Y-axis.
57   virtual int DrawHorizontalRule(int y) const = 0;
58 
59   // Draws a line of text. Returns the offset it should be moving along Y-axis.
60   virtual int DrawTextLine(int x, int y, const std::string& line, bool bold) const = 0;
61 
62   // Draws surface portion (sx, sy, w, h) at screen location (dx, dy).
63   virtual void DrawSurface(const GRSurface* surface, int sx, int sy, int w, int h, int dx,
64                            int dy) const = 0;
65 
66   // Draws rectangle at (x, y) - (x + w, y + h).
67   virtual void DrawFill(int x, int y, int w, int h) const = 0;
68 
69   // Draws given surface (surface->pixel_bytes = 1) as text at (x, y).
70   virtual void DrawTextIcon(int x, int y, const GRSurface* surface) const = 0;
71 
72   // Draws multiple text lines. Returns the offset it should be moving along Y-axis.
73   virtual int DrawTextLines(int x, int y, const std::vector<std::string>& lines) const = 0;
74 
75   // Similar to DrawTextLines() to draw multiple text lines, but additionally wraps long lines. It
76   // keeps symmetrical margins of 'x' at each end of a line. Returns the offset it should be moving
77   // along Y-axis.
78   virtual int DrawWrappedTextLines(int x, int y, const std::vector<std::string>& lines) const = 0;
79 };
80 
81 // Interface for classes that maintain the menu selection and display.
82 class Menu {
83  public:
84   virtual ~Menu() = default;
85   // Returns the current menu selection.
86   size_t selection() const;
87   // Sets the current selection to |sel|. Handle the overflow cases depending on if the menu is
88   // scrollable.
89   virtual int Select(int sel) = 0;
90   // Displays the menu headers on the screen at offset x, y
91   virtual int DrawHeader(int x, int y) const = 0;
92   // Iterates over the menu items and displays each of them at offset x, y.
93   virtual int DrawItems(int x, int y, int screen_width, bool long_press) const = 0;
94 
95  protected:
96   Menu(size_t initial_selection, const DrawInterface& draw_func);
97   // Current menu selection.
98   size_t selection_;
99   // Reference to the class that implements all the draw functions.
100   const DrawInterface& draw_funcs_;
101 };
102 
103 // This class uses strings as the menu header and items.
104 class TextMenu : public Menu {
105  public:
106   // Constructs a Menu instance with the given |headers|, |items| and properties. Sets the initial
107   // selection to |initial_selection|.
108   TextMenu(bool scrollable, size_t max_items, size_t max_length,
109            const std::vector<std::string>& headers, const std::vector<std::string>& items,
110            size_t initial_selection, int char_height, const DrawInterface& draw_funcs);
111 
112   int Select(int sel) override;
113   int DrawHeader(int x, int y) const override;
114   int DrawItems(int x, int y, int screen_width, bool long_press) const override;
115 
scrollable()116   bool scrollable() const {
117     return scrollable_;
118   }
119 
120   // Returns count of menu items.
121   size_t ItemsCount() const;
122 
123   // Returns the index of the first menu item.
124   size_t MenuStart() const;
125 
126   // Returns the index of the last menu item + 1.
127   size_t MenuEnd() const;
128 
129   // Menu example:
130   // info:                           Android Recovery
131   //                                 ....
132   // help messages:                  Swipe up/down to move
133   //                                 Swipe left/right to select
134   // empty line (horizontal rule):
135   // menu headers:                   Select file to view
136   // menu items:                     /cache/recovery/last_log
137   //                                 /cache/recovery/last_log.1
138   //                                 /cache/recovery/last_log.2
139   //                                 ...
140   const std::vector<std::string>& text_headers() const;
141   std::string TextItem(size_t index) const;
142 
143   // Checks if the menu items fit vertically on the screen. Returns true and set the
144   // |cur_selection_str| if the items exceed the screen limit.
145   bool ItemsOverflow(std::string* cur_selection_str) const;
146 
147  private:
148   // The menu is scrollable to display more items. Used on wear devices who have smaller screens.
149   const bool scrollable_;
150   // The max number of menu items to fit vertically on a screen.
151   const size_t max_display_items_;
152   // The length of each item to fit horizontally on a screen.
153   const size_t max_item_length_;
154   // The menu headers.
155   std::vector<std::string> text_headers_;
156   // The actual menu items trimmed to fit the given properties.
157   std::vector<std::string> text_items_;
158   // The first item to display on the screen.
159   size_t menu_start_;
160 
161   // Height in pixels of each character.
162   int char_height_;
163 };
164 
165 // This class uses GRSurface's as the menu header and items.
166 class GraphicMenu : public Menu {
167  public:
168   // Constructs a Menu instance with the given |headers|, |items| and properties. Sets the initial
169   // selection to |initial_selection|. |headers| and |items| will be made local copies.
170   GraphicMenu(const GRSurface* graphic_headers, const std::vector<const GRSurface*>& graphic_items,
171               size_t initial_selection, const DrawInterface& draw_funcs);
172 
173   int Select(int sel) override;
174   int DrawHeader(int x, int y) const override;
175   int DrawItems(int x, int y, int screen_width, bool long_press) const override;
176 
177   // Checks if all the header and items are valid GRSurface's; and that they can fit in the area
178   // defined by |max_width| and |max_height|.
179   static bool Validate(size_t max_width, size_t max_height, const GRSurface* graphic_headers,
180                        const std::vector<const GRSurface*>& graphic_items);
181 
182   // Returns true if |surface| fits on the screen with a vertical offset |y|.
183   static bool ValidateGraphicSurface(size_t max_width, size_t max_height, int y,
184                                      const GRSurface* surface);
185 
186  private:
187   // Menu headers and items in graphic icons. These are the copies owned by the class instance.
188   std::unique_ptr<GRSurface> graphic_headers_;
189   std::vector<std::unique_ptr<GRSurface>> graphic_items_;
190 };
191 
192 // Implementation of RecoveryUI appropriate for devices with a screen
193 // (shows an icon + a progress bar, text logging, menu, etc.)
194 class ScreenRecoveryUI : public RecoveryUI, public DrawInterface {
195  public:
196   ScreenRecoveryUI();
197   explicit ScreenRecoveryUI(bool scrollable_menu);
198   ~ScreenRecoveryUI() override;
199 
200   bool Init(const std::string& locale) override;
201   std::string GetLocale() const override;
202 
203   // overall recovery state ("background image")
204   void SetBackground(Icon icon) override;
205   void SetSystemUpdateText(bool security_update) override;
206 
207   // progress indicator
208   void SetProgressType(ProgressType type) override;
209   void ShowProgress(float portion, float seconds) override;
210   void SetProgress(float fraction) override;
211 
212   void SetStage(int current, int max) override;
213 
214   // text log
215   void ShowText(bool visible) override;
216   bool IsTextVisible() override;
217   bool WasTextEverVisible() override;
218 
219   // printing messages
220   void Print(const char* fmt, ...) override __printflike(2, 3);
221   void PrintOnScreenOnly(const char* fmt, ...) override __printflike(2, 3);
222   void ShowFile(const std::string& filename) override;
223 
224   // menu display
225   size_t ShowMenu(const std::vector<std::string>& headers, const std::vector<std::string>& items,
226                   size_t initial_selection, bool menu_only,
227                   const std::function<int(int, bool)>& key_handler) override;
228   void SetTitle(const std::vector<std::string>& lines) override;
229 
230   void KeyLongPress(int) override;
231 
232   void Redraw();
233 
234   // Checks the background text image, for debugging purpose. It iterates the locales embedded in
235   // the on-device resource files and shows the localized text, for manual inspection.
236   void CheckBackgroundTextImages();
237 
238   // Displays the localized wipe data menu.
239   size_t ShowPromptWipeDataMenu(const std::vector<std::string>& backup_headers,
240                                 const std::vector<std::string>& backup_items,
241                                 const std::function<int(int, bool)>& key_handler) override;
242 
243   // Displays the localized wipe data confirmation menu.
244   size_t ShowPromptWipeDataConfirmationMenu(
245       const std::vector<std::string>& backup_headers, const std::vector<std::string>& backup_items,
246       const std::function<int(int, bool)>& key_handler) override;
247 
248  protected:
249   static constexpr int kMenuIndent = 4;
250 
251   // The margin that we don't want to use for showing texts (e.g. round screen, or screen with
252   // rounded corners).
253   const int margin_width_;
254   const int margin_height_;
255 
256   // Number of frames per sec (default: 30) for both parts of the animation.
257   const int animation_fps_;
258 
259   // The scale factor from dp to pixels. 1.0 for mdpi, 4.0 for xxxhdpi.
260   const float density_;
261 
262   virtual bool InitTextParams();
263 
264   virtual bool LoadWipeDataMenuText();
265 
266   // Creates a GraphicMenu with |graphic_header| and |graphic_items|. If the GraphicMenu isn't
267   // valid or it doesn't fit on the screen; falls back to create a TextMenu instead. If succeeds,
268   // returns a unique pointer to the created menu; otherwise returns nullptr.
269   virtual std::unique_ptr<Menu> CreateMenu(const GRSurface* graphic_header,
270                                            const std::vector<const GRSurface*>& graphic_items,
271                                            const std::vector<std::string>& text_headers,
272                                            const std::vector<std::string>& text_items,
273                                            size_t initial_selection) const;
274 
275   // Creates a TextMenu with |text_headers| and |text_items|; and sets the menu selection to
276   // |initial_selection|.
277   virtual std::unique_ptr<Menu> CreateMenu(const std::vector<std::string>& text_headers,
278                                            const std::vector<std::string>& text_items,
279                                            size_t initial_selection) const;
280 
281   // Takes the ownership of |menu| and displays it.
282   virtual size_t ShowMenu(std::unique_ptr<Menu>&& menu, bool menu_only,
283                           const std::function<int(int, bool)>& key_handler);
284 
285   // Sets the menu highlight to the given index, wrapping if necessary. Returns the actual item
286   // selected.
287   virtual int SelectMenu(int sel);
288 
289   // Returns the help message displayed on top of the menu.
290   virtual std::vector<std::string> GetMenuHelpMessage() const;
291 
292   virtual void draw_background_locked();
293   virtual void draw_foreground_locked();
294   virtual void draw_screen_locked();
295   virtual void draw_menu_and_text_buffer_locked(const std::vector<std::string>& help_message);
296   virtual void update_screen_locked();
297   virtual void update_progress_locked();
298 
299   const GRSurface* GetCurrentFrame() const;
300   const GRSurface* GetCurrentText() const;
301 
302   void ProgressThreadLoop();
303 
304   virtual void ShowFile(FILE*);
305   virtual void PrintV(const char*, bool, va_list);
306   void PutChar(char);
307   void ClearText();
308 
309   void LoadAnimation();
310   std::unique_ptr<GRSurface> LoadBitmap(const std::string& filename);
311   std::unique_ptr<GRSurface> LoadLocalizedBitmap(const std::string& filename);
312 
313   int PixelsFromDp(int dp) const;
314   virtual int GetAnimationBaseline() const;
315   virtual int GetProgressBaseline() const;
316   virtual int GetTextBaseline() const;
317 
318   // Returns pixel width of draw buffer.
319   virtual int ScreenWidth() const;
320   // Returns pixel height of draw buffer.
321   virtual int ScreenHeight() const;
322 
323   // Implementation of the draw functions in DrawInterface.
324   void SetColor(UIElement e) const override;
325   void DrawHighlightBar(int x, int y, int width, int height) const override;
326   int DrawHorizontalRule(int y) const override;
327   void DrawSurface(const GRSurface* surface, int sx, int sy, int w, int h, int dx,
328                    int dy) const override;
329   void DrawFill(int x, int y, int w, int h) const override;
330   void DrawTextIcon(int x, int y, const GRSurface* surface) const override;
331   int DrawTextLine(int x, int y, const std::string& line, bool bold) const override;
332   int DrawTextLines(int x, int y, const std::vector<std::string>& lines) const override;
333   int DrawWrappedTextLines(int x, int y, const std::vector<std::string>& lines) const override;
334 
335   // The layout to use.
336   int layout_;
337 
338   // The images that contain localized texts.
339   std::unique_ptr<GRSurface> erasing_text_;
340   std::unique_ptr<GRSurface> error_text_;
341   std::unique_ptr<GRSurface> installing_text_;
342   std::unique_ptr<GRSurface> no_command_text_;
343 
344   // Localized text images for the wipe data menu.
345   std::unique_ptr<GRSurface> cancel_wipe_data_text_;
346   std::unique_ptr<GRSurface> factory_data_reset_text_;
347   std::unique_ptr<GRSurface> try_again_text_;
348   std::unique_ptr<GRSurface> wipe_data_confirmation_text_;
349   std::unique_ptr<GRSurface> wipe_data_menu_header_text_;
350 
351   std::unique_ptr<GRSurface> fastbootd_logo_;
352 
353   // current_icon_ points to one of the frames in intro_frames_ or loop_frames_, indexed by
354   // current_frame_, or error_icon_.
355   Icon current_icon_;
356   std::unique_ptr<GRSurface> error_icon_;
357   std::vector<std::unique_ptr<GRSurface>> intro_frames_;
358   std::vector<std::unique_ptr<GRSurface>> loop_frames_;
359   size_t current_frame_;
360   bool intro_done_;
361 
362   // progress_bar and stage_marker images.
363   std::unique_ptr<GRSurface> progress_bar_empty_;
364   std::unique_ptr<GRSurface> progress_bar_fill_;
365   std::unique_ptr<GRSurface> stage_marker_empty_;
366   std::unique_ptr<GRSurface> stage_marker_fill_;
367 
368   ProgressType progressBarType;
369 
370   float progressScopeStart, progressScopeSize, progress;
371   double progressScopeTime, progressScopeDuration;
372 
373   // true when both graphics pages are the same (except for the progress bar).
374   bool pagesIdentical;
375 
376   size_t text_cols_, text_rows_;
377 
378   // Log text overlay, displayed when a magic key is pressed.
379   char** text_;
380   size_t text_col_, text_row_;
381 
382   bool show_text;
383   bool show_text_ever;  // has show_text ever been true?
384 
385   std::vector<std::string> title_lines_;
386 
387   bool scrollable_menu_;
388   std::unique_ptr<Menu> menu_;
389 
390   // An alternate text screen, swapped with 'text_' when we're viewing a log file.
391   char** file_viewer_text_;
392 
393   std::thread progress_thread_;
394   std::atomic<bool> progress_thread_stopped_{ false };
395 
396   int stage, max_stage;
397 
398   int char_width_;
399   int char_height_;
400 
401   // The locale that's used to show the rendered texts.
402   std::string locale_;
403   bool rtl_locale_;
404 
405   std::mutex updateMutex;
406 
407  private:
408   void SetLocale(const std::string&);
409 
410   // Display the background texts for "erasing", "error", "no_command" and "installing" for the
411   // selected locale.
412   void SelectAndShowBackgroundText(const std::vector<std::string>& locales_entries, size_t sel);
413 };
414 
415 #endif  // RECOVERY_UI_H
416