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_UI_H
18 #define RECOVERY_UI_H
19 
20 #include <linux/input.h>  // KEY_MAX
21 
22 #include <atomic>
23 #include <condition_variable>
24 #include <functional>
25 #include <mutex>
26 #include <string>
27 #include <thread>
28 #include <vector>
29 
30 static constexpr const char* DEFAULT_LOCALE = "en-US";
31 
32 // Abstract class for controlling the user interface during recovery.
33 class RecoveryUI {
34  public:
35   enum Icon {
36     NONE,
37     INSTALLING_UPDATE,
38     ERASING,
39     NO_COMMAND,
40     ERROR,
41   };
42 
43   enum ProgressType {
44     EMPTY,
45     INDETERMINATE,
46     DETERMINATE,
47   };
48 
49   enum KeyAction {
50     ENQUEUE,
51     TOGGLE,
52     REBOOT,
53     IGNORE,
54   };
55 
56   enum class KeyError : int {
57     TIMED_OUT = -1,
58     INTERRUPTED = -2,
59   };
60 
61   RecoveryUI();
62 
63   virtual ~RecoveryUI();
64 
65   // Initializes the object; called before anything else. UI texts will be initialized according
66   // to the given locale. Returns true on success.
67   virtual bool Init(const std::string& locale);
68 
69   virtual std::string GetLocale() const = 0;
70 
71   // Shows a stage indicator. Called immediately after Init().
72   virtual void SetStage(int current, int max) = 0;
73 
74   // Sets the overall recovery state ("background image").
75   virtual void SetBackground(Icon icon) = 0;
76   virtual void SetSystemUpdateText(bool security_update) = 0;
77 
78   // --- progress indicator ---
79   virtual void SetProgressType(ProgressType determinate) = 0;
80 
81   // Shows a progress bar and define the scope of the next operation:
82   //   portion - fraction of the progress bar the next operation will use
83   //   seconds - expected time interval (progress bar moves at this minimum rate)
84   virtual void ShowProgress(float portion, float seconds) = 0;
85 
86   // Sets progress bar position (0.0 - 1.0 within the scope defined by the last call to
87   // ShowProgress).
88   virtual void SetProgress(float fraction) = 0;
89 
90   // --- text log ---
91 
92   virtual void ShowText(bool visible) = 0;
93 
94   virtual bool IsTextVisible() = 0;
95 
96   virtual bool WasTextEverVisible() = 0;
97 
98   // Writes a message to the on-screen log (shown if the user has toggled on the text display).
99   // Print() will also dump the message to stdout / log file, while PrintOnScreenOnly() not.
100   virtual void Print(const char* fmt, ...) __printflike(2, 3) = 0;
101   virtual void PrintOnScreenOnly(const char* fmt, ...) __printflike(2, 3) = 0;
102 
103   // Shows the contents of the given file. Caller ensures the patition that contains the file has
104   // been mounted.
105   virtual void ShowFile(const std::string& filename) = 0;
106 
107   // --- key handling ---
108 
109   // Waits for a key and return it. May return TIMED_OUT after timeout and
110   // KeyError::INTERRUPTED on a key interrupt.
111   virtual int WaitKey();
112 
113   // Wakes up the UI if it is waiting on key input, causing WaitKey to return KeyError::INTERRUPTED.
114   virtual void InterruptKey();
115 
116   virtual bool IsKeyPressed(int key);
117   virtual bool IsLongPress();
118 
119   // Returns true if you have the volume up/down and power trio typical of phones and tablets, false
120   // otherwise.
121   virtual bool HasThreeButtons() const;
122 
123   // Returns true if it has a power key.
124   virtual bool HasPowerKey() const;
125 
126   // Returns true if it supports touch inputs.
127   virtual bool HasTouchScreen() const;
128 
129   // Erases any queued-up keys.
130   virtual void FlushKeys();
131 
132   // Called on each key press, even while operations are in progress. Return value indicates whether
133   // an immediate operation should be triggered (toggling the display, rebooting the device), or if
134   // the key should be enqueued for use by the main thread.
135   virtual KeyAction CheckKey(int key, bool is_long_press);
136 
137   // Called when a key is held down long enough to have been a long-press (but before the key is
138   // released). This means that if the key is eventually registered (released without any other keys
139   // being pressed in the meantime), CheckKey will be called with 'is_long_press' true.
140   virtual void KeyLongPress(int key);
141 
142   // Normally in recovery there's a key sequence that triggers immediate reboot of the device,
143   // regardless of what recovery is doing (with the default CheckKey implementation, it's pressing
144   // the power button 7 times in row). Call this to enable or disable that feature. It is enabled by
145   // default.
146   virtual void SetEnableReboot(bool enabled);
147 
148   // --- menu display ---
149 
150   virtual void SetTitle(const std::vector<std::string>& lines) = 0;
151 
152   // Displays a menu with the given 'headers' and 'items'. The supplied 'key_handler' callback,
153   // which is typically bound to Device::HandleMenuKey(), should return the expected action for the
154   // given key code and menu visibility (e.g. to move the cursor or to select an item). Caller sets
155   // 'menu_only' to true to ensure only a menu item gets selected and returned. Otherwise if
156   // 'menu_only' is false, ShowMenu() will forward any non-negative value returned from the
157   // key_handler, which may be beyond the range of menu items. This could be used to trigger a
158   // device-specific action, even without that being listed in the menu. Caller needs to handle
159   // such a case accordingly (e.g. by calling Device::InvokeMenuItem() to process the action).
160   // Returns a non-negative value (the chosen item number or device-specific action code), or
161   // static_cast<size_t>(TIMED_OUT) if timed out waiting for input or
162   // static_cast<size_t>(ERR_KEY_INTERTUPT) if interrupted, such as by InterruptKey().
163   virtual size_t ShowMenu(const std::vector<std::string>& headers,
164                           const std::vector<std::string>& items, size_t initial_selection,
165                           bool menu_only, const std::function<int(int, bool)>& key_handler) = 0;
166 
167   // Displays the localized wipe data menu with pre-generated graphs. If there's an issue
168   // with the graphs, falls back to use the backup string headers and items instead. The initial
169   // selection is the 0th item in the menu, which is expected to reboot the device without a wipe.
170   virtual size_t ShowPromptWipeDataMenu(const std::vector<std::string>& backup_headers,
171                                         const std::vector<std::string>& backup_items,
172                                         const std::function<int(int, bool)>& key_handler) = 0;
173   // Displays the localized wipe data confirmation menu with pre-generated images. Falls back to
174   // the text strings upon failures. The initial selection is the 0th item, which returns to the
175   // upper level menu.
176   virtual size_t ShowPromptWipeDataConfirmationMenu(
177       const std::vector<std::string>& backup_headers, const std::vector<std::string>& backup_items,
178       const std::function<int(int, bool)>& key_handler) = 0;
179 
180   // Set whether or not the fastbootd logo is displayed.
SetEnableFastbootdLogo(bool enable)181   void SetEnableFastbootdLogo(bool enable) {
182     fastbootd_logo_enabled_ = enable;
183   }
184 
185   // Resets the key interrupt status.
ResetKeyInterruptStatus()186   void ResetKeyInterruptStatus() {
187     key_interrupted_ = false;
188   }
189 
190   // Returns the key interrupt status.
IsKeyInterrupted()191   bool IsKeyInterrupted() const {
192     return key_interrupted_;
193   }
194 
195   virtual bool IsUsbConnected();
196 
197  protected:
198   void EnqueueKey(int key_code);
199 
200   // The normal and dimmed brightness percentages (default: 50 and 25, which means 50% and 25% of
201   // the max_brightness). Because the absolute values may vary across devices. These two values can
202   // be configured via subclassing. Setting brightness_normal_ to 0 to disable screensaver.
203   unsigned int brightness_normal_;
204   unsigned int brightness_dimmed_;
205   std::string brightness_file_;
206   std::string max_brightness_file_;
207 
208   // Whether we should listen for touch inputs (default: false).
209   bool touch_screen_allowed_;
210 
211   bool fastbootd_logo_enabled_;
212 
213  private:
214   enum class ScreensaverState {
215     DISABLED,
216     NORMAL,
217     DIMMED,
218     OFF,
219   };
220 
221   // The sensitivity when detecting a swipe.
222   const int touch_low_threshold_;
223   const int touch_high_threshold_;
224 
225   void OnKeyDetected(int key_code);
226   void OnTouchDetected(int dx, int dy);
227   int OnInputEvent(int fd, uint32_t epevents);
228   void ProcessKey(int key_code, int updown);
229   void TimeKey(int key_code, int count);
230 
231   bool InitScreensaver();
232   void SetScreensaverState(ScreensaverState state);
233 
234   // Key event input queue
235   std::mutex key_queue_mutex;
236   std::condition_variable key_queue_cond;
237   bool key_interrupted_;
238   int key_queue[256], key_queue_len;
239 
240   // key press events
241   std::mutex key_press_mutex;
242   char key_pressed[KEY_MAX + 1];
243   int key_last_down;
244   bool key_long_press;
245   int key_down_count;
246   bool enable_reboot;
247 
248   int rel_sum;
249   int consecutive_power_keys;
250 
251   bool has_power_key;
252   bool has_up_key;
253   bool has_down_key;
254   bool has_touch_screen;
255 
256   // Touch event related variables. See the comments in RecoveryUI::OnInputEvent().
257   int touch_slot_;
258   int touch_X_;
259   int touch_Y_;
260   int touch_start_X_;
261   int touch_start_Y_;
262   bool touch_finger_down_;
263   bool touch_swiping_;
264   bool is_bootreason_recovery_ui_;
265 
266   std::thread input_thread_;
267   std::atomic<bool> input_thread_stopped_{ false };
268 
269   ScreensaverState screensaver_state_;
270 
271   // The following two contain the absolute values computed from brightness_normal_ and
272   // brightness_dimmed_ respectively.
273   unsigned int brightness_normal_value_;
274   unsigned int brightness_dimmed_value_;
275 };
276 
277 #endif  // RECOVERY_UI_H
278