split out device-specific recovery UI code into vendor directories

Take some device-specific details of the recovery UI (eg, what keys to
press to bring up the interface and perform actions, exact text of the
menu, etc.) and split them out into separate C functions.  Arrange to
take implementations of those functions from the appropriate vendor
directory at build time.  Provide a default implementation in case no
vendor-specific one is available.
diff --git a/Android.mk b/Android.mk
index 8c1de73..ba82017 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,11 +1,11 @@
+ifneq ($(TARGET_SIMULATOR),true)
+ifeq ($(TARGET_ARCH),arm)
+
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
 commands_recovery_local_path := $(LOCAL_PATH)
 
-ifneq ($(TARGET_SIMULATOR),true)
-ifeq ($(TARGET_ARCH),arm)
-
 LOCAL_SRC_FILES := \
 	recovery.c \
 	bootloader.c \
@@ -29,17 +29,22 @@
 
 LOCAL_MODULE_TAGS := eng
 
-LOCAL_STATIC_LIBRARIES := libminzip libunz libamend libmtdutils libmincrypt
+LOCAL_STATIC_LIBRARIES :=
+ifeq ($(TARGET_RECOVERY_UI_LIB),)
+  LOCAL_SRC_FILES += default_recovery_ui.c
+else
+  LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UI_LIB)
+endif
+LOCAL_STATIC_LIBRARIES += libminzip libunz libamend libmtdutils libmincrypt
 LOCAL_STATIC_LIBRARIES += libminui libpixelflinger_static libpng libcutils
 LOCAL_STATIC_LIBRARIES += libstdc++ libc
 
 include $(BUILD_EXECUTABLE)
 
-include $(commands_recovery_local_path)/minui/Android.mk
-
 endif   # TARGET_ARCH == arm
 endif	# !TARGET_SIMULATOR
 
+include $(commands_recovery_local_path)/minui/Android.mk
 include $(commands_recovery_local_path)/amend/Android.mk
 include $(commands_recovery_local_path)/minzip/Android.mk
 include $(commands_recovery_local_path)/mtdutils/Android.mk
diff --git a/default_recovery_ui.c b/default_recovery_ui.c
new file mode 100644
index 0000000..7bc5f2c
--- /dev/null
+++ b/default_recovery_ui.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <linux/input.h>
+
+#include "recovery_ui.h"
+#include "common.h"
+
+char* MENU_HEADERS[] = { "Android system recovery utility",
+                         "",
+                         NULL };
+
+char* MENU_ITEMS[] = { "reboot system now",
+                       "apply sdcard:update.zip",
+                       "wipe data/factory reset",
+                       "wipe cache partition",
+                       NULL };
+
+int device_toggle_display(char* key_pressed, int key_code) {
+  return key_code == KEY_HOME;
+}
+
+int device_reboot_now(char* key_pressed, int key_code) {
+  return 0;
+}
+
+int device_handle_key(int key_code, int visible) {
+  if (visible) {
+    switch (key_code) {
+      case KEY_DOWN:
+      case KEY_VOLUMEDOWN:
+        return HIGHLIGHT_DOWN;
+
+      case KEY_UP:
+      case KEY_VOLUMEUP:
+        return HIGHLIGHT_UP;
+
+      case KEY_ENTER:
+        return SELECT_ITEM;
+    }
+  }
+
+  return NO_ACTION;
+}
+
+void device_perform_action(int which) {
+  // none defined
+}
diff --git a/minui/minui.h b/minui/minui.h
index 80b47a4..567d421 100644
--- a/minui/minui.h
+++ b/minui/minui.h
@@ -41,22 +41,6 @@
 // see http://www.mjmwired.net/kernel/Documentation/input/ for info.
 struct input_event;
 
