Commit 32a0a47a authored by Doug Zongker's avatar Doug Zongker
Browse files

move key processing to RecoveryUI

Move the key for handling keys from ScreenRecoveryUI to RecoveryUI, so
it can be used by devices without screens.  Remove the UIParameters
struct and replace it with some new member variables in
ScreenRecoveryUI.

Change-Id: I70094ecbc4acbf76ce44d5b5ec2036c36bdc3414
parent daefc1d4
master brillo-m10-dev brillo-m10-release brillo-m7-dev brillo-m7-mr-dev brillo-m7-release brillo-m8-dev brillo-m8-release brillo-m9-dev brillo-m9-release halo-5.1.1_r33 halo-dev halo-rk312x-5.1.0_r5 idea133 idea133-weekly-release jb-dev jb-mr0-release jb-mr1-dev jb-mr1-dev-plus-aosp jb-mr1-release jb-mr1.1-dev jb-mr1.1-dev-plus-aosp jb-mr1.1-release jb-mr2-dev jb-mr2-release jb-mr2.0-release jb-mr2.0.0-release jb-release kitkat-cts-dev kitkat-cts-release kitkat-dev kitkat-mr1-release kitkat-mr1.1-release kitkat-mr2-release kitkat-mr2.1-release kitkat-mr2.2-release kitkat-release kitkat-wear l-preview lollipop-cts-release lollipop-dev lollipop-mr1-cts-release lollipop-mr1-dev lollipop-mr1-fi-release lollipop-mr1-release lollipop-mr1-wfc-release lollipop-release lollipop-wear-release marshmallow-cts-release marshmallow-dev marshmallow-dr-dev marshmallow-dr-dragon-release marshmallow-dr-release marshmallow-dr1.5-dev marshmallow-dr1.5-release marshmallow-dr1.6-release marshmallow-mr1-dev marshmallow-mr1-release marshmallow-mr2-release marshmallow-mr3-release marshmallow-release master-soong nougat-cts-release nougat-dev nougat-dr1-release nougat-mr0.5-release nougat-mr1-dev nougat-mr1-release nougat-mr1.1-release nougat-mr1.2-release nougat-release rockchip-5.1.0_r5 rockchip-6.0.1_r55 sdk-release spartan-1.0.0_r1 tools_r21 tools_r22 tools_r22.2 android-wear-n-preview-2 android-wear-n-preview-1 android-wear-5.1.1_r1 android-wear-5.1.0_r1 android-wear-5.0.0_r1 android-sdk-support_r11 android-sdk-4.4.2_r1.0.1 android-sdk-4.4.2_r1 android-n-preview-5 android-n-preview-4 android-n-preview-3 android-n-preview-2 android-n-preview-1 android-n-mr1-preview-2 android-n-mr1-preview-1 android-m-preview android-m-preview-2 android-m-preview-1 android-l-preview_r2 android-cts-7.1_r1 android-cts-7.0_r5 android-cts-7.0_r4 android-cts-7.0_r3 android-cts-7.0_r2 android-cts-7.0_r1 android-cts-6.0_r14 android-cts-6.0_r13 android-cts-6.0_r12 android-cts-6.0_r9 android-cts-6.0_r8 android-cts-6.0_r7 android-cts-6.0_r6 android-cts-6.0_r5 android-cts-6.0_r4 android-cts-6.0_r3 android-cts-6.0_r2 android-cts-6.0_r1 android-cts-5.1_r15 android-cts-5.1_r14 android-cts-5.1_r13 android-cts-5.1_r10 android-cts-5.1_r9 android-cts-5.1_r8 android-cts-5.1_r7 android-cts-5.1_r6 android-cts-5.1_r5 android-cts-5.1_r4 android-cts-5.1_r3 android-cts-5.1_r2 android-cts-5.1_r1 android-cts-5.0_r9 android-cts-5.0_r8 android-cts-5.0_r7 android-cts-5.0_r6 android-cts-5.0_r5 android-cts-5.0_r4 android-cts-5.0_r3 android-cts-4.4_r4 android-cts-4.4_r1 android-cts-4.2_r2 android-cts-4.2_r1 android-cts-4.1_r4 android-cts-4.1_r2 android-cts-4.1_r1 android-7.1.1_r13 android-7.1.1_r12 android-7.1.1_r11 android-7.1.1_r10 android-7.1.1_r9 android-7.1.1_r8 android-7.1.1_r7 android-7.1.1_r6 android-7.1.1_r4 android-7.1.1_r3 android-7.1.1_r2 android-7.1.1_r1 android-7.1.0_r7 android-7.1.0_r6 android-7.1.0_r5 android-7.1.0_r4 android-7.1.0_r3 android-7.1.0_r2 android-7.1.0_r1 android-7.0.0_r27 android-7.0.0_r24 android-7.0.0_r21 android-7.0.0_r19 android-7.0.0_r17 android-7.0.0_r15 android-7.0.0_r14 android-7.0.0_r13 android-7.0.0_r12 android-7.0.0_r7 android-7.0.0_r6 android-7.0.0_r5 android-7.0.0_r4 android-7.0.0_r3 android-7.0.0_r1 android-6.0.1_r77 android-6.0.1_r74 android-6.0.1_r73 android-6.0.1_r72 android-6.0.1_r70 android-6.0.1_r69 android-6.0.1_r68 android-6.0.1_r67 android-6.0.1_r66 android-6.0.1_r65 android-6.0.1_r63 android-6.0.1_r62 android-6.0.1_r61 android-6.0.1_r60 android-6.0.1_r59 android-6.0.1_r58 android-6.0.1_r57 android-6.0.1_r56 android-6.0.1_r55 android-6.0.1_r54 android-6.0.1_r53 android-6.0.1_r52 android-6.0.1_r51 android-6.0.1_r50 android-6.0.1_r49 android-6.0.1_r48 android-6.0.1_r47 android-6.0.1_r46 android-6.0.1_r45 android-6.0.1_r43 android-6.0.1_r42 android-6.0.1_r41 android-6.0.1_r40 android-6.0.1_r33 android-6.0.1_r32 android-6.0.1_r31 android-6.0.1_r30 android-6.0.1_r28 android-6.0.1_r27 android-6.0.1_r26 android-6.0.1_r25 android-6.0.1_r24 android-6.0.1_r22 android-6.0.1_r21 android-6.0.1_r20 android-6.0.1_r18 android-6.0.1_r17 android-6.0.1_r16 android-6.0.1_r13 android-6.0.1_r12 android-6.0.1_r11 android-6.0.1_r10 android-6.0.1_r9 android-6.0.1_r8 android-6.0.1_r7 android-6.0.1_r5 android-6.0.1_r4 android-6.0.1_r3 android-6.0.1_r1 android-6.0.0_r41 android-6.0.0_r26 android-6.0.0_r25 android-6.0.0_r24 android-6.0.0_r23 android-6.0.0_r13 android-6.0.0_r12 android-6.0.0_r11 android-6.0.0_r7 android-6.0.0_r6 android-6.0.0_r5 android-6.0.0_r4 android-6.0.0_r3 android-6.0.0_r2 android-6.0.0_r1 android-5.1.1_r38 android-5.1.1_r37 android-5.1.1_r36 android-5.1.1_r35 android-5.1.1_r34 android-5.1.1_r33 android-5.1.1_r30 android-5.1.1_r29 android-5.1.1_r28 android-5.1.1_r26 android-5.1.1_r25 android-5.1.1_r24 android-5.1.1_r23 android-5.1.1_r22 android-5.1.1_r20 android-5.1.1_r19 android-5.1.1_r18 android-5.1.1_r17 android-5.1.1_r16 android-5.1.1_r15 android-5.1.1_r14 android-5.1.1_r13 android-5.1.1_r12 android-5.1.1_r10 android-5.1.1_r9 android-5.1.1_r8 android-5.1.1_r7 android-5.1.1_r6 android-5.1.1_r5 android-5.1.1_r4 android-5.1.1_r3 android-5.1.1_r2 android-5.1.1_r1 android-5.1.0_r5 android-5.1.0_r4 android-5.1.0_r3 android-5.1.0_r1 android-5.0.2_r3 android-5.0.2_r1 android-5.0.1_r1 android-5.0.0_r7 android-5.0.0_r6 android-5.0.0_r5.1 android-5.0.0_r5 android-5.0.0_r4 android-5.0.0_r3 android-5.0.0_r2 android-5.0.0_r1 android-4.4.4_r2.0.1 android-4.4.4_r2 android-4.4.4_r1.0.1 android-4.4.4_r1 android-4.4.3_r1.1.0.1 android-4.4.3_r1.1 android-4.4.3_r1.0.1 android-4.4.3_r1 android-4.4.2_r2.0.1 android-4.4.2_r2 android-4.4.2_r1.0.1 android-4.4.2_r1 android-4.4.1_r1.0.1 android-4.4.1_r1 android-4.4w_r1 android-4.4_r1.2.0.1 android-4.4_r1.2 android-4.4_r1.1.0.1 android-4.4_r1.1 android-4.4_r1.0.1 android-4.4_r1 android-4.4_r0.9 android-4.4_r0.8 android-4.4_r0.7 android-4.3.1_r1 android-4.3_r3.1 android-4.3_r3 android-4.3_r2.3 android-4.3_r2.2 android-4.3_r2.1 android-4.3_r2 android-4.3_r1.1 android-4.3_r1 android-4.3_r0.9.1 android-4.3_r0.9 android-4.2.2_r1.2 android-4.2.2_r1.1 android-4.2.2_r1 android-4.2.1_r1.2 android-4.2.1_r1.1 android-4.2.1_r1 android-4.2_r1 android-4.1.2_r2.1 android-4.1.2_r2 android-4.1.2_r1 android-4.1.1_r6.1 android-4.1.1_r6 android-4.1.1_r5 android-4.1.1_r4 android-4.1.1_r3 android-4.1.1_r2 android-4.1.1_r1.1 android-4.1.1_r1
No related merge requests found
......@@ -8,6 +8,7 @@ LOCAL_SRC_FILES := \
bootloader.cpp \
install.cpp \
roots.cpp \
ui.cpp \
screen_ui.cpp \
verifier.cpp
......@@ -50,7 +51,7 @@ include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := verifier_test.cpp verifier.cpp
LOCAL_SRC_FILES := verifier_test.cpp verifier.cpp ui.cpp
LOCAL_MODULE := verifier_test
......@@ -58,7 +59,7 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_TAGS := tests
LOCAL_STATIC_LIBRARIES := libmincrypt libcutils libstdc++ libc
LOCAL_STATIC_LIBRARIES := libmincrypt libminui libcutils libstdc++ libc
include $(BUILD_EXECUTABLE)
......
......@@ -58,25 +58,6 @@ typedef struct {
// (that much).
} Volume;
typedef struct {
// number of frames in indeterminate progress bar animation
int indeterminate_frames;
// number of frames per second to try to maintain when animating
int update_fps;
// number of frames in installing animation. may be zero for a
// static installation icon.
int installing_frames;
// the install icon is animated by drawing images containing the
// changing part over the base icon. These specify the
// coordinates of the upper-left corner.
int install_overlay_offset_x;
int install_overlay_offset_y;
} UIParameters;
// fopen a file, mounting volumes and making parent dirs as necessary.
FILE* fopen_path(const char *path, const char *mode);
......
......@@ -61,8 +61,6 @@ static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";
extern UIParameters ui_parameters; // from ui.c
RecoveryUI* ui = NULL;
/*
......@@ -745,7 +743,7 @@ main(int argc, char **argv) {
ui = device->GetUI();
ui->Init();
ui->SetBackground(RecoveryUI::INSTALLING);
ui->SetBackground(RecoveryUI::NONE);
load_volume_table();
get_args(&argc, &argv);
......
......@@ -29,24 +29,14 @@
#include <unistd.h>
#include "common.h"
#include <cutils/android_reboot.h>
#include "device.h"
#include "minui/minui.h"
#include "ui.h"
#include "screen_ui.h"
#include "device.h"
#include "ui.h"
#define CHAR_WIDTH 10
#define CHAR_HEIGHT 18
#define UI_WAIT_KEY_TIMEOUT_SEC 120
UIParameters ui_parameters = {
6, // indeterminate progress bar frames
20, // fps
7, // installation icon frames (0 == static image)
13, 190, // installation icon overlay offset
};
// There's only (at most) one of these objects, and global callbacks
// (for pthread_create, and the input event system) need to find it,
// so use a global variable.
......@@ -78,11 +68,18 @@ ScreenRecoveryUI::ScreenRecoveryUI() :
menu_top(0),
menu_items(0),
menu_sel(0),
key_queue_len(0),
key_last_down(-1) {
// These values are correct for the default image resources
// provided with the android platform. Devices which use
// different resources should have a subclass of ScreenRecoveryUI
// that overrides Init() to set these values appropriately and
// then call the superclass Init().
animation_fps(20),
indeterminate_frames(6),
installing_frames(7),
install_overlay_offset_x(13),
install_overlay_offset_y(190) {
pthread_mutex_init(&updateMutex, NULL);
pthread_mutex_init(&key_queue_mutex, NULL);
pthread_cond_init(&key_queue_cond, NULL);
self = this;
}
......@@ -97,8 +94,7 @@ void ScreenRecoveryUI::draw_install_overlay_locked(int frame) {
int iconWidth = gr_get_width(surface);
int iconHeight = gr_get_height(surface);
gr_blit(surface, 0, 0, iconWidth, iconHeight,
ui_parameters.install_overlay_offset_x,
ui_parameters.install_overlay_offset_y);
install_overlay_offset_x, install_overlay_offset_y);
}
// Clear the screen and draw the currently selected background icon (if any).
......@@ -157,7 +153,7 @@ void ScreenRecoveryUI::draw_progress_locked()
if (progressBarType == INDETERMINATE) {
static int frame = 0;
gr_blit(progressBarIndeterminate[frame], 0, 0, width, height, dx, dy);
frame = (frame + 1) % ui_parameters.indeterminate_frames;
frame = (frame + 1) % indeterminate_frames;
}
}
}
......@@ -229,35 +225,36 @@ void ScreenRecoveryUI::update_progress_locked()
}
// Keeps the progress bar updated, even when the process is otherwise busy.
void* ScreenRecoveryUI::progress_thread(void *cookie)
{
double interval = 1.0 / ui_parameters.update_fps;
void* ScreenRecoveryUI::progress_thread(void *cookie) {
self->progress_loop();
return NULL;
}
void ScreenRecoveryUI::progress_loop() {
double interval = 1.0 / animation_fps;
for (;;) {
double start = now();
pthread_mutex_lock(&self->updateMutex);
pthread_mutex_lock(&updateMutex);
int redraw = 0;
// update the installation animation, if active
// skip this if we have a text overlay (too expensive to update)
if (self->currentIcon == INSTALLING &&
ui_parameters.installing_frames > 0 &&
!self->show_text) {
self->installingFrame =
(self->installingFrame + 1) % ui_parameters.installing_frames;
if (currentIcon == INSTALLING && installing_frames > 0 && !show_text) {
installingFrame = (installingFrame + 1) % installing_frames;
redraw = 1;
}
// update the progress bar animation, if active
// skip this if we have a text overlay (too expensive to update)
if (self->progressBarType == INDETERMINATE && !self->show_text) {
if (progressBarType == INDETERMINATE && !show_text) {
redraw = 1;
}
// move the progress bar forward on timed intervals, if configured
int duration = self->progressScopeDuration;
if (self->progressBarType == DETERMINATE && duration > 0) {
double elapsed = now() - self->progressScopeTime;
int duration = progressScopeDuration;
if (progressBarType == DETERMINATE && duration > 0) {
double elapsed = now() - progressScopeTime;
float progress = 1.0 * elapsed / duration;
if (progress > 1.0) progress = 1.0;
if (progress > progress) {
......@@ -266,117 +263,15 @@ void* ScreenRecoveryUI::progress_thread(void *cookie)
}
}
if (redraw) self->update_progress_locked();
if (redraw) update_progress_locked();
pthread_mutex_unlock(&self->updateMutex);
pthread_mutex_unlock(&updateMutex);
double end = now();
// minimum of 20ms delay between frames
double delay = interval - (end-start);
if (delay < 0.02) delay = 0.02;
usleep((long)(delay * 1000000));
}
return NULL;
}
int ScreenRecoveryUI::input_callback(int fd, short revents, void* data)
{
struct input_event ev;
int ret;
ret = ev_get_input(fd, revents, &ev);
if (ret)
return -1;
if (ev.type == EV_SYN) {
return 0;
} 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.
self->rel_sum += ev.value;
if (self->rel_sum > 3) {
self->process_key(KEY_DOWN, 1); // press down key
self->process_key(KEY_DOWN, 0); // and release it
self->rel_sum = 0;
} else if (self->rel_sum < -3) {
self->process_key(KEY_UP, 1); // press up key
self->process_key(KEY_UP, 0); // and release it
self->rel_sum = 0;
}
}
} else {
self->rel_sum = 0;
}
if (ev.type == EV_KEY && ev.code <= KEY_MAX)
self->process_key(ev.code, ev.value);
return 0;
}
// Process a key-up or -down event. A key is "registered" when it is
// pressed and then released, with no other keypresses or releases in
// between. Registered keys are passed to CheckKey() to see if it
// should trigger a visibility toggle, an immediate reboot, or be
// queued to be processed next time the foreground thread wants a key
// (eg, for the menu).
//
// We also keep track of which keys are currently down so that
// CheckKey can call IsKeyPressed to see what other keys are held when
// a key is registered.
//
// updown == 1 for key down events; 0 for key up events
void ScreenRecoveryUI::process_key(int key_code, int updown) {
bool register_key = false;
pthread_mutex_lock(&key_queue_mutex);
key_pressed[key_code] = updown;
if (updown) {
key_last_down = key_code;
} else {
if (key_last_down == key_code)
register_key = true;
key_last_down = -1;
}
pthread_mutex_unlock(&key_queue_mutex);
if (register_key) {
switch (CheckKey(key_code)) {
case RecoveryUI::TOGGLE:
pthread_mutex_lock(&updateMutex);
show_text = !show_text;
if (show_text) show_text_ever = true;
update_screen_locked();
pthread_mutex_unlock(&updateMutex);
break;
case RecoveryUI::REBOOT:
android_reboot(ANDROID_RB_RESTART, 0, 0);
break;
case RecoveryUI::ENQUEUE:
pthread_mutex_lock(&key_queue_mutex);
const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
if (key_queue_len < queue_max) {
key_queue[key_queue_len++] = key_code;
pthread_cond_signal(&key_queue_cond);
}
pthread_mutex_unlock(&key_queue_mutex);
break;
}
}
}
// Reads input events, handles special hot keys, and adds to the key queue.
void* ScreenRecoveryUI::input_thread(void *cookie)
{
for (;;) {
if (!ev_wait(-1))
ev_dispatch();
}
return NULL;
}
void ScreenRecoveryUI::LoadBitmap(const char* filename, gr_surface* surface) {
......@@ -389,7 +284,6 @@ void ScreenRecoveryUI::LoadBitmap(const char* filename, gr_surface* surface) {
void ScreenRecoveryUI::Init()
{
gr_init();
ev_init(input_callback, NULL);
text_col = text_row = 0;
text_rows = gr_fb_height() / CHAR_HEIGHT;
......@@ -406,19 +300,19 @@ void ScreenRecoveryUI::Init()
int i;
progressBarIndeterminate = (gr_surface*)malloc(ui_parameters.indeterminate_frames *
progressBarIndeterminate = (gr_surface*)malloc(indeterminate_frames *
sizeof(gr_surface));
for (i = 0; i < ui_parameters.indeterminate_frames; ++i) {
for (i = 0; i < indeterminate_frames; ++i) {
char filename[40];
// "indeterminate01.png", "indeterminate02.png", ...
sprintf(filename, "indeterminate%02d", i+1);
LoadBitmap(filename, progressBarIndeterminate+i);
}
if (ui_parameters.installing_frames > 0) {
installationOverlay = (gr_surface*)malloc(ui_parameters.installing_frames *
if (installing_frames > 0) {
installationOverlay = (gr_surface*)malloc(installing_frames *
sizeof(gr_surface));
for (i = 0; i < ui_parameters.installing_frames; ++i) {
for (i = 0; i < installing_frames; ++i) {
char filename[40];
// "icon_installing_overlay01.png",
// "icon_installing_overlay02.png", ...
......@@ -430,17 +324,16 @@ void ScreenRecoveryUI::Init()
// base image on the screen.
if (backgroundIcon[INSTALLING] != NULL) {
gr_surface bg = backgroundIcon[INSTALLING];
ui_parameters.install_overlay_offset_x +=
(gr_fb_width() - gr_get_width(bg)) / 2;
ui_parameters.install_overlay_offset_y +=
(gr_fb_height() - gr_get_height(bg)) / 2;
install_overlay_offset_x += (gr_fb_width() - gr_get_width(bg)) / 2;
install_overlay_offset_y += (gr_fb_height() - gr_get_height(bg)) / 2;
}
} else {
installationOverlay = NULL;
}
pthread_create(&progress_t, NULL, progress_thread, NULL);
pthread_create(&input_t, NULL, input_thread, NULL);
RecoveryUI::Init();
}
void ScreenRecoveryUI::SetBackground(Icon icon)
......@@ -593,70 +486,3 @@ void ScreenRecoveryUI::ShowText(bool visible)
update_screen_locked();
pthread_mutex_unlock(&updateMutex);
}
// Return true if USB is connected.
bool ScreenRecoveryUI::usb_connected() {
int fd = open("/sys/class/android_usb/android0/state", O_RDONLY);
if (fd < 0) {
printf("failed to open /sys/class/android_usb/android0/state: %s\n",
strerror(errno));
return 0;
}
char buf;
/* USB is connected if android_usb state is CONNECTED or CONFIGURED */
int connected = (read(fd, &buf, 1) == 1) && (buf == 'C');
if (close(fd) < 0) {
printf("failed to close /sys/class/android_usb/android0/state: %s\n",
strerror(errno));
}
return connected;
}
int ScreenRecoveryUI::WaitKey()
{
pthread_mutex_lock(&key_queue_mutex);
// Time out after UI_WAIT_KEY_TIMEOUT_SEC, unless a USB cable is
// plugged in.
do {
struct timeval now;
struct timespec timeout;
gettimeofday(&now, NULL);
timeout.tv_sec = now.tv_sec;
timeout.tv_nsec = now.tv_usec * 1000;
timeout.tv_sec += UI_WAIT_KEY_TIMEOUT_SEC;
int rc = 0;
while (key_queue_len == 0 && rc != ETIMEDOUT) {
rc = pthread_cond_timedwait(&key_queue_cond, &key_queue_mutex,
&timeout);
}
} while (usb_connected() && key_queue_len == 0);
int key = -1;
if (key_queue_len > 0) {
key = key_queue[0];
memcpy(&key_queue[0], &key_queue[1], sizeof(int) * --key_queue_len);
}
pthread_mutex_unlock(&key_queue_mutex);
return key;
}
bool ScreenRecoveryUI::IsKeyPressed(int key)
{
pthread_mutex_lock(&key_queue_mutex);
int pressed = key_pressed[key];
pthread_mutex_unlock(&key_queue_mutex);
return pressed;
}
void ScreenRecoveryUI::FlushKeys() {
pthread_mutex_lock(&key_queue_mutex);
key_queue_len = 0;
pthread_mutex_unlock(&key_queue_mutex);
}
RecoveryUI::KeyAction ScreenRecoveryUI::CheckKey(int key) {
return RecoveryUI::ENQUEUE;
}
......@@ -43,15 +43,6 @@ class ScreenRecoveryUI : public RecoveryUI {
bool IsTextVisible();
bool WasTextEverVisible();
// key handling
int WaitKey();
bool IsKeyPressed(int key);
void FlushKeys();
// The default implementation of CheckKey enqueues all keys.
// Devices should typically override this to provide some way to
// toggle the log/menu display, and to do an immediate reboot.
KeyAction CheckKey(int key);
// printing messages
void Print(const char* fmt, ...); // __attribute__((format(printf, 1, 2)));
......@@ -95,16 +86,12 @@ class ScreenRecoveryUI : public RecoveryUI {
bool show_menu;
int menu_top, menu_items, menu_sel;
// Key event input queue
pthread_mutex_t key_queue_mutex;
pthread_cond_t key_queue_cond;
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
int rel_sum;
pthread_t progress_t;
pthread_t input_t;
int animation_fps;
int indeterminate_frames;
int installing_frames;
int install_overlay_offset_x, install_overlay_offset_y;
void draw_install_overlay_locked(int frame);
void draw_background_locked(Icon icon);
......@@ -114,11 +101,7 @@ class ScreenRecoveryUI : public RecoveryUI {
void update_screen_locked();
void update_progress_locked();
static void* progress_thread(void* cookie);
static int input_callback(int fd, short revents, void* data);
void process_key(int key_code, int updown);
static void* input_thread(void* cookie);
bool usb_connected();
void progress_loop();
void LoadBitmap(const char* filename, gr_surface* surface);
......
/*
* Copyright (C) 2011 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 <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <pthread.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <cutils/android_reboot.h>
#include "common.h"
#include "device.h"
#include "minui/minui.h"
#include "screen_ui.h"
#include "ui.h"
#define UI_WAIT_KEY_TIMEOUT_SEC 120
// There's only (at most) one of these objects, and global callbacks
// (for pthread_create, and the input event system) need to find it,
// so use a global variable.
static RecoveryUI* self = NULL;
RecoveryUI::RecoveryUI() :
key_queue_len(0),
key_last_down(-1) {
pthread_mutex_init(&key_queue_mutex, NULL);
pthread_cond_init(&key_queue_cond, NULL);
self = this;
}
void RecoveryUI::Init() {
ev_init(input_callback, NULL);
pthread_create(&input_t, NULL, input_thread, NULL);
}
int RecoveryUI::input_callback(int fd, short revents, void* data)
{
struct input_event ev;
int ret;
ret = ev_get_input(fd, revents, &ev);
if (ret)
return -1;
if (ev.type == EV_SYN) {
return 0;
} 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.
self->rel_sum += ev.value;
if (self->rel_sum > 3) {
self->process_key(KEY_DOWN, 1); // press down key
self->process_key(KEY_DOWN, 0); // and release it
self->rel_sum = 0;
} else if (self->rel_sum < -3) {
self->process_key(KEY_UP, 1); // press up key
self->process_key(KEY_UP, 0); // and release it
self->rel_sum = 0;
}
}
} else {
self->rel_sum = 0;
}
if (ev.type == EV_KEY && ev.code <= KEY_MAX)
self->process_key(ev.code, ev.value);
return 0;
}
// Process a key-up or -down event. A key is "registered" when it is
// pressed and then released, with no other keypresses or releases in
// between. Registered keys are passed to CheckKey() to see if it
// should trigger a visibility toggle, an immediate reboot, or be
// queued to be processed next time the foreground thread wants a key
// (eg, for the menu).
//
// We also keep track of which keys are currently down so that
// CheckKey can call IsKeyPressed to see what other keys are held when
// a key is registered.
//
// updown == 1 for key down events; 0 for key up events
void RecoveryUI::process_key(int key_code, int updown) {
bool register_key = false;
pthread_mutex_lock(&key_queue_mutex);
key_pressed[key_code] = updown;
if (updown) {
key_last_down = key_code;
} else {
if (key_last_down == key_code)
register_key = true;
key_last_down = -1;
}
pthread_mutex_unlock(&key_queue_mutex);
if (register_key) {
switch (CheckKey(key_code)) {
case RecoveryUI::TOGGLE:
ShowText(!IsTextVisible());
break;
case RecoveryUI::REBOOT:
android_reboot(ANDROID_RB_RESTART, 0, 0);
break;
case RecoveryUI::ENQUEUE:
pthread_mutex_lock(&key_queue_mutex);
const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
if (key_queue_len < queue_max) {
key_queue[key_queue_len++] = key_code;
pthread_cond_signal(&key_queue_cond);
}
pthread_mutex_unlock(&key_queue_mutex);
break;
}
}
}
// Reads input events, handles special hot keys, and adds to the key queue.
void* RecoveryUI::input_thread(void *cookie)
{
for (;;) {
if (!ev_wait(-1))
ev_dispatch();
}
return NULL;
}
int RecoveryUI::WaitKey()
{
pthread_mutex_lock(&key_queue_mutex);
// Time out after UI_WAIT_KEY_TIMEOUT_SEC, unless a USB cable is
// plugged in.
do {
struct timeval now;
struct timespec timeout;
gettimeofday(&now, NULL);
timeout.tv_sec = now.tv_sec;
timeout.tv_nsec = now.tv_usec * 1000;
timeout.tv_sec += UI_WAIT_KEY_TIMEOUT_SEC;
int rc = 0;
while (key_queue_len == 0 && rc != ETIMEDOUT) {
rc = pthread_cond_timedwait(&key_queue_cond, &key_queue_mutex,
&timeout);
}
} while (usb_connected() && key_queue_len == 0);
int key = -1;
if (key_queue_len > 0) {
key = key_queue[0];
memcpy(&key_queue[0], &key_queue[1], sizeof(int) * --key_queue_len);
}
pthread_mutex_unlock(&key_queue_mutex);
return key;
}
// Return true if USB is connected.
bool RecoveryUI::usb_connected() {
int fd = open("/sys/class/android_usb/android0/state", O_RDONLY);
if (fd < 0) {
printf("failed to open /sys/class/android_usb/android0/state: %s\n",
strerror(errno));
return 0;
}
char buf;
/* USB is connected if android_usb state is CONNECTED or CONFIGURED */
int connected = (read(fd, &buf, 1) == 1) && (buf == 'C');
if (close(fd) < 0) {
printf("failed to close /sys/class/android_usb/android0/state: %s\n",
strerror(errno));
}
return connected;
}
bool RecoveryUI::IsKeyPressed(int key)
{
pthread_mutex_lock(&key_queue_mutex);
int pressed = key_pressed[key];
pthread_mutex_unlock(&key_queue_mutex);
return pressed;
}
void RecoveryUI::FlushKeys() {
pthread_mutex_lock(&key_queue_mutex);
key_queue_len = 0;
pthread_mutex_unlock(&key_queue_mutex);
}
RecoveryUI::KeyAction RecoveryUI::CheckKey(int key) {
return RecoveryUI::ENQUEUE;
}
......@@ -17,13 +17,18 @@
#ifndef RECOVERY_UI_H
#define RECOVERY_UI_H
#include <linux/input.h>
#include <pthread.h>
// Abstract class for controlling the user interface during recovery.
class RecoveryUI {
public:
RecoveryUI();
virtual ~RecoveryUI() { }
// Initialize the object; called before anything else.
virtual void Init() = 0;
virtual void Init();
// Set the overall recovery state ("background image").
enum Icon { NONE, INSTALLING, ERROR };
......@@ -57,19 +62,19 @@ class RecoveryUI {
// --- key handling ---
// Wait for keypress and return it. May return -1 after timeout.
virtual int WaitKey() = 0;
virtual int WaitKey();
virtual bool IsKeyPressed(int key) = 0;
virtual bool IsKeyPressed(int key);
// Erase any queued-up keys.
virtual void FlushKeys() = 0;
virtual void FlushKeys();
// Called on each keypress, even while operations are in progress.
// Return value indicates whether an immediate operation should be
// triggered (toggling the display, rebooting the device), or if
// the key should be enqueued for use by the main thread.
enum KeyAction { ENQUEUE, TOGGLE, REBOOT };
virtual KeyAction CheckKey(int key) = 0;
virtual KeyAction CheckKey(int key);
// --- menu display ---
......@@ -86,6 +91,22 @@ class RecoveryUI {
// End menu mode, resetting the text overlay so that ui_print()
// statements will be displayed.
virtual void EndMenu() = 0;
private:
// Key event input queue
pthread_mutex_t key_queue_mutex;
pthread_cond_t key_queue_cond;
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
int rel_sum;
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();
};
#endif // RECOVERY_UI_H
......@@ -84,11 +84,6 @@ class FakeUI : public RecoveryUI {
fputs(buf, stderr);
}
int WaitKey() { return 0; }
bool IsKeyPressed(int key) { return false; }
void FlushKeys() { }
KeyAction CheckKey(int key) { return ENQUEUE; }
void StartMenu(const char* const * headers, const char* const * items,
int initial_selection) { }
int SelectMenu(int sel) { return 0; }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment