Recovery啓動流程(2)---UI界面

Recovery啓動流程系列文章把recvoery目錄下文件分成小塊講解,最後再以一條主線貫穿所有的內容。這篇文章主要講解Recovery-UI的相關內容。
我們知道,當我們通過按鍵或者應用進入recovery模式,實質是kernel後加載recovery.img,kernel起來後執行的第一個進程就是init,此進程會讀入init.rc啓動相應的服務。在recovery模式中,啓動的服務是執行recovery可執行文件,此文件是bootable/recovery/recovery.cpp文件生成,我們就從recovery.cpp文件開始分析。
bootable/recovery/recovery.cpp

int
main(int argc, char **argv) {
....
    Device* device = make_device();
    ui = device->GetUI();
    gCurrentUI = ui;

    ui->SetLocale(locale);
    ui->Init();

    ui->SetBackground(RecoveryUI::NONE);  
    if (show_text) ui->ShowText(true);  
....
    if (status != INSTALL_SUCCESS || ui->IsTextVisible()) {  
        prompt_and_wait(device, status);  
    }  
....
}

1.首先新建了一個Device類的對象, Device類封裝了一些操作,包括UI的操作

2.調用Device類的GetUI()返回一個RecoveryUI對象

3.調用ui->SetLocale(locale)設置語言,調用SetBackground方法設置背景圖片

4.調用Init()進行初始化。

5.這裏的Init從代碼上看應該是ui.cpp文件中RecoveryUI類的Init()方法,但是經驗上走的應該是ScreenRecoveryUI,其中的願意我還在看,這裏我是按照ScreenRecoveryUI::Init追的代碼。其中RecoveryUI是ScreenRecoveryUI的父類。

6.顯示recovery的主界面,即一個選擇菜單
初始化:

void ScreenRecoveryUI::Init() {
    gr_init();             //初始化圖形設備,分配Pixelflinger庫渲染的內存

    gr_font_size(&char_width, &char_height);
    text_rows_ = gr_fb_height() / char_height;
    text_cols_ = gr_fb_width() / char_width;

#ifdef SUPPORT_UTF8_MULTILINGUAL
    int ml_cols_ = 6 * text_cols_; //max is 6 char for 1 utf8 character.
    text_ = Alloc2d(text_rows_, ml_cols_ + 1);
    file_viewer_text_ = Alloc2d(text_rows_, ml_cols_ + 1);
    menu_ = Alloc2d(text_rows_, ml_cols_ + 1);
    menu_headers_wrap = Alloc2d(text_rows_, ml_cols_ + 1);
#else
    text_ = Alloc2d(text_rows_, text_cols_ + 1);
    file_viewer_text_ = Alloc2d(text_rows_, text_cols_ + 1);
    menu_ = Alloc2d(text_rows_, text_cols_ + 1);
#endif

    text_col_ = text_row_ = 0;
    text_top_ = 1;

    backgroundIcon[NONE] = nullptr;
    LoadBitmapArray("icon_installing", &installing_frames, &installation);
    backgroundIcon[INSTALLING_UPDATE] = installing_frames ? installation[0] : nullptr;
    backgroundIcon[ERASING] = backgroundIcon[INSTALLING_UPDATE];
    LoadBitmap("icon_error", &backgroundIcon[ERROR]);                //LoadBitmap()  將png生成surface, 每個png圖片對應一個surface, 所有surface存放在一個數組中
    backgroundIcon[NO_COMMAND] = backgroundIcon[ERROR];

    LoadBitmap("icon_recovery", &backgroundIcon[RECOVERY]);
    LoadBitmap("progress_empty", &progressBarEmpty);
    LoadBitmap("progress_fill", &progressBarFill);
    LoadBitmap("stage_empty", &stageMarkerEmpty);
    LoadBitmap("stage_fill", &stageMarkerFill);

/* add for AT&T recovery update install UI begin */
#ifdef TARGET_ATT_RECOVERY_UI
    LoadBitmap("icon_attinstalling", &backgroundIcon[ATT_INSTALLING_UPDATE]);
    LoadBitmap("progress_attempty", &progressBarEmpty_ATT);
    LoadBitmap("progress_attfill", &progressBarFill_ATT);
    LoadLocalizedBitmap("installing_atttext", &backgroundText[ATT_INSTALLING_UPDATE]);   //LoadLocalizedBitmap()  將區域文字所在的圖片中的text信息根據當前的locale提取出來,生成對應的surface, 所有
 surface也存放在一個數組中
#endif
/* add for AT&T recovery update install UI end */

    LoadLocalizedBitmap("installing_text", &backgroundText[INSTALLING_UPDATE]);
    LoadLocalizedBitmap("erasing_text", &backgroundText[ERASING]);
    LoadLocalizedBitmap("no_command_text", &backgroundText[NO_COMMAND]);
    LoadLocalizedBitmap("error_text", &backgroundText[ERROR]);

    pthread_create(&progress_thread_, nullptr, ProgressThreadStartRoutine, this);   //創建一個線程,在該循環中不停地檢測currentIcon以及progressBarType來決定是不是要更新進度條。
    RecoveryUI::Init();  //初始化RecoveryUI類
}