-// Dream-specific key codes
-#define KEY_DREAM_HOME        102  // = KEY_HOME
-#define KEY_DREAM_RED         107  // = KEY_END
-#define KEY_DREAM_VOLUMEDOWN  114  // = KEY_VOLUMEDOWN
-#define KEY_DREAM_VOLUMEUP    115  // = KEY_VOLUMEUP
-#define KEY_DREAM_SYM         127  // = KEY_COMPOSE
-#define KEY_DREAM_MENU        139  // = KEY_MENU
-#define KEY_DREAM_BACK        158  // = KEY_BACK
-#define KEY_DREAM_FOCUS       211  // = KEY_HP (light touch on camera)
-#define KEY_DREAM_CAMERA      212  // = KEY_CAMERA
-#define KEY_DREAM_AT          215  // = KEY_EMAIL
-#define KEY_DREAM_GREEN       231
-#define KEY_DREAM_FATTOUCH    258  // = BTN_2 ???
-#define KEY_DREAM_BALL        272  // = BTN_MOUSE
-#define KEY_DREAM_TOUCH       330  // = BTN_TOUCH
-
 int ev_init(void);
 void ev_exit(void);
 int ev_get(struct input_event *ev, unsigned dont_wait);
diff --git a/recovery.c b/recovery.c
index 188d4de..6c13b9f 100644
--- a/recovery.c
+++ b/recovery.c
@@ -37,6 +37,7 @@
 #include "minui/minui.h"
 #include "minzip/DirUtil.h"
 #include "roots.h"
