// Clear the screen and draw the currently selected background icon (if any). // Should only be called with updateMutex locked. voidScreenRecoveryUI::draw_background_locked(){ pagesIdentical = false; gr_color(0, 0, 0, 255); gr_clear(); if (current_icon_ != NONE) { if (max_stage != -1) { int stage_height = gr_get_height(stage_marker_empty_.get()); int stage_width = gr_get_width(stage_marker_empty_.get()); int x = (ScreenWidth() - max_stage * gr_get_width(stage_marker_empty_.get())) / 2; int y = ScreenHeight() - stage_height - margin_height_; for (int i = 0; i < max_stage; ++i) { constauto& stage_surface = (i < stage) ? stage_marker_fill_ : stage_marker_empty_; DrawSurface(stage_surface.get(), 0, 0, stage_width, stage_height, x, y); x += stage_width; } }
// Draws the animation and progress bar (if any) on the screen. Does not flip pages. Should only be // called with updateMutex locked. voidScreenRecoveryUI::draw_foreground_locked(){ if (current_icon_ != NONE) { constauto& frame = GetCurrentFrame(); int frame_width = gr_get_width(frame); int frame_height = gr_get_height(frame); int frame_x = (ScreenWidth() - frame_width) / 2; int frame_y = GetAnimationBaseline(); DrawSurface(frame, 0, 0, frame_width, frame_height, frame_x, frame_y); }
有没有发现一个是foreground,一个是background。继续看:
// Redraws everything on the screen. Does not flip pages. Should only be called with updateMutex // locked. voidScreenRecoveryUI::draw_screen_locked(){ if (!show_text) { draw_background_locked(); draw_foreground_locked(); return; }
int arg; int option_index; while ((arg = getopt_long(args_to_parse.size() - 1, args_to_parse.data(), "", OPTIONS, &option_index)) != -1) { switch (arg) { case't': show_text = true; break;
最终会走到start_recovery(),同样这里just_exit也是默认false。
Device::BuiltinAction start_recovery(Device* device, const std::vector<std::string>& args){ staticconstexprstructoption OPTIONS[] = { ... } elseif (!just_exit) { // If this is an eng or userdebug build, automatically turn on the text display if no command // is specified. Note that this should be called before setting the background to avoid // flickering the background image. if (is_ro_debuggable()) { ui->ShowText(true); } status = INSTALL_NONE; // No command specified ui->SetBackground(RecoveryUI::NO_COMMAND); }
注意了,只要是eng or userdebug版本,就直接call ->ShowText也就是show menu了。所以原生user版本才会出现小机器人。
// Determine the next action. // - If the state is INSTALL_REBOOT, device will reboot into the target as specified in // `next_action`. // - If the recovery menu is visible, prompt and wait for commands. // - If the state is INSTALL_NONE, wait for commands (e.g. in user build, one manually boots // into recovery to sideload a package or to wipe the device). // - In all other cases, reboot the device. Therefore, normal users will observe the device // rebooting a) immediately upon successful finish (INSTALL_SUCCESS); or b) an "error" screen // for 5s followed by an automatic reboot. if (status != INSTALL_REBOOT) { if (status == INSTALL_NONE || ui->IsTextVisible()) { Device::BuiltinAction temp = prompt_and_wait(device, status); if (temp != Device::NO_ACTION) { next_action = temp; } } }
intRecoveryUI::OnInputEvent(int fd, uint32_t epevents){ structinput_event ev; if (ev_get_input(fd, epevents, &ev) == -1) { return-1; } ... if (ev.type == EV_KEY && ev.code <= KEY_MAX) { //tj: here if (touch_screen_allowed_) { if (ev.code == BTN_TOUCH) { // A BTN_TOUCH with value 1 indicates the start of contact (protocol A), with 0 means // lifting the contact. touch_finger_down_ = (ev.value == 1); }
// Intentionally ignore BTN_TOUCH and BTN_TOOL_FINGER, which would otherwise trigger // additional scrolling (because in ScreenRecoveryUI::ShowFile(), we consider keys other than // KEY_POWER and KEY_UP as KEY_DOWN). if (ev.code == BTN_TOUCH || ev.code == BTN_TOOL_FINGER) { return0; } }
ProcessKey(ev.code, ev.value); //tj: here }
ProcessKey():
// Processes 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 voidRecoveryUI::ProcessKey(int key_code, int updown){ bool register_key = false; bool long_press = false;
{
看注释,一个按键的up和down是registered key。注意We also keep track...,跟踪的是registered key和other keys。
CheckKey()会决定是否要显示,ok,再看代码:
voidRecoveryUI::ProcessKey(int key_code, int updown){ ... bool reboot_enabled = enable_reboot; if (register_key) { switch (CheckKey(key_code, long_press)) { case RecoveryUI::IGNORE: break;
case RecoveryUI::TOGGLE: ShowText(!IsTextVisible()); //tj break;
// If we have power and volume up keys, that chord is the signal to toggle the text display. if (HasThreeButtons() || (HasPowerKey() && HasTouchScreen() && touch_screen_allowed_)) { if ((key == KEY_VOLUMEUP || key == KEY_UP) && IsKeyPressed(KEY_POWER)) { return TOGGLE; } } else { ... }