notify about pending long press

Recovery changes:

- add a method to the UI class that is called when a key is held down
  long enough to be a "long press" (but before it is released).
  Device-specific subclasses can override this to indicate a long
  press.

- do color selection for ScreenRecoveryUI's menu-and-log drawing
  function.  Subclasses can override this to customize the colors they
  use for various elements.

- Include the value of ro.build.display.id in the menu headers, so you
  can see on the screen what version of recovery you are running.

Change-Id: I426a6daf892b9011638e2035aebfa2831d4f596d
diff --git a/recovery.cpp b/recovery.cpp
index c5a589c..38366b6 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -75,6 +75,7 @@
 
 RecoveryUI* ui = NULL;
 char* locale = NULL;
+char recovery_version[PROPERTY_VALUE_MAX+1];
 
 /*
  * The recovery tool communicates with the main system through /cache files.
@@ -526,21 +527,17 @@
 
 static const char**
 prepend_title(const char* const* headers) {
-    const char* title[] = { "Android system recovery <"
-                            EXPAND(RECOVERY_API_VERSION) "e>",
-                            "",
-                            NULL };
-
     // count the number of lines in our title, plus the
     // caller-provided headers.
-    int count = 0;
+    int count = 3;   // our title has 3 lines
     const char* const* p;
-    for (p = title; *p; ++p, ++count);
     for (p = headers; *p; ++p, ++count);
 
     const char** new_headers = (const char**)malloc((count+1) * sizeof(char*));
     const char** h = new_headers;
-    for (p = title; *p; ++p, ++h) *h = *p;
+    *(h++) = "Android system recovery <" EXPAND(RECOVERY_API_VERSION) "e>";
+    *(h++) = recovery_version;
+    *(h++) = "";
     for (p = headers; *p; ++p, ++h) *h = *p;
     *h = NULL;
 
@@ -1022,6 +1019,7 @@
     printf("\n");
 
     property_list(print_property, NULL);
+    property_get("ro.build.display.id", recovery_version, "");
     printf("\n");
 
     int status = INSTALL_SUCCESS;
diff --git a/screen_ui.cpp b/screen_ui.cpp
index 93e2609..6a63858 100644
--- a/screen_ui.cpp
+++ b/screen_ui.cpp
@@ -196,9 +196,29 @@
     }
 }
 
-#define C_HEADER  247,0,6
-#define C_MENU    0,106,157
-#define C_LOG     249,194,0
+void ScreenRecoveryUI::SetColor(UIElement e) {
+    switch (e) {
+        case HEADER:
+            gr_color(247, 0, 6, 255);
+            break;
+        case MENU:
+        case MENU_SEL_BG:
+            gr_color(0, 106, 157, 255);
+            break;
+        case MENU_SEL_FG:
+            gr_color(255, 255, 255, 255);
+            break;
+        case LOG:
+            gr_color(249, 194, 0, 255);
+            break;
+        case TEXT_FILL:
+            gr_color(0, 0, 0, 160);
+            break;
+        default:
+            gr_color(255, 255, 255, 255);
+            break;
+    }
+}
 
 // Redraw everything on the screen.  Does not flip pages.
 // Should only be called with updateMutex locked.
@@ -208,37 +228,38 @@
     draw_progress_locked();
 
     if (show_text) {
-        gr_color(0, 0, 0, 160);
+        SetColor(TEXT_FILL);
         gr_fill(0, 0, gr_fb_width(), gr_fb_height());
 
         int y = 0;
         int i = 0;
         if (show_menu) {
-            gr_color(C_HEADER, 255);
+            SetColor(HEADER);
 
             for (; i < menu_top + menu_items; ++i) {
-                if (i == menu_top) gr_color(C_MENU, 255);
+                if (i == menu_top) SetColor(MENU);
 
                 if (i == menu_top + menu_sel) {
                     // draw the highlight bar
+                    SetColor(MENU_SEL_BG);
                     gr_fill(0, y-2, gr_fb_width(), y+char_height+2);
                     // white text of selected item
-                    gr_color(255, 255, 255, 255);
+                    SetColor(MENU_SEL_FG);
                     if (menu[i][0]) gr_text(4, y, menu[i], 1);
-                    gr_color(C_MENU, 255);
+                    SetColor(MENU);
                 } else {
                     if (menu[i][0]) gr_text(4, y, menu[i], i < menu_top);
                 }
                 y += char_height+4;
             }
-            gr_color(C_MENU, 255);
+            SetColor(MENU);
             y += 4;
             gr_fill(0, y, gr_fb_width(), y+2);
             y += 4;
             ++i;
         }
 
-        gr_color(C_LOG, 255);
+        SetColor(LOG);
 
         // display from the bottom up, until we hit the top of the
         // screen, the bottom of the menu, or we've displayed the
@@ -585,3 +606,10 @@
     update_screen_locked();
     pthread_mutex_unlock(&updateMutex);
 }
+
+void ScreenRecoveryUI::Redraw()
+{
+    pthread_mutex_lock(&updateMutex);
+    update_screen_locked();
+    pthread_mutex_unlock(&updateMutex);
+}
diff --git a/screen_ui.h b/screen_ui.h
index fe0de46..0bd220f 100644
--- a/screen_ui.h
+++ b/screen_ui.h
@@ -53,6 +53,11 @@
     int SelectMenu(int sel);
     void EndMenu();
 
+    void Redraw();
+
+    enum UIElement { HEADER, MENU, MENU_SEL_BG, MENU_SEL_FG, LOG, TEXT_FILL };
+    virtual void SetColor(UIElement e);
+
   private:
     Icon currentIcon;
     int installingFrame;
diff --git a/ui.cpp b/ui.cpp
index 65f4028..cece02d 100644
--- a/ui.cpp
+++ b/ui.cpp
@@ -46,7 +46,8 @@
 RecoveryUI::RecoveryUI() :
     key_queue_len(0),
     key_last_down(-1),
-    key_down_time(0) {
+    key_long_press(false),
+    key_down_count(0) {
     pthread_mutex_init(&key_queue_mutex, NULL);
     pthread_cond_init(&key_queue_cond, NULL);
     self = this;
@@ -112,19 +113,22 @@
     bool register_key = false;
     bool long_press = false;
 
-    const long long_threshold = CLOCKS_PER_SEC * 750 / 1000;
-
     pthread_mutex_lock(&key_queue_mutex);
     key_pressed[key_code] = updown;
     if (updown) {
+        ++key_down_count;
         key_last_down = key_code;
-        key_down_time = clock();
+        key_long_press = false;
+        pthread_t th;
+        key_timer_t* info = new key_timer_t;
+        info->ui = this;
+        info->key_code = key_code;
+        info->count = key_down_count;
+        pthread_create(&th, NULL, &RecoveryUI::time_key_helper, info);
+        pthread_detach(th);
     } else {
         if (key_last_down == key_code) {
-            long duration = clock() - key_down_time;
-            if (duration > long_threshold) {
-                long_press = true;
-            }
+            long_press = key_long_press;
             register_key = true;
         }
         key_last_down = -1;
@@ -152,6 +156,24 @@
     }
 }
 
+void* RecoveryUI::time_key_helper(void* cookie) {
+    key_timer_t* info = (key_timer_t*) cookie;
+    info->ui->time_key(info->key_code, info->count);
+    delete info;
+    return NULL;
+}
+
+void RecoveryUI::time_key(int key_code, int count) {
+    usleep(750000);  // 750 ms == "long"
+    bool long_press = false;
+    pthread_mutex_lock(&key_queue_mutex);
+    if (key_last_down == key_code && key_down_count == count) {
+        long_press = key_long_press = true;
+    }
+    pthread_mutex_unlock(&key_queue_mutex);
+    if (long_press) KeyLongPress(key_code);
+}
+
 void RecoveryUI::EnqueueKey(int key_code) {
     pthread_mutex_lock(&key_queue_mutex);
     const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
@@ -242,3 +264,6 @@
 
 void RecoveryUI::NextCheckKeyIsLong(bool is_long_press) {
 }
+
+void RecoveryUI::KeyLongPress(int key) {
+}
diff --git a/ui.h b/ui.h
index aca7b7b..6c8987a 100644
--- a/ui.h
+++ b/ui.h
@@ -80,8 +80,17 @@
     enum KeyAction { ENQUEUE, TOGGLE, REBOOT, IGNORE };
     virtual KeyAction CheckKey(int key);
 
+    // Called immediately before each call to CheckKey(), tell you if
+    // the key was long-pressed.
     virtual void NextCheckKeyIsLong(bool is_long_press);
 
+    // Called when a key is held down long enough to have been a
+    // long-press (but before the key is released).  This means that
+    // if the key is eventually registered (released without any other
+    // keys being pressed in the meantime), NextCheckKeyIsLong() will
+    // be called with "true".
+    virtual void KeyLongPress(int key);
+
     // --- menu display ---
 
     // Display some header text followed by a menu of items, which appears
@@ -108,15 +117,25 @@
     int key_queue[256], key_queue_len;
     char key_pressed[KEY_MAX + 1];     // under key_queue_mutex
     int key_last_down;                 // under key_queue_mutex
-    clock_t key_down_time;             // under key_queue_mutex
+    bool key_long_press;               // under key_queue_mutex
+    int key_down_count;                // under key_queue_mutex
     int rel_sum;
 
+    typedef struct {
+        RecoveryUI* ui;
+        int key_code;
+        int count;
+    } key_timer_t;
+
     pthread_t input_t;
 
     static void* input_thread(void* cookie);
     static int input_callback(int fd, short revents, void* data);
     void process_key(int key_code, int updown);
     bool usb_connected();
+
+    static void* time_key_helper(void* cookie);
+    void time_key(int key_code, int count);
 };
 
 #endif  // RECOVERY_UI_H