bootable/recovery/minui/ui.cpp

void RecoveryUI::Init() {
    ev_init(InputCallback, this);

    ev_iterate_available_keys(std::bind(&RecoveryUI::OnKeyDetected, this, std::placeholders::_1));

    pthread_create(&input_thread_, nullptr, InputThreadLoop, nullptr);
}

通過RecoveryUI::Init(); 調用events.cpp文件,界面和按鍵/觸摸聯繫在一起了,後面會用單獨的文章介紹recovery按鍵和觸屏的相關內容。
下面介紹幾個常用的函數

void ScreenRecoveryUI::SetLocale(const char* new_locale) {
    if (new_locale) {
        this->locale = new_locale;
        char* lang = strdup(locale);
        for (char* p = lang; *p; ++p) {
            if (*p == '_') {
                *p = '\0';
                break;
            }
        }
        // A bit cheesy: keep an explicit list of supported languages
        // that are RTL.
        if (strcmp(lang, "ar") == 0 ||   // Arabic
            strcmp(lang, "fa") == 0 ||   // Persian (Farsi)
            strcmp(lang, "he") == 0 ||   // Hebrew (new language code)
            strcmp(lang, "iw") == 0 ||   // Hebrew (old language code)
            strcmp(lang, "ur") == 0) {   // Urdu
            rtl_locale = true;
        }
        free(lang);
    } else {
        new_locale = nullptr;
    }
}

從recovery.cpp main()中可知,進入recovery後會分析/cache/recovery/command文件,根據內容來設定顯示的文字語言
SetLocale函數根據locale判斷所用的字體是否屬於阿拉伯語系,阿拉伯語的書寫習慣是從右到左,如果是阿拉伯語系的話,就設置一個標誌,後面根據這個標誌決定從右到左顯示文字或進度條。關於顯示文字的語言通過代碼即可查看,這裏只簡單的列出語言設置的幾條主線,不貼出具體的代碼(太多了)。

g_ml_str[] (mi_string.h)-> ml_string_fetch() (multilingual.c)

ml_set_language (multilingual.c) -> ml_select() (recovery.cpp) -> prompt_and_wait() (recovery.cpp) -> main() (recovery.cpp)

SetBackground函數比較簡潔,關鍵部分在update_screen_locked。
update_screen_locked 和update_progress_locked是recovery的UI部分的關鍵函數,update_screen_locked用來更新背 景, update_progress_locked用來更新進度條,因爲顯示的畫面會一直在更新,所以這兩個函數會在不同的地方被反覆調用

void ScreenRecoveryUI::SetBackground(Icon icon) {
    pthread_mutex_lock(&updateMutex);
    currentIcon = icon;
    update_screen_locked();
    pthread_mutex_unlock(&updateMutex);
}
void ScreenRecoveryUI::update_screen_locked() {
    draw_screen_locked();
    gr_flip();
}
void ScreenRecoveryUI::draw_screen_locked() {
    if (!show_text) {
        draw_background_locked(currentIcon);               //************   有一個bug因爲此行沒有,導致SetBackground函數無法更換背景圖片
        draw_progress_locked();
    } else {
        gr_color(0, 0, 0, 255);
        gr_clear();
        draw_background_locked(currentIcon);            //************
    .........
   
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章