auto import from //branches/cupcake/...@130745
This commit is contained in:
parent
928d471ef2
commit
8b7334b3c2
4 changed files with 253 additions and 47 deletions
12
common.h
12
common.h
|
@ -26,12 +26,24 @@ void ui_init();
|
|||
int ui_wait_key(); // waits for a key/button press, returns the code
|
||||
int ui_key_pressed(int key); // returns >0 if the code is currently pressed
|
||||
int ui_text_visible(); // returns >0 if text log is currently visible
|
||||
void ui_clear_key_queue();
|
||||
|
||||
// Write a message to the on-screen log shown with Alt-L (also to stderr).
|
||||
// The screen is small, and users may need to report these messages to support,
|
||||
// so keep the output short and not too cryptic.
|
||||
void ui_print(const char *fmt, ...);
|
||||
|
||||
// Display some header text followed by a menu of items, which appears
|
||||
// at the top of the screen (in place of any scrolling ui_print()
|
||||
// output, if necessary).
|
||||
void ui_start_menu(char** headers, char** items);
|
||||
// Set the menu highlight to the given index, and return it (capped to
|
||||
// the range [0..numitems).
|
||||
int ui_menu_select(int sel);
|
||||
// End menu mode, resetting the text overlay so that ui_print()
|
||||
// statements will be displayed.
|
||||
void ui_end_menu();
|
||||
|
||||
// Set the icon (normally the only thing visible besides the progress bar).
|
||||
enum {
|
||||
BACKGROUND_ICON_NONE,
|
||||
|
|
|
@ -43,6 +43,7 @@ static GRFont *gr_font = 0;
|
|||
static GGLContext *gr_context = 0;
|
||||
static GGLSurface gr_font_texture;
|
||||
static GGLSurface gr_framebuffer[2];
|
||||
static GGLSurface gr_mem_surface;
|
||||
static unsigned gr_active_fb = 0;
|
||||
|
||||
static int gr_fb_fd = -1;
|
||||
|
@ -55,7 +56,7 @@ static int get_framebuffer(GGLSurface *fb)
|
|||
int fd;
|
||||
struct fb_fix_screeninfo fi;
|
||||
void *bits;
|
||||
|
||||
|
||||
fd = open("/dev/graphics/fb0", O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror("cannot open fb0");
|
||||
|
@ -87,9 +88,9 @@ static int get_framebuffer(GGLSurface *fb)
|
|||
fb->stride = vi.xres;
|
||||
fb->data = bits;
|
||||
fb->format = GGL_PIXEL_FORMAT_RGB_565;
|
||||
|
||||
|
||||
fb++;
|
||||
|
||||
|
||||
fb->version = sizeof(*fb);
|
||||
fb->width = vi.xres;
|
||||
fb->height = vi.yres;
|
||||
|
@ -100,6 +101,15 @@ static int get_framebuffer(GGLSurface *fb)
|
|||
return fd;
|
||||
}
|
||||
|
||||
static void get_memory_surface(GGLSurface* ms) {
|
||||
ms->version = sizeof(*ms);
|
||||
ms->width = vi.xres;
|
||||
ms->height = vi.yres;
|
||||
ms->stride = vi.xres;
|
||||
ms->data = malloc(vi.xres * vi.yres * 2);
|
||||
ms->format = GGL_PIXEL_FORMAT_RGB_565;
|
||||
}
|
||||
|
||||
static void set_active_framebuffer(unsigned n)
|
||||
{
|
||||
if (n > 1) return;
|
||||
|
@ -113,14 +123,16 @@ static void set_active_framebuffer(unsigned n)
|
|||
void gr_flip(void)
|
||||
{
|
||||
GGLContext *gl = gr_context;
|
||||
|
||||
/* currently active buffer becomes the backbuffer */
|
||||
gl->colorBuffer(gl, gr_framebuffer + gr_active_fb);
|
||||
|
||||
/* swap front and back buffers */
|
||||
/* swap front and back buffers */
|
||||
gr_active_fb = (gr_active_fb + 1) & 1;
|
||||
|
||||
/* inform the display driver */
|
||||
/* copy data from the in-memory surface to the buffer we're about
|
||||
* to make active. */
|
||||
memcpy(gr_framebuffer[gr_active_fb].data, gr_mem_surface.data,
|
||||
vi.xres * vi.yres * 2);
|
||||
|
||||
/* inform the display driver */
|
||||
set_active_framebuffer(gr_active_fb);
|
||||
}
|
||||
|
||||
|
@ -147,13 +159,13 @@ int gr_text(int x, int y, const char *s)
|
|||
unsigned off;
|
||||
|
||||
y -= font->ascent;
|
||||
|
||||
|
||||
gl->bindTexture(gl, &font->texture);
|
||||
gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
|
||||
gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
|
||||
gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
|
||||
gl->enable(gl, GGL_TEXTURE_2D);
|
||||
|
||||
|
||||
while((off = *s++)) {
|
||||
off -= 32;
|
||||
if (off < 96) {
|
||||
|
@ -209,10 +221,10 @@ static void gr_init_font(void)
|
|||
unsigned char *in, data;
|
||||
|
||||
gr_font = calloc(sizeof(*gr_font), 1);
|
||||
ftex = &gr_font->texture;
|
||||
ftex = &gr_font->texture;
|
||||
|
||||
bits = malloc(font.width * font.height);
|
||||
|
||||
|
||||
ftex->version = sizeof(*ftex);
|
||||
ftex->width = font.width;
|
||||
ftex->height = font.height;
|
||||
|
@ -225,7 +237,7 @@ static void gr_init_font(void)
|
|||
memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
|
||||
bits += (data & 0x7f);
|
||||
}
|
||||
|
||||
|
||||
gr_font->cwidth = font.cwidth;
|
||||
gr_font->cheight = font.cheight;
|
||||
gr_font->ascent = font.cheight - 2;
|
||||
|
@ -254,13 +266,16 @@ int gr_init(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
get_memory_surface(&gr_mem_surface);
|
||||
|
||||
fprintf(stderr, "framebuffer: fd %d (%d x %d)\n",
|
||||
gr_fb_fd, gr_framebuffer[0].width, gr_framebuffer[0].height);
|
||||
|
||||
/* start with 0 as front (displayed) and 1 as back (drawing) */
|
||||
gr_active_fb = 0;
|
||||
set_active_framebuffer(0);
|
||||
gl->colorBuffer(gl, gr_framebuffer + 1);
|
||||
gl->colorBuffer(gl, &gr_mem_surface);
|
||||
|
||||
|
||||
gl->activeTexture(gl, 0);
|
||||
gl->enable(gl, GGL_BLEND);
|
||||
|
@ -273,7 +288,9 @@ void gr_exit(void)
|
|||
{
|
||||
close(gr_fb_fd);
|
||||
gr_fb_fd = -1;
|
||||
|
||||
|
||||
free(gr_mem_surface.data);
|
||||
|
||||
ioctl(gr_vt_fd, KDSETMODE, (void*) KD_TEXT);
|
||||
close(gr_vt_fd);
|
||||
gr_vt_fd = -1;
|
||||
|
@ -291,5 +308,5 @@ int gr_fb_height(void)
|
|||
|
||||
gr_pixel *gr_fb_data(void)
|
||||
{
|
||||
return (unsigned short *) gr_framebuffer[1 - gr_active_fb].data;
|
||||
return (unsigned short *) gr_mem_surface.data;
|
||||
}
|
||||
|
|
99
recovery.c
99
recovery.c
|
@ -291,17 +291,32 @@ erase_root(const char *root)
|
|||
static void
|
||||
prompt_and_wait()
|
||||
{
|
||||
ui_print("\n"
|
||||
"Home+Back - reboot system now\n"
|
||||
"Alt+L - toggle log text display\n"
|
||||
"Alt+S - apply sdcard:update.zip\n"
|
||||
"Alt+W - wipe data/factory reset\n");
|
||||
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
|
||||
char* items[] = { "reboot system now [Home+Back]",
|
||||
"apply sdcard:update.zip [Alt+S]",
|
||||
"wipe data/factory reset [Alt+W]",
|
||||
NULL };
|
||||
|
||||
ui_start_menu(headers, items);
|
||||
int selected = 0;
|
||||
int chosen_item = -1;
|
||||
|
||||
finish_recovery(NULL);
|
||||
ui_reset_progress();
|
||||
for (;;) {
|
||||
finish_recovery(NULL);
|
||||
ui_reset_progress();
|
||||
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
|
||||
|
@ -310,23 +325,64 @@ prompt_and_wait()
|
|||
ui_key_pressed(KEY_DREAM_HOME)) {
|
||||
usleep(1000);
|
||||
}
|
||||
break;
|
||||
chosen_item = ITEM_REBOOT;
|
||||
} else if (alt && key == KEY_W) {
|
||||
ui_print("\n");
|
||||
erase_root("DATA:");
|
||||
erase_root("CACHE:");
|
||||
ui_print("Data wipe complete.\n");
|
||||
if (!ui_text_visible()) break;
|
||||
chosen_item = ITEM_WIPE_DATA;
|
||||
} else if (alt && key == KEY_S) {
|
||||
ui_print("\nInstalling from sdcard...\n");
|
||||
int status = install_package(SDCARD_PACKAGE_FILE);
|
||||
if (status != INSTALL_SUCCESS) {
|
||||
ui_set_background(BACKGROUND_ICON_ERROR);
|
||||
ui_print("Installation aborted.\n");
|
||||
} else if (!ui_text_visible()) {
|
||||
break; // reboot if logs aren't visible
|
||||
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;
|
||||
}
|
||||
|
||||
if (chosen_item >= 0) {
|
||||
// turn off the menu, letting ui_print() to scroll output
|
||||
// on the screen.
|
||||
ui_end_menu();
|
||||
|
||||
switch (chosen_item) {
|
||||
case ITEM_REBOOT:
|
||||
return;
|
||||
|
||||
case ITEM_WIPE_DATA:
|
||||
ui_print("\n-- Wiping data...\n");
|
||||
erase_root("DATA:");
|
||||
erase_root("CACHE:");
|
||||
ui_print("Data wipe complete.\n");
|
||||
if (!ui_text_visible()) return;
|
||||
break;
|
||||
|
||||
case ITEM_APPLY_SDCARD:
|
||||
ui_print("\n-- Install from sdcard...\n");
|
||||
int status = install_package(SDCARD_PACKAGE_FILE);
|
||||
if (status != INSTALL_SUCCESS) {
|
||||
ui_set_background(BACKGROUND_ICON_ERROR);
|
||||
ui_print("Installation aborted.\n");
|
||||
} else if (!ui_text_visible()) {
|
||||
return; // reboot if logs aren't visible
|
||||
} else {
|
||||
ui_print("Install from sdcard complete.\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
ui_print("\nPress Home+Back to reboot\n");
|
||||
|
||||
// if we didn't return from this function to reboot, show
|
||||
// the menu again.
|
||||
ui_start_menu(headers, items);
|
||||
selected = 0;
|
||||
chosen_item = -1;
|
||||
|
||||
finish_recovery(NULL);
|
||||
ui_reset_progress();
|
||||
|
||||
// throw away keys pressed while the command was running,
|
||||
// so user doesn't accidentally trigger menu items.
|
||||
ui_clear_key_queue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -348,7 +404,6 @@ main(int argc, char **argv)
|
|||
fprintf(stderr, "Starting recovery on %s", ctime(&start));
|
||||
|
||||
ui_init();
|
||||
ui_print("Android system recovery utility\n");
|
||||
get_args(&argc, &argv);
|
||||
|
||||
int previous_runs = 0;
|
||||
|
|
140
ui.c
140
ui.c
|
@ -89,6 +89,10 @@ static int text_cols = 0, text_rows = 0;
|
|||
static int text_col = 0, text_row = 0, text_top = 0;
|
||||
static int show_text = 0;
|
||||
|
||||
static char menu[MAX_ROWS][MAX_COLS];
|
||||
static int show_menu = 0;
|
||||
static int menu_top = 0, menu_items = 0, menu_sel = 0;
|
||||
|
||||
// Key event input queue
|
||||
static pthread_mutex_t key_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t key_queue_cond = PTHREAD_COND_INITIALIZER;
|
||||
|
@ -154,6 +158,12 @@ static void draw_progress_locked()
|
|||
}
|
||||
}
|
||||
|
||||
static void draw_text_line(int row, const char* t) {
|
||||
if (t[0] != '\0') {
|
||||
gr_text(0, (row+1)*CHAR_HEIGHT-1, t);
|
||||
}
|
||||
}
|
||||
|
||||
// Redraw everything on the screen. Does not flip pages.
|
||||
// Should only be called with gUpdateMutex locked.
|
||||
static void draw_screen_locked(void)
|
||||
|
@ -163,13 +173,32 @@ static void draw_screen_locked(void)
|
|||
|
||||
if (show_text) {
|
||||
gr_color(0, 0, 0, 160);
|
||||
gr_fill(0, 0, gr_fb_width(), text_rows * CHAR_HEIGHT);
|
||||
gr_fill(0, 0, gr_fb_width(), gr_fb_height());
|
||||
|
||||
int i = 0;
|
||||
if (show_menu) {
|
||||
gr_color(64, 96, 255, 255);
|
||||
gr_fill(0, (menu_top+menu_sel) * CHAR_HEIGHT,
|
||||
gr_fb_width(), (menu_top+menu_sel+1)*CHAR_HEIGHT+1);
|
||||
|
||||
for (; i < menu_top + menu_items; ++i) {
|
||||
if (i == menu_top + menu_sel) {
|
||||
gr_color(255, 255, 255, 255);
|
||||
draw_text_line(i, menu[i]);
|
||||
gr_color(64, 96, 255, 255);
|
||||
} else {
|
||||
draw_text_line(i, menu[i]);
|
||||
}
|
||||
}
|
||||
gr_fill(0, i*CHAR_HEIGHT+CHAR_HEIGHT/2-1,
|
||||
gr_fb_width(), i*CHAR_HEIGHT+CHAR_HEIGHT/2+1);
|
||||
++i;
|
||||
}
|
||||
|
||||
gr_color(255, 255, 0, 255);
|
||||
int i;
|
||||
for (i = 0; i < text_rows; ++i) {
|
||||
const char* line = text[(i + text_top) % text_rows];
|
||||
if (line[0] != '\0') gr_text(0, (i + 1) * CHAR_HEIGHT - 1, line);
|
||||
|
||||
for (; i < text_rows; ++i) {
|
||||
draw_text_line(i, text[(i+text_top) % text_rows]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -228,13 +257,50 @@ static void *progress_thread(void *cookie)
|
|||
// Reads input events, handles special hot keys, and adds to the key queue.
|
||||
static void *input_thread(void *cookie)
|
||||
{
|
||||
int rel_sum = 0;
|
||||
int fake_key = 0;
|
||||
for (;;) {
|
||||
// wait for the next key event
|
||||
struct input_event ev;
|
||||
do { ev_get(&ev, 0); } while (ev.type != EV_KEY || ev.code > KEY_MAX);
|
||||
do {
|
||||
ev_get(&ev, 0);
|
||||
|
||||
if (ev.type == EV_SYN) {
|
||||
continue;
|
||||
} else if (ev.type == EV_REL) {
|
||||
if (ev.code == REL_Y) {
|
||||
// accumulate the up or down motion reported by
|
||||
// the trackball. When it exceeds a threshold
|
||||
// (positive or negative), fake an up/down
|
||||
// key event.
|
||||
rel_sum += ev.value;
|
||||
if (rel_sum > 3) {
|
||||
fake_key = 1;
|
||||
ev.type = EV_KEY;
|
||||
ev.code = KEY_DOWN;
|
||||
ev.value = 1;
|
||||
rel_sum = 0;
|
||||
} else if (rel_sum < -3) {
|
||||
fake_key = 1;
|
||||
ev.type = EV_KEY;
|
||||
ev.code = KEY_UP;
|
||||
ev.value = 1;
|
||||
rel_sum = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rel_sum = 0;
|
||||
}
|
||||
} while (ev.type != EV_KEY || ev.code > KEY_MAX);
|
||||
|
||||
pthread_mutex_lock(&key_queue_mutex);
|
||||
key_pressed[ev.code] = ev.value;
|
||||
if (!fake_key) {
|
||||
// our "fake" keys only report a key-down event (no
|
||||
// key-up), so don't record them in the key_pressed
|
||||
// table.
|
||||
key_pressed[ev.code] = ev.value;
|
||||
}
|
||||
fake_key = 0;
|
||||
const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
|
||||
if (ev.value > 0 && key_queue_len < queue_max) {
|
||||
key_queue[key_queue_len++] = ev.code;
|
||||
|
@ -242,9 +308,10 @@ static void *input_thread(void *cookie)
|
|||
}
|
||||
pthread_mutex_unlock(&key_queue_mutex);
|
||||
|
||||
// Alt+L: toggle log display
|
||||
// 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) {
|
||||
if ((alt && ev.code == KEY_L && ev.value > 0) ||
|
||||
(key_pressed[KEY_HOME] && ev.code == KEY_END && ev.value > 0)) {
|
||||
pthread_mutex_lock(&gUpdateMutex);
|
||||
show_text = !show_text;
|
||||
update_screen_locked();
|
||||
|
@ -269,6 +336,7 @@ void ui_init(void)
|
|||
text_col = text_row = 0;
|
||||
text_rows = gr_fb_height() / CHAR_HEIGHT;
|
||||
if (text_rows > MAX_ROWS) text_rows = MAX_ROWS;
|
||||
text_top = 1;
|
||||
|
||||
text_cols = gr_fb_width() / CHAR_WIDTH;
|
||||
if (text_cols > MAX_COLS - 1) text_cols = MAX_COLS - 1;
|
||||
|
@ -392,6 +460,54 @@ void ui_print(const char *fmt, ...)
|
|||
pthread_mutex_unlock(&gUpdateMutex);
|
||||
}
|
||||
|
||||
void ui_start_menu(char** headers, char** items) {
|
||||
int i;
|
||||
pthread_mutex_lock(&gUpdateMutex);
|
||||
if (text_rows > 0 && text_cols > 0) {
|
||||
for (i = 0; i < text_rows; ++i) {
|
||||
if (headers[i] == NULL) break;
|
||||
strncpy(menu[i], headers[i], text_cols-1);
|
||||
menu[i][text_cols-1] = '\0';
|
||||
}
|
||||
menu_top = i;
|
||||
for (; i < text_rows; ++i) {
|
||||
if (items[i-menu_top] == NULL) break;
|
||||
strncpy(menu[i], items[i-menu_top], text_cols-1);
|
||||
menu[i][text_cols-1] = '\0';
|
||||
}
|
||||
menu_items = i - menu_top;
|
||||
show_menu = 1;
|
||||
menu_sel = 0;
|
||||
update_screen_locked();
|
||||
}
|
||||
pthread_mutex_unlock(&gUpdateMutex);
|
||||
}
|
||||
|
||||
int ui_menu_select(int sel) {
|
||||
int old_sel;
|
||||
pthread_mutex_lock(&gUpdateMutex);
|
||||
if (show_menu > 0) {
|
||||
old_sel = menu_sel;
|
||||
menu_sel = sel;
|
||||
if (menu_sel < 0) menu_sel = 0;
|
||||
if (menu_sel >= menu_items) menu_sel = menu_items-1;
|
||||
sel = menu_sel;
|
||||
if (menu_sel != old_sel) update_screen_locked();
|
||||
}
|
||||
pthread_mutex_unlock(&gUpdateMutex);
|
||||
return sel;
|
||||
}
|
||||
|
||||
void ui_end_menu() {
|
||||
int i;
|
||||
pthread_mutex_lock(&gUpdateMutex);
|
||||
if (show_menu > 0 && text_rows > 0 && text_cols > 0) {
|
||||
show_menu = 0;
|
||||
update_screen_locked();
|
||||
}
|
||||
pthread_mutex_unlock(&gUpdateMutex);
|
||||
}
|
||||
|
||||
int ui_text_visible()
|
||||
{
|
||||
pthread_mutex_lock(&gUpdateMutex);
|
||||
|
@ -418,3 +534,9 @@ int ui_key_pressed(int key)
|
|||
// This is a volatile static array, don't bother locking
|
||||
return key_pressed[key];
|
||||
}
|
||||
|
||||
void ui_clear_key_queue() {
|
||||
pthread_mutex_lock(&key_queue_mutex);
|
||||
key_queue_len = 0;
|
||||
pthread_mutex_unlock(&key_queue_mutex);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue