Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7440630c authored by Doug Zongker's avatar Doug Zongker
Browse files

refactor ui functions into a class

Move all the functions in ui.c to be members of a ScreenRecoveryUI
class, which is a subclass of an abstract RecoveryUI class.  Recovery
then creates a global singleton instance of this class and then invoke
the methods to drive the UI.  We use this to allow substitution of a
different RecoveryUI implementation for devices with radically
different form factors (eg, that don't have a screen).

Change-Id: I7fd8b2949d0db5a3f47c52978bca183966c86f33
parent 10e418d3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@ LOCAL_SRC_FILES := \
    bootloader.cpp \
    install.cpp \
    roots.cpp \
    ui.cpp \
    screen_ui.cpp \
    verifier.cpp

LOCAL_MODULE := recovery
+20 −14
Original line number Diff line number Diff line
@@ -34,9 +34,17 @@
#include "verifier.h"
#include "ui.h"

extern RecoveryUI* ui;

#define ASSUMED_UPDATE_BINARY_NAME  "META-INF/com/google/android/update-binary"
#define PUBLIC_KEYS_FILE "/res/keys"

// Default allocation of progress bar segments to operations
static const int VERIFICATION_PROGRESS_TIME = 60;
static const float VERIFICATION_PROGRESS_FRACTION = 0.25;
static const float DEFAULT_FILES_PROGRESS_FRACTION = 0.4;
static const float DEFAULT_IMAGE_PROGRESS_FRACTION = 0.1;

// If the package contains an update binary, extract it and run it.
static int
try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
@@ -134,18 +142,17 @@ try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
            float fraction = strtof(fraction_s, NULL);
            int seconds = strtol(seconds_s, NULL, 10);

            ui_show_progress(fraction * (1-VERIFICATION_PROGRESS_FRACTION),
                             seconds);
            ui->ShowProgress(fraction * (1-VERIFICATION_PROGRESS_FRACTION), seconds);
        } else if (strcmp(command, "set_progress") == 0) {
            char* fraction_s = strtok(NULL, " \n");
            float fraction = strtof(fraction_s, NULL);
            ui_set_progress(fraction);
            ui->SetProgress(fraction);
        } else if (strcmp(command, "ui_print") == 0) {
            char* str = strtok(NULL, "\n");
            if (str) {
                ui_print("%s", str);
                ui->Print("%s", str);
            } else {
                ui_print("\n");
                ui->Print("\n");
            }
        } else if (strcmp(command, "wipe_cache") == 0) {
            *wipe_cache = 1;
@@ -244,9 +251,9 @@ exit:
static int
really_install_package(const char *path, int* wipe_cache)
{
    ui_set_background(BACKGROUND_ICON_INSTALLING);
    ui_print("Finding update package...\n");
    ui_show_indeterminate_progress();
    ui->SetBackground(RecoveryUI::INSTALLING);
    ui->Print("Finding update package...\n");
    ui->SetProgressType(RecoveryUI::INDETERMINATE);
    LOGI("Update location: %s\n", path);

    if (ensure_path_mounted(path) != 0) {
@@ -254,7 +261,7 @@ really_install_package(const char *path, int* wipe_cache)
        return INSTALL_CORRUPT;
    }

    ui_print("Opening update package...\n");
    ui->Print("Opening update package...\n");

    int numKeys;
    RSAPublicKey* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);
@@ -265,10 +272,9 @@ really_install_package(const char *path, int* wipe_cache)
    LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);

    // Give verification half the progress bar...
    ui_print("Verifying update package...\n");
    ui_show_progress(
            VERIFICATION_PROGRESS_FRACTION,
            VERIFICATION_PROGRESS_TIME);
    ui->Print("Verifying update package...\n");
    ui->SetProgressType(RecoveryUI::DETERMINATE);
    ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME);

    int err;
    err = verify_file(path, loadedKeys, numKeys);
@@ -290,7 +296,7 @@ really_install_package(const char *path, int* wipe_cache)

    /* Verify and install the contents of the package.
     */
    ui_print("Installing update...\n");
    ui->Print("Installing update...\n");
    return try_update_binary(path, &zip, wipe_cache);
}

+51 −44
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
#include "roots.h"
#include "recovery_ui.h"
#include "ui.h"
#include "screen_ui.h"

static const struct option OPTIONS[] = {
  { "send_intent", required_argument, NULL, 's' },
@@ -62,6 +63,8 @@ static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";

extern UIParameters ui_parameters;    // from ui.c

RecoveryUI* ui = NULL;

/*
 * The recovery tool communicates with the main system through /cache files.
 *   /cache/recovery/command - INPUT - command line for tool, one arg per line
@@ -291,9 +294,9 @@ finish_recovery(const char *send_intent) {

static int
erase_volume(const char *volume) {
    ui_set_background(BACKGROUND_ICON_INSTALLING);
    ui_show_indeterminate_progress();
    ui_print("Formatting %s...\n", volume);
    ui->SetBackground(RecoveryUI::INSTALLING);
    ui->SetProgressType(RecoveryUI::INDETERMINATE);
    ui->Print("Formatting %s...\n", volume);

    ensure_path_unmounted(volume);

@@ -425,22 +428,22 @@ get_menu_selection(const char* const * headers, const char* const * items,
                   int menu_only, int initial_selection) {
    // throw away keys pressed previously, so user doesn't
    // accidentally trigger menu items.
    ui_clear_key_queue();
    ui->FlushKeys();

    ui_start_menu(headers, items, initial_selection);
    ui->StartMenu(headers, items, initial_selection);
    int selected = initial_selection;
    int chosen_item = -1;

    while (chosen_item < 0) {
        int key = ui_wait_key();
        int visible = ui_text_visible();
        int key = ui->WaitKey();
        int visible = ui->IsTextVisible();

        if (key == -1) {   // ui_wait_key() timed out
            if (ui_text_ever_visible()) {
            if (ui->WasTextEverVisible()) {
                continue;
            } else {
                LOGI("timed out waiting for key input; rebooting.\n");
                ui_end_menu();
                ui->EndMenu();
                return ITEM_REBOOT;
            }
        }
@@ -451,11 +454,11 @@ get_menu_selection(const char* const * headers, const char* const * items,
            switch (action) {
                case HIGHLIGHT_UP:
                    --selected;
                    selected = ui_menu_select(selected);
                    selected = ui->SelectMenu(selected);
                    break;
                case HIGHLIGHT_DOWN:
                    ++selected;
                    selected = ui_menu_select(selected);
                    selected = ui->SelectMenu(selected);
                    break;
                case SELECT_ITEM:
                    chosen_item = selected;
@@ -468,7 +471,7 @@ get_menu_selection(const char* const * headers, const char* const * items,
        }
    }

    ui_end_menu();
    ui->EndMenu();
    return chosen_item;
}

@@ -577,7 +580,7 @@ update_directory(const char* path, const char* unmount_when_done,
            strlcat(new_path, "/", PATH_MAX);
            strlcat(new_path, item, PATH_MAX);

            ui_print("\n-- Install %s ...\n", path);
            ui->Print("\n-- Install %s ...\n", path);
            set_sdcard_update_bootloader_message();
            char* copy = copy_sideloaded_package(new_path);
            if (unmount_when_done != NULL) {
@@ -636,11 +639,11 @@ wipe_data(int confirm) {
        }
    }

    ui_print("\n-- Wiping data...\n");
    ui->Print("\n-- Wiping data...\n");
    device_wipe_data();
    erase_volume("/data");
    erase_volume("/cache");
    ui_print("Data wipe complete.\n");
    ui->Print("Data wipe complete.\n");
}

static void
@@ -649,7 +652,7 @@ prompt_and_wait() {

    for (;;) {
        finish_recovery(NULL);
        ui_reset_progress();
        ui->SetProgressType(RecoveryUI::EMPTY);

        int chosen_item = get_menu_selection(headers, MENU_ITEMS, 0, 0);

@@ -665,35 +668,35 @@ prompt_and_wait() {
                return;

            case ITEM_WIPE_DATA:
                wipe_data(ui_text_visible());
                if (!ui_text_visible()) return;
                wipe_data(ui->IsTextVisible());
                if (!ui->IsTextVisible()) return;
                break;

            case ITEM_WIPE_CACHE:
                ui_print("\n-- Wiping cache...\n");
                ui->Print("\n-- Wiping cache...\n");
                erase_volume("/cache");
                ui_print("Cache wipe complete.\n");
                if (!ui_text_visible()) return;
                ui->Print("Cache wipe complete.\n");
                if (!ui->IsTextVisible()) return;
                break;

            case ITEM_APPLY_SDCARD:
                status = update_directory(SDCARD_ROOT, SDCARD_ROOT, &wipe_cache);
                if (status == INSTALL_SUCCESS && wipe_cache) {
                    ui_print("\n-- Wiping cache (at package request)...\n");
                    ui->Print("\n-- Wiping cache (at package request)...\n");
                    if (erase_volume("/cache")) {
                        ui_print("Cache wipe failed.\n");
                        ui->Print("Cache wipe failed.\n");
                    } else {
                        ui_print("Cache wipe complete.\n");
                        ui->Print("Cache wipe complete.\n");
                    }
                }
                if (status >= 0) {
                    if (status != INSTALL_SUCCESS) {
                        ui_set_background(BACKGROUND_ICON_ERROR);
                        ui_print("Installation aborted.\n");
                    } else if (!ui_text_visible()) {
                        ui->SetBackground(RecoveryUI::ERROR);
                        ui->Print("Installation aborted.\n");
                    } else if (!ui->IsTextVisible()) {
                        return;  // reboot if logs aren't visible
                    } else {
                        ui_print("\nInstall from sdcard complete.\n");
                        ui->Print("\nInstall from sdcard complete.\n");
                    }
                }
                break;
@@ -701,21 +704,21 @@ prompt_and_wait() {
                // Don't unmount cache at the end of this.
                status = update_directory(CACHE_ROOT, NULL, &wipe_cache);
                if (status == INSTALL_SUCCESS && wipe_cache) {
                    ui_print("\n-- Wiping cache (at package request)...\n");
                    ui->Print("\n-- Wiping cache (at package request)...\n");
                    if (erase_volume("/cache")) {
                        ui_print("Cache wipe failed.\n");
                        ui->Print("Cache wipe failed.\n");
                    } else {
                        ui_print("Cache wipe complete.\n");
                        ui->Print("Cache wipe complete.\n");
                    }
                }
                if (status >= 0) {
                    if (status != INSTALL_SUCCESS) {
                        ui_set_background(BACKGROUND_ICON_ERROR);
                        ui_print("Installation aborted.\n");
                    } else if (!ui_text_visible()) {
                        ui->SetBackground(RecoveryUI::ERROR);
                        ui->Print("Installation aborted.\n");
                    } else if (!ui->IsTextVisible()) {
                        return;  // reboot if logs aren't visible
                    } else {
                        ui_print("\nInstall from cache complete.\n");
                        ui->Print("\nInstall from cache complete.\n");
                    }
                }
                break;
@@ -738,9 +741,13 @@ main(int argc, char **argv) {
    freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL);
    printf("Starting recovery on %s", ctime(&start));

    // TODO: device_* should be a C++ class; init should return the
    // appropriate UI for the device.
    device_ui_init(&ui_parameters);
    ui_init();
    ui_set_background(BACKGROUND_ICON_INSTALLING);
    ui = new ScreenRecoveryUI();

    ui->Init();
    ui->SetBackground(RecoveryUI::INSTALLING);
    load_volume_table();
    get_args(&argc, &argv);

@@ -757,7 +764,7 @@ main(int argc, char **argv) {
        case 'u': update_package = optarg; break;
        case 'w': wipe_data = wipe_cache = 1; break;
        case 'c': wipe_cache = 1; break;
        case 't': ui_show_text(1); break;
        case 't': ui->ShowText(true); break;
        case '?':
            LOGE("Invalid command argument\n");
            continue;
@@ -800,27 +807,27 @@ main(int argc, char **argv) {
                LOGE("Cache wipe (requested by package) failed.");
            }
        }
        if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n");
        if (status != INSTALL_SUCCESS) ui->Print("Installation aborted.\n");
    } else if (wipe_data) {
        if (device_wipe_data()) status = INSTALL_ERROR;
        if (erase_volume("/data")) status = INSTALL_ERROR;
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui_print("Data wipe failed.\n");
        if (status != INSTALL_SUCCESS) ui->Print("Data wipe failed.\n");
    } else if (wipe_cache) {
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui_print("Cache wipe failed.\n");
        if (status != INSTALL_SUCCESS) ui->Print("Cache wipe failed.\n");
    } else {
        status = INSTALL_ERROR;  // No command specified
    }

    if (status != INSTALL_SUCCESS) ui_set_background(BACKGROUND_ICON_ERROR);
    if (status != INSTALL_SUCCESS || ui_text_visible()) {
    if (status != INSTALL_SUCCESS) ui->SetBackground(RecoveryUI::ERROR);
    if (status != INSTALL_SUCCESS || ui->IsTextVisible()) {
        prompt_and_wait();
    }

    // Otherwise, get ready to boot the main system...
    finish_recovery(send_intent);
    ui_print("Rebooting...\n");
    ui->Print("Rebooting...\n");
    android_reboot(ANDROID_RB_RESTART, 0, 0);
    return EXIT_SUCCESS;
}
+180 −213

File changed and moved.

Preview size limit exceeded, changes collapsed.

screen_ui.h

0 → 100644
+121 −0
Original line number Diff line number Diff line
/*
 * 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.
 */

#ifndef RECOVERY_SCREEN_UI_H
#define RECOVERY_SCREEN_UI_H

#include <pthread.h>

#include "ui.h"
#include "minui/minui.h"

// Implementation of RecoveryUI appropriate for devices with a screen
// (shows an icon + a progress bar, text logging, menu, etc.)
class ScreenRecoveryUI : public RecoveryUI {
  public:
    ScreenRecoveryUI();

    void Init();

    // overall recovery state ("background image")
    void SetBackground(Icon icon);

    // progress indicator
    void SetProgressType(ProgressType type);
    void ShowProgress(float portion, float seconds);
    void SetProgress(float fraction);

    // text log
    void ShowText(bool visible);
    bool IsTextVisible();
    bool WasTextEverVisible();

    // key handling
    int WaitKey();
    bool IsKeyPressed(int key);
    void FlushKeys();

    // printing messages
    void Print(const char* fmt, ...); // __attribute__((format(printf, 1, 2)));

    // menu display
    void StartMenu(const char* const * headers, const char* const * items,
                           int initial_selection);
    int SelectMenu(int sel);
    void EndMenu();

  private:
    Icon currentIcon;
    int installingFrame;

    pthread_mutex_t updateMutex;
    gr_surface backgroundIcon[3];
    gr_surface *installationOverlay;
    gr_surface *progressBarIndeterminate;
    gr_surface progressBarEmpty;
    gr_surface progressBarFill;

    ProgressType progressBarType;

    float progressScopeStart, progressScopeSize, progress;
    double progressScopeTime, progressScopeDuration;

    // true when both graphics pages are the same (except for the
    // progress bar)
    bool pagesIdentical;

    static const int kMaxCols = 96;
    static const int kMaxRows = 32;

    // Log text overlay, displayed when a magic key is pressed
    char text[kMaxRows][kMaxCols];
    int text_cols, text_rows;
    int text_col, text_row, text_top;
    bool show_text;
    bool show_text_ever;   // has show_text ever been true?

    char menu[kMaxRows][kMaxCols];
    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;
    volatile char key_pressed[KEY_MAX + 1];
    int rel_sum;

    pthread_t progress_t;
    pthread_t input_t;

    void draw_install_overlay_locked(int frame);
    void draw_background_locked(Icon icon);
    void draw_progress_locked();
    void draw_text_line(int row, const char* t);
    void draw_screen_locked();
    void update_screen_locked();
    void update_progress_locked();
    static void* progress_thread(void* cookie);
    static int input_callback(int fd, short revents, void* data);
    static void* input_thread(void* cookie);

    bool usb_connected();

    void LoadBitmap(const char* filename, gr_surface* surface);

};

#endif  // RECOVERY_UI_H
Loading