+#include "recovery_ui.h"
 
 static const struct option OPTIONS[] = {
   { "send_intent", required_argument, NULL, 's' },
@@ -287,25 +288,7 @@
 static void
 prompt_and_wait()
 {
-    char* headers[] = { "Android system recovery utility",
-                        "",
-                        "Use trackball to highlight;",
-                        "click to select.",
-                        "",
-                        NULL };
-
-    // these constants correspond to elements of the items[] list.
-#define ITEM_REBOOT        0
-#define ITEM_APPLY_SDCARD  1
-#define ITEM_WIPE_DATA     2
-#define ITEM_WIPE_CACHE    3
-    char* items[] = { "reboot system now [Home+Back]",
-                      "apply sdcard:update.zip [Alt+S]",
-                      "wipe data/factory reset [Alt+W]",
-                      "wipe cache partition",
-                      NULL };
-
-    ui_start_menu(headers, items);
+    ui_start_menu(MENU_HEADERS, MENU_ITEMS);
     int selected = 0;
     int chosen_item = -1;
 
@@ -313,29 +296,28 @@
     ui_reset_progress();
     for (;;) {
         int key = ui_wait_key();
-        int alt = ui_key_pressed(KEY_LEFTALT) || ui_key_pressed(KEY_RIGHTALT);
         int visible = ui_text_visible();
 
-        if (key == KEY_DREAM_BACK && ui_key_pressed(KEY_DREAM_HOME)) {
-            // Wait for the keys to be released, to avoid triggering
-            // special boot modes (like coming back into recovery!).
-            while (ui_key_pressed(KEY_DREAM_BACK) ||
-                   ui_key_pressed(KEY_DREAM_HOME)) {
-                usleep(1000);
+        int action = device_handle_key(key, visible);
+
+        if (action < 0) {
+            switch (action) {
+                case HIGHLIGHT_UP:
+                    --selected;
+                    selected = ui_menu_select(selected);
+                    break;
+                case HIGHLIGHT_DOWN:
+                    ++selected;
+                    selected = ui_menu_select(selected);
+                    break;
+                case SELECT_ITEM:
+                    chosen_item = selected;
+                    break;
+                case NO_ACTION:
+                    break;
             }
-            chosen_item = ITEM_REBOOT;
-        } else if (alt && key == KEY_W) {
-            chosen_item = ITEM_WIPE_DATA;
-        } else if (alt && key == KEY_S) {
-            chosen_item = ITEM_APPLY_SDCARD;
-        } else if ((key == KEY_DOWN || key == KEY_VOLUMEDOWN) && visible) {
-            ++selected;
-            selected = ui_menu_select(selected);
-        } else if ((key == KEY_UP || key == KEY_VOLUMEUP) && visible) {
-            --selected;
-            selected = ui_menu_select(selected);
-        } else if (key == BTN_MOUSE && visible) {
-            chosen_item = selected;
+        } else {
+            chosen_item = action;
         }
 
         if (chosen_item >= 0) {
@@ -343,6 +325,11 @@
             // on the screen.
             ui_end_menu();
 
+            // device-specific code may take some action here.  It may
+            // return one of the core actions handled in the switch
+            // statement below.
+            chosen_item = device_perform_action(chosen_item);
+
             switch (chosen_item) {
                 case ITEM_REBOOT:
                     return;
@@ -372,8 +359,8 @@
                         return;  // reboot if logs aren't visible
                     } else {
                       if (firmware_update_pending()) {
-                        ui_print("\nReboot via home+back or menu\n"
-                                 "to complete installation.\n");
+                        ui_print("\nReboot via menu to complete\n"
+                                 "installation.\n");
                       } else {
                         ui_print("\nInstall from sdcard complete.\n");
                       }
@@ -383,7 +370,7 @@
 
             // if we didn't return from this function to reboot, show
             // the menu again.
-            ui_start_menu(headers, items);
+            ui_start_menu(MENU_HEADERS, MENU_ITEMS);
             selected = 0;
             chosen_item = -1;
 
diff --git a/recovery_ui.h b/recovery_ui.h
new file mode 100644
index 0000000..86f540b
--- /dev/null
+++ b/recovery_ui.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _RECOVERY_UI_H
+#define _RECOVERY_UI_H
+
+// Called in the input thread when a new key (key_code) is pressed.
+// *key_pressed is an array of KEY_MAX+1 bytes indicating which other
+// keys are already pressed.  Return true if the text display should
+// be toggled.
+extern int device_toggle_display(char* key_pressed, int key_code);
+
+// Called in the input thread when a new key (key_code) is pressed.
+// *key_pressed is an array of KEY_MAX+1 bytes indicating which other
+// keys are already pressed.  Return true if the device should reboot
+// immediately.
+extern int device_reboot_now(char* key_pressed, int key_code);
+
+// Called from the main thread when recovery is waiting for input and
+// a key is pressed.  key is the code of the key pressed; visible is
+// true if the recovery menu is being shown.  Implementations can call
+// ui_key_pressed() to discover if other keys are being held down.
+// Return one of the defined constants below in order to:
+//
+//   - move the menu highlight (HIGHLIGHT_*)
+//   - invoke the highlighted item (SELECT_ITEM)
+//   - do nothing (NO_ACTION)
+//   - invoke a specific action (a menu position: any non-negative number)
+extern int device_handle_key(int key, int visible);
+
+// Perform a recovery action selected from the menu.  'which' will be
+// the item number of the selected menu item, or a non-negative number
+// returned from device_handle_key().  The menu will be hidden when
+// this is called; implementations can call ui_print() to print
+// information to the screen.
+extern int device_perform_action(int which);
+
+#define NO_ACTION           -1
+
+#define HIGHLIGHT_UP        -2
+#define HIGHLIGHT_DOWN      -3
+#define SELECT_ITEM         -4
+
+#define ITEM_REBOOT          0
+#define ITEM_APPLY_SDCARD    1
+#define ITEM_WIPE_DATA       2
+#define ITEM_WIPE_CACHE      3
+
+// Header text to display above the main menu.
+extern char* MENU_HEADERS[];
+
+// Text of menu items.
+extern char* MENU_ITEMS[];
+
+#endif
diff --git a/ui.c b/ui.c
index b84f172..039d682 100644
--- a/ui.c
+++ b/ui.c
@@ -307,20 +307,14 @@
         }
         pthread_mutex_unlock(&key_queue_mutex);
 
-        // Alt+L or Home+End: toggle log display
-        int alt = key_pressed[KEY_LEFTALT] || key_pressed[KEY_RIGHTALT];
-        if ((alt && ev.code == KEY_L && ev.value > 0) ||
-            (key_pressed[KEY_HOME] && ev.code == KEY_END && ev.value > 0)) {
+        if (ev.value > 0 && device_toggle_display(key_pressed, ev.code)) {
             pthread_mutex_lock(&gUpdateMutex);
             show_text = !show_text;
             update_screen_locked();
             pthread_mutex_unlock(&gUpdateMutex);
         }
 
-        // Green+Menu+Red: reboot immediately
-        if (ev.code == KEY_DREAM_RED &&
-            key_pressed[KEY_DREAM_MENU] &&
-            key_pressed[KEY_DREAM_GREEN]) {
+        if (ev.value > 0 && device_reboot_now(key_pressed, ev.code)) {
             reboot(RB_AUTOBOOT);
         }
     }