Add ScreenRecoveryUI::ShowMenu().

From caller's PoV, RecoveryUI::{Start,Select,End}Menu should always be
used together, i.e. to show a menu and get user's selection. This CL
provides ShowMenu() as one-stop service (which is based on
get_menu_selection() from recovery.cpp).

Also move RecoveryUI::{Start,Select,End}Menu into ScreenRecoveryUI, with
a dropped access level from public to protected.

Due to the dependency on recovery / librecovery refactoring, will add
testcases in follow-up CLs.

Test: Build and boot into recovery image. Check the menus (main menu,
      'View recovery logs', 'Wipe data/factory reset').
Change-Id: Ie17aa78144871a12affd6f9075e045f76608a0ba
diff --git a/screen_ui.cpp b/screen_ui.cpp
index 317e552..aaeb18c 100644
--- a/screen_ui.cpp
+++ b/screen_ui.cpp
@@ -1009,6 +1009,53 @@
   pthread_mutex_unlock(&updateMutex);
 }
 
+int ScreenRecoveryUI::ShowMenu(const char* const* headers, const char* const* items,
+                               int initial_selection, bool menu_only,
+                               const std::function<int(int, bool)>& key_handler) {
+  // Throw away keys pressed previously, so user doesn't accidentally trigger menu items.
+  FlushKeys();
+
+  StartMenu(headers, items, initial_selection);
+
+  int selected = initial_selection;
+  int chosen_item = -1;
+  while (chosen_item < 0) {
+    int key = WaitKey();
+    if (key == -1) {  // WaitKey() timed out.
+      if (WasTextEverVisible()) {
+        continue;
+      } else {
+        LOG(INFO) << "Timed out waiting for key input; rebooting.";
+        EndMenu();
+        return -1;
+      }
+    }
+
+    bool visible = IsTextVisible();
+    int action = key_handler(key, visible);
+    if (action < 0) {
+      switch (action) {
+        case Device::kHighlightUp:
+          selected = SelectMenu(--selected);
+          break;
+        case Device::kHighlightDown:
+          selected = SelectMenu(++selected);
+          break;
+        case Device::kInvokeItem:
+          chosen_item = selected;
+          break;
+        case Device::kNoAction:
+          break;
+      }
+    } else if (!menu_only) {
+      chosen_item = action;
+    }
+  }
+
+  EndMenu();
+  return chosen_item;
+}
+
 bool ScreenRecoveryUI::IsTextVisible() {
   pthread_mutex_lock(&updateMutex);
   int visible = show_text;