aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTao Bao2017-01-03 12:15:33 -0600
committerTao Bao2017-01-04 00:40:03 -0600
commit736d59c56754b86135d9156208645b8b1814fba1 (patch)
treeb34e26851aaea9d8958f818d32c7d0e15196fa27
parent71633ebfb00103dd95a82cd813824dbddd9b905d (diff)
downloadplatform-bootable-recovery-736d59c56754b86135d9156208645b8b1814fba1.tar.gz
platform-bootable-recovery-736d59c56754b86135d9156208645b8b1814fba1.tar.xz
platform-bootable-recovery-736d59c56754b86135d9156208645b8b1814fba1.zip
recovery: Fix the broken UI text.
UI text is broken (doesn't show any text during FDR) due to commit d530449e54bd327e9c26209ffa0490c6508afe6c, which reordered the calls to RecoveryUI::SetLocale() and RecoveryUI::Init(). Because Init() uses the locale info to load the localized texts (from images), the locale must be set prior to that via SetLocale(). This CL refactors Init() to take the locale parameter, and removes the odd SetLocale() API. Bug: 34029338 Test: 'Run graphics test' under recovery. Change-Id: I620394a3d4e3705e9af5a1f6299285d143ae1b01
-rw-r--r--recovery.cpp3
-rw-r--r--screen_ui.cpp234
-rw-r--r--screen_ui.h8
-rw-r--r--stub_ui.h2
-rw-r--r--tests/component/verifier_test.cpp70
-rw-r--r--ui.cpp67
-rw-r--r--ui.h21
-rw-r--r--wear_ui.cpp71
-rw-r--r--wear_ui.h4
9 files changed, 244 insertions, 236 deletions
diff --git a/recovery.cpp b/recovery.cpp
index b7aeaee1..5888c542 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -1506,11 +1506,10 @@ int main(int argc, char **argv) {
1506 Device* device = make_device(); 1506 Device* device = make_device();
1507 ui = device->GetUI(); 1507 ui = device->GetUI();
1508 1508
1509 if (!ui->Init()) { 1509 if (!ui->Init(locale)) {
1510 printf("Failed to initialize UI, use stub UI instead."); 1510 printf("Failed to initialize UI, use stub UI instead.");
1511 ui = new StubRecoveryUI(); 1511 ui = new StubRecoveryUI();
1512 } 1512 }
1513 ui->SetLocale(locale.c_str());
1514 // Set background string to "installing security update" for security update, 1513 // Set background string to "installing security update" for security update,
1515 // otherwise set it to "installing system update". 1514 // otherwise set it to "installing system update".
1516 ui->SetSystemUpdateText(security_update); 1515 ui->SetSystemUpdateText(security_update);
diff --git a/screen_ui.cpp b/screen_ui.cpp
index 5b9e5a5a..706877b4 100644
--- a/screen_ui.cpp
+++ b/screen_ui.cpp
@@ -29,6 +29,7 @@
29#include <time.h> 29#include <time.h>
30#include <unistd.h> 30#include <unistd.h>
31 31
32#include <string>
32#include <vector> 33#include <vector>
33 34
34#include <android-base/logging.h> 35#include <android-base/logging.h>
@@ -51,37 +52,34 @@ static double now() {
51 return tv.tv_sec + tv.tv_usec / 1000000.0; 52 return tv.tv_sec + tv.tv_usec / 1000000.0;
52} 53}
53 54
54ScreenRecoveryUI::ScreenRecoveryUI() : 55ScreenRecoveryUI::ScreenRecoveryUI()
55 currentIcon(NONE), 56 : currentIcon(NONE),
56 locale(nullptr), 57 progressBarType(EMPTY),
57 progressBarType(EMPTY), 58 progressScopeStart(0),
58 progressScopeStart(0), 59 progressScopeSize(0),
59 progressScopeSize(0), 60 progress(0),
60 progress(0), 61 pagesIdentical(false),
61 pagesIdentical(false), 62 text_cols_(0),
62 text_cols_(0), 63 text_rows_(0),
63 text_rows_(0), 64 text_(nullptr),
64 text_(nullptr), 65 text_col_(0),
65 text_col_(0), 66 text_row_(0),
66 text_row_(0), 67 text_top_(0),
67 text_top_(0), 68 show_text(false),
68 show_text(false), 69 show_text_ever(false),
69 show_text_ever(false), 70 menu_(nullptr),
70 menu_(nullptr), 71 show_menu(false),
71 show_menu(false), 72 menu_items(0),
72 menu_items(0), 73 menu_sel(0),
73 menu_sel(0), 74 file_viewer_text_(nullptr),
74 file_viewer_text_(nullptr), 75 intro_frames(0),
75 intro_frames(0), 76 loop_frames(0),
76 loop_frames(0), 77 current_frame(0),
77 current_frame(0), 78 intro_done(false),
78 intro_done(false), 79 animation_fps(30), // TODO: there's currently no way to infer this.
79 animation_fps(30), // TODO: there's currently no way to infer this. 80 stage(-1),
80 stage(-1), 81 max_stage(-1),
81 max_stage(-1), 82 updateMutex(PTHREAD_MUTEX_INITIALIZER) {}
82 updateMutex(PTHREAD_MUTEX_INITIALIZER),
83 rtl_locale(false) {
84}
85 83
86GRSurface* ScreenRecoveryUI::GetCurrentFrame() { 84GRSurface* ScreenRecoveryUI::GetCurrentFrame() {
87 if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) { 85 if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) {
@@ -175,51 +173,50 @@ void ScreenRecoveryUI::draw_background_locked() {
175// Does not flip pages. 173// Does not flip pages.
176// Should only be called with updateMutex locked. 174// Should only be called with updateMutex locked.
177void ScreenRecoveryUI::draw_foreground_locked() { 175void ScreenRecoveryUI::draw_foreground_locked() {
178 if (currentIcon != NONE) { 176 if (currentIcon != NONE) {
179 GRSurface* frame = GetCurrentFrame(); 177 GRSurface* frame = GetCurrentFrame();
180 int frame_width = gr_get_width(frame); 178 int frame_width = gr_get_width(frame);
181 int frame_height = gr_get_height(frame); 179 int frame_height = gr_get_height(frame);
182 int frame_x = (gr_fb_width() - frame_width) / 2; 180 int frame_x = (gr_fb_width() - frame_width) / 2;
183 int frame_y = GetAnimationBaseline(); 181 int frame_y = GetAnimationBaseline();
184 gr_blit(frame, 0, 0, frame_width, frame_height, frame_x, frame_y); 182 gr_blit(frame, 0, 0, frame_width, frame_height, frame_x, frame_y);
185 } 183 }
186 184
187 if (progressBarType != EMPTY) { 185 if (progressBarType != EMPTY) {
188 int width = gr_get_width(progressBarEmpty); 186 int width = gr_get_width(progressBarEmpty);
189 int height = gr_get_height(progressBarEmpty); 187 int height = gr_get_height(progressBarEmpty);
190 188
191 int progress_x = (gr_fb_width() - width)/2; 189 int progress_x = (gr_fb_width() - width) / 2;
192 int progress_y = GetProgressBaseline(); 190 int progress_y = GetProgressBaseline();
193 191
194 // Erase behind the progress bar (in case this was a progress-only update) 192 // Erase behind the progress bar (in case this was a progress-only update)
195 gr_color(0, 0, 0, 255); 193 gr_color(0, 0, 0, 255);
196 gr_fill(progress_x, progress_y, width, height); 194 gr_fill(progress_x, progress_y, width, height);
197 195
198 if (progressBarType == DETERMINATE) { 196 if (progressBarType == DETERMINATE) {
199 float p = progressScopeStart + progress * progressScopeSize; 197 float p = progressScopeStart + progress * progressScopeSize;
200 int pos = (int) (p * width); 198 int pos = static_cast<int>(p * width);
201 199
202 if (rtl_locale) { 200 if (rtl_locale_) {
203 // Fill the progress bar from right to left. 201 // Fill the progress bar from right to left.
204 if (pos > 0) { 202 if (pos > 0) {
205 gr_blit(progressBarFill, width-pos, 0, pos, height, 203 gr_blit(progressBarFill, width - pos, 0, pos, height, progress_x + width - pos,
206 progress_x+width-pos, progress_y); 204 progress_y);
207 } 205 }
208 if (pos < width-1) { 206 if (pos < width - 1) {
209 gr_blit(progressBarEmpty, 0, 0, width-pos, height, progress_x, progress_y); 207 gr_blit(progressBarEmpty, 0, 0, width - pos, height, progress_x, progress_y);
210 } 208 }
211 } else { 209 } else {
212 // Fill the progress bar from left to right. 210 // Fill the progress bar from left to right.
213 if (pos > 0) { 211 if (pos > 0) {
214 gr_blit(progressBarFill, 0, 0, pos, height, progress_x, progress_y); 212 gr_blit(progressBarFill, 0, 0, pos, height, progress_x, progress_y);
215 }
216 if (pos < width-1) {
217 gr_blit(progressBarEmpty, pos, 0, width-pos, height,
218 progress_x+pos, progress_y);
219 }
220 }
221 } 213 }
214 if (pos < width - 1) {
215 gr_blit(progressBarEmpty, pos, 0, width - pos, height, progress_x + pos, progress_y);
216 }
217 }
222 } 218 }
219 }
223} 220}
224 221
225void ScreenRecoveryUI::SetColor(UIElement e) { 222void ScreenRecoveryUI::SetColor(UIElement e) {
@@ -423,10 +420,10 @@ void ScreenRecoveryUI::LoadBitmap(const char* filename, GRSurface** surface) {
423} 420}
424 421
425void ScreenRecoveryUI::LoadLocalizedBitmap(const char* filename, GRSurface** surface) { 422void ScreenRecoveryUI::LoadLocalizedBitmap(const char* filename, GRSurface** surface) {
426 int result = res_create_localized_alpha_surface(filename, locale, surface); 423 int result = res_create_localized_alpha_surface(filename, locale_.c_str(), surface);
427 if (result < 0) { 424 if (result < 0) {
428 LOG(ERROR) << "couldn't load bitmap " << filename << " (error " << result << ")"; 425 LOG(ERROR) << "couldn't load bitmap " << filename << " (error " << result << ")";
429 } 426 }
430} 427}
431 428
432static char** Alloc2d(size_t rows, size_t cols) { 429static char** Alloc2d(size_t rows, size_t cols) {
@@ -459,47 +456,47 @@ bool ScreenRecoveryUI::InitTextParams() {
459 return true; 456 return true;
460} 457}
461 458
462bool ScreenRecoveryUI::Init() { 459bool ScreenRecoveryUI::Init(const std::string& locale) {
463 RecoveryUI::Init(); 460 RecoveryUI::Init(locale);
464 if (!InitTextParams()) { 461 if (!InitTextParams()) {
465 return false; 462 return false;
466 } 463 }
467 464
468 density_ = static_cast<float>(android::base::GetIntProperty("ro.sf.lcd_density", 160)) / 160.f; 465 density_ = static_cast<float>(android::base::GetIntProperty("ro.sf.lcd_density", 160)) / 160.f;
469 466
470 // Are we portrait or landscape? 467 // Are we portrait or landscape?
471 layout_ = (gr_fb_width() > gr_fb_height()) ? LANDSCAPE : PORTRAIT; 468 layout_ = (gr_fb_width() > gr_fb_height()) ? LANDSCAPE : PORTRAIT;
472 // Are we the large variant of our base layout? 469 // Are we the large variant of our base layout?
473 if (gr_fb_height() > PixelsFromDp(800)) ++layout_; 470 if (gr_fb_height() > PixelsFromDp(800)) ++layout_;
474 471
475 text_ = Alloc2d(text_rows_, text_cols_ + 1); 472 text_ = Alloc2d(text_rows_, text_cols_ + 1);
476 file_viewer_text_ = Alloc2d(text_rows_, text_cols_ + 1); 473 file_viewer_text_ = Alloc2d(text_rows_, text_cols_ + 1);
477 menu_ = Alloc2d(text_rows_, text_cols_ + 1); 474 menu_ = Alloc2d(text_rows_, text_cols_ + 1);
478 475
479 text_col_ = text_row_ = 0; 476 text_col_ = text_row_ = 0;
480 text_top_ = 1; 477 text_top_ = 1;
481 478
482 LoadBitmap("icon_error", &error_icon); 479 LoadBitmap("icon_error", &error_icon);
483 480
484 LoadBitmap("progress_empty", &progressBarEmpty); 481 LoadBitmap("progress_empty", &progressBarEmpty);
485 LoadBitmap("progress_fill", &progressBarFill); 482 LoadBitmap("progress_fill", &progressBarFill);
486 483
487 LoadBitmap("stage_empty", &stageMarkerEmpty); 484 LoadBitmap("stage_empty", &stageMarkerEmpty);
488 LoadBitmap("stage_fill", &stageMarkerFill); 485 LoadBitmap("stage_fill", &stageMarkerFill);
489 486
490 // Background text for "installing_update" could be "installing update" 487 // Background text for "installing_update" could be "installing update"
491 // or "installing security update". It will be set after UI init according 488 // or "installing security update". It will be set after UI init according
492 // to commands in BCB. 489 // to commands in BCB.
493 installing_text = nullptr; 490 installing_text = nullptr;
494 LoadLocalizedBitmap("erasing_text", &erasing_text); 491 LoadLocalizedBitmap("erasing_text", &erasing_text);
495 LoadLocalizedBitmap("no_command_text", &no_command_text); 492 LoadLocalizedBitmap("no_command_text", &no_command_text);
496 LoadLocalizedBitmap("error_text", &error_text); 493 LoadLocalizedBitmap("error_text", &error_text);
497 494
498 LoadAnimation(); 495 LoadAnimation();
499 496
500 pthread_create(&progress_thread_, nullptr, ProgressThreadStartRoutine, this); 497 pthread_create(&progress_thread_, nullptr, ProgressThreadStartRoutine, this);
501 498
502 return true; 499 return true;
503} 500}
504 501
505void ScreenRecoveryUI::LoadAnimation() { 502void ScreenRecoveryUI::LoadAnimation() {
@@ -539,31 +536,6 @@ void ScreenRecoveryUI::LoadAnimation() {
539 } 536 }
540} 537}
541 538
542void ScreenRecoveryUI::SetLocale(const char* new_locale) {
543 this->locale = new_locale;
544 this->rtl_locale = false;
545
546 if (locale) {
547 char* lang = strdup(locale);
548 for (char* p = lang; *p; ++p) {
549 if (*p == '_') {
550 *p = '\0';
551 break;
552 }
553 }
554
555 // A bit cheesy: keep an explicit list of supported RTL languages.
556 if (strcmp(lang, "ar") == 0 || // Arabic
557 strcmp(lang, "fa") == 0 || // Persian (Farsi)
558 strcmp(lang, "he") == 0 || // Hebrew (new language code)
559 strcmp(lang, "iw") == 0 || // Hebrew (old language code)
560 strcmp(lang, "ur") == 0) { // Urdu
561 rtl_locale = true;
562 }
563 free(lang);
564 }
565}
566
567void ScreenRecoveryUI::SetBackground(Icon icon) { 539void ScreenRecoveryUI::SetBackground(Icon icon) {
568 pthread_mutex_lock(&updateMutex); 540 pthread_mutex_lock(&updateMutex);
569 541
diff --git a/screen_ui.h b/screen_ui.h
index 38e2f072..3ad64907 100644
--- a/screen_ui.h
+++ b/screen_ui.h
@@ -20,6 +20,8 @@
20#include <pthread.h> 20#include <pthread.h>
21#include <stdio.h> 21#include <stdio.h>
22 22
23#include <string>
24
23#include "ui.h" 25#include "ui.h"
24#include "minui/minui.h" 26#include "minui/minui.h"
25 27
@@ -29,8 +31,7 @@ class ScreenRecoveryUI : public RecoveryUI {
29 public: 31 public:
30 ScreenRecoveryUI(); 32 ScreenRecoveryUI();
31 33
32 bool Init() override; 34 bool Init(const std::string& locale) override;
33 void SetLocale(const char* locale);
34 35
35 // overall recovery state ("background image") 36 // overall recovery state ("background image")
36 void SetBackground(Icon icon); 37 void SetBackground(Icon icon);
@@ -71,8 +72,6 @@ class ScreenRecoveryUI : public RecoveryUI {
71 protected: 72 protected:
72 Icon currentIcon; 73 Icon currentIcon;
73 74
74 const char* locale;
75
76 // The scale factor from dp to pixels. 1.0 for mdpi, 4.0 for xxxhdpi. 75 // The scale factor from dp to pixels. 1.0 for mdpi, 4.0 for xxxhdpi.
77 float density_; 76 float density_;
78 // The layout to use. 77 // The layout to use.
@@ -135,7 +134,6 @@ class ScreenRecoveryUI : public RecoveryUI {
135 int char_width_; 134 int char_width_;
136 int char_height_; 135 int char_height_;
137 pthread_mutex_t updateMutex; 136 pthread_mutex_t updateMutex;
138 bool rtl_locale;
139 137
140 virtual bool InitTextParams(); 138 virtual bool InitTextParams();
141 139
diff --git a/stub_ui.h b/stub_ui.h
index 1219b284..85dbcfd8 100644
--- a/stub_ui.h
+++ b/stub_ui.h
@@ -24,8 +24,6 @@ class StubRecoveryUI : public RecoveryUI {
24 public: 24 public:
25 StubRecoveryUI() = default; 25 StubRecoveryUI() = default;
26 26
27 void SetLocale(const char* locale) override {}
28
29 void SetBackground(Icon icon) override {} 27 void SetBackground(Icon icon) override {}
30 void SetSystemUpdateText(bool security_update) override {} 28 void SetSystemUpdateText(bool security_update) override {}
31 29
diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp
index 33aadb3f..b740af96 100644
--- a/tests/component/verifier_test.cpp
+++ b/tests/component/verifier_test.cpp
@@ -40,38 +40,44 @@
40RecoveryUI* ui = NULL; 40RecoveryUI* ui = NULL;
41 41
42class MockUI : public RecoveryUI { 42class MockUI : public RecoveryUI {
43 bool Init() { return true; } 43 bool Init(const std::string&) override {
44 void SetStage(int, int) { } 44 return true;
45 void SetLocale(const char*) { } 45 }
46 void SetBackground(Icon /*icon*/) { } 46 void SetStage(int, int) override {}
47 void SetSystemUpdateText(bool /*security_update*/) { } 47 void SetBackground(Icon /*icon*/) override {}
48 48 void SetSystemUpdateText(bool /*security_update*/) override {}
49 void SetProgressType(ProgressType /*determinate*/) { } 49
50 void ShowProgress(float /*portion*/, float /*seconds*/) { } 50 void SetProgressType(ProgressType /*determinate*/) override {}
51 void SetProgress(float /*fraction*/) { } 51 void ShowProgress(float /*portion*/, float /*seconds*/) override {}
52 52 void SetProgress(float /*fraction*/) override {}
53 void ShowText(bool /*visible*/) { } 53
54 bool IsTextVisible() { return false; } 54 void ShowText(bool /*visible*/) override {}
55 bool WasTextEverVisible() { return false; } 55 bool IsTextVisible() override {
56 void Print(const char* fmt, ...) { 56 return false;
57 va_list ap; 57 }
58 va_start(ap, fmt); 58 bool WasTextEverVisible() override {
59 vfprintf(stderr, fmt, ap); 59 return false;
60 va_end(ap); 60 }
61 } 61 void Print(const char* fmt, ...) override {
62 void PrintOnScreenOnly(const char* fmt, ...) { 62 va_list ap;
63 va_list ap; 63 va_start(ap, fmt);
64 va_start(ap, fmt); 64 vfprintf(stderr, fmt, ap);
65 vfprintf(stderr, fmt, ap); 65 va_end(ap);
66 va_end(ap); 66 }
67 } 67 void PrintOnScreenOnly(const char* fmt, ...) override {
68 void ShowFile(const char*) { } 68 va_list ap;
69 69 va_start(ap, fmt);
70 void StartMenu(const char* const* /*headers*/, 70 vfprintf(stderr, fmt, ap);
71 const char* const* /*items*/, 71 va_end(ap);
72 int /*initial_selection*/) { } 72 }
73 int SelectMenu(int /*sel*/) { return 0; } 73 void ShowFile(const char*) override {}
74 void EndMenu() { } 74
75 void StartMenu(const char* const* /*headers*/, const char* const* /*items*/,
76 int /*initial_selection*/) override {}
77 int SelectMenu(int /*sel*/) override {
78 return 0;
79 }
80 void EndMenu() override {}
75}; 81};
76 82
77void 83void
diff --git a/ui.cpp b/ui.cpp
index 2d80c382..f31660db 100644
--- a/ui.cpp
+++ b/ui.cpp
@@ -14,6 +14,8 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17#include "ui.h"
18
17#include <errno.h> 19#include <errno.h>
18#include <fcntl.h> 20#include <fcntl.h>
19#include <linux/input.h> 21#include <linux/input.h>
@@ -28,6 +30,8 @@
28#include <time.h> 30#include <time.h>
29#include <unistd.h> 31#include <unistd.h>
30 32
33#include <string>
34
31#include <android-base/properties.h> 35#include <android-base/properties.h>
32#include <cutils/android_reboot.h> 36#include <cutils/android_reboot.h>
33 37
@@ -35,25 +39,25 @@
35#include "roots.h" 39#include "roots.h"
36#include "device.h" 40#include "device.h"
37#include "minui/minui.h" 41#include "minui/minui.h"
38#include "screen_ui.h"
39#include "ui.h"
40 42
41#define UI_WAIT_KEY_TIMEOUT_SEC 120 43#define UI_WAIT_KEY_TIMEOUT_SEC 120
42 44
43RecoveryUI::RecoveryUI() 45RecoveryUI::RecoveryUI()
44 : key_queue_len(0), 46 : locale_(""),
45 key_last_down(-1), 47 rtl_locale_(false),
46 key_long_press(false), 48 key_queue_len(0),
47 key_down_count(0), 49 key_last_down(-1),
48 enable_reboot(true), 50 key_long_press(false),
49 consecutive_power_keys(0), 51 key_down_count(0),
50 last_key(-1), 52 enable_reboot(true),
51 has_power_key(false), 53 consecutive_power_keys(0),
52 has_up_key(false), 54 last_key(-1),
53 has_down_key(false) { 55 has_power_key(false),
54 pthread_mutex_init(&key_queue_mutex, nullptr); 56 has_up_key(false),
55 pthread_cond_init(&key_queue_cond, nullptr); 57 has_down_key(false) {
56 memset(key_pressed, 0, sizeof(key_pressed)); 58 pthread_mutex_init(&key_queue_mutex, nullptr);
59 pthread_cond_init(&key_queue_cond, nullptr);
60 memset(key_pressed, 0, sizeof(key_pressed));
57} 61}
58 62
59void RecoveryUI::OnKeyDetected(int key_code) { 63void RecoveryUI::OnKeyDetected(int key_code) {
@@ -80,13 +84,16 @@ static void* InputThreadLoop(void*) {
80 return nullptr; 84 return nullptr;
81} 85}
82 86
83bool RecoveryUI::Init() { 87bool RecoveryUI::Init(const std::string& locale) {
84 ev_init(InputCallback, this); 88 // Set up the locale info.
89 SetLocale(locale);
85 90
86 ev_iterate_available_keys(std::bind(&RecoveryUI::OnKeyDetected, this, std::placeholders::_1)); 91 ev_init(InputCallback, this);
87 92
88 pthread_create(&input_thread_, nullptr, InputThreadLoop, nullptr); 93 ev_iterate_available_keys(std::bind(&RecoveryUI::OnKeyDetected, this, std::placeholders::_1));
89 return true; 94
95 pthread_create(&input_thread_, nullptr, InputThreadLoop, nullptr);
96 return true;
90} 97}
91 98
92int RecoveryUI::OnInputEvent(int fd, uint32_t epevents) { 99int RecoveryUI::OnInputEvent(int fd, uint32_t epevents) {
@@ -338,3 +345,23 @@ void RecoveryUI::SetEnableReboot(bool enabled) {
338 enable_reboot = enabled; 345 enable_reboot = enabled;
339 pthread_mutex_unlock(&key_queue_mutex); 346 pthread_mutex_unlock(&key_queue_mutex);
340} 347}
348
349void RecoveryUI::SetLocale(const std::string& new_locale) {
350 this->locale_ = new_locale;
351 this->rtl_locale_ = false;
352
353 if (!new_locale.empty()) {
354 size_t underscore = new_locale.find('_');
355 // lang has the language prefix prior to '_', or full string if '_' doesn't exist.
356 std::string lang = new_locale.substr(0, underscore);
357
358 // A bit cheesy: keep an explicit list of supported RTL languages.
359 if (lang == "ar" || // Arabic
360 lang == "fa" || // Persian (Farsi)
361 lang == "he" || // Hebrew (new language code)
362 lang == "iw" || // Hebrew (old language code)
363 lang == "ur") { // Urdu
364 rtl_locale_ = true;
365 }
366 }
367}
diff --git a/ui.h b/ui.h
index be95a4e2..8493c6f0 100644
--- a/ui.h
+++ b/ui.h
@@ -21,6 +21,8 @@
21#include <pthread.h> 21#include <pthread.h>
22#include <time.h> 22#include <time.h>
23 23
24#include <string>
25
24// Abstract class for controlling the user interface during recovery. 26// Abstract class for controlling the user interface during recovery.
25class RecoveryUI { 27class RecoveryUI {
26 public: 28 public:
@@ -28,14 +30,13 @@ class RecoveryUI {
28 30
29 virtual ~RecoveryUI() { } 31 virtual ~RecoveryUI() { }
30 32
31 // Initialize the object; called before anything else. Returns true on success. 33 // Initialize the object; called before anything else. UI texts will be
32 virtual bool Init(); 34 // initialized according to the given locale. Returns true on success.
35 virtual bool Init(const std::string& locale);
36
33 // Show a stage indicator. Call immediately after Init(). 37 // Show a stage indicator. Call immediately after Init().
34 virtual void SetStage(int current, int max) = 0; 38 virtual void SetStage(int current, int max) = 0;
35 39
36 // After calling Init(), you can tell the UI what locale it is operating in.
37 virtual void SetLocale(const char* locale) = 0;
38
39 // Set the overall recovery state ("background image"). 40 // Set the overall recovery state ("background image").
40 enum Icon { NONE, INSTALLING_UPDATE, ERASING, NO_COMMAND, ERROR }; 41 enum Icon { NONE, INSTALLING_UPDATE, ERASING, NO_COMMAND, ERROR };
41 virtual void SetBackground(Icon icon) = 0; 42 virtual void SetBackground(Icon icon) = 0;
@@ -122,10 +123,14 @@ class RecoveryUI {
122 // statements will be displayed. 123 // statements will be displayed.
123 virtual void EndMenu() = 0; 124 virtual void EndMenu() = 0;
124 125
125protected: 126 protected:
126 void EnqueueKey(int key_code); 127 void EnqueueKey(int key_code);
127 128
128private: 129 // The locale that's used to show the rendered texts.
130 std::string locale_;
131 bool rtl_locale_;
132
133 private:
129 // Key event input queue 134 // Key event input queue
130 pthread_mutex_t key_queue_mutex; 135 pthread_mutex_t key_queue_mutex;
131 pthread_cond_t key_queue_cond; 136 pthread_cond_t key_queue_cond;
@@ -162,6 +167,8 @@ private:
162 167
163 static void* time_key_helper(void* cookie); 168 static void* time_key_helper(void* cookie);
164 void time_key(int key_code, int count); 169 void time_key(int key_code, int count);
170
171 void SetLocale(const std::string&);
165}; 172};
166 173
167#endif // RECOVERY_UI_H 174#endif // RECOVERY_UI_H
diff --git a/wear_ui.cpp b/wear_ui.cpp
index bdb0ef00..b4c63a5a 100644
--- a/wear_ui.cpp
+++ b/wear_ui.cpp
@@ -14,6 +14,8 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17#include "wear_ui.h"
18
17#include <errno.h> 19#include <errno.h>
18#include <fcntl.h> 20#include <fcntl.h>
19#include <stdarg.h> 21#include <stdarg.h>
@@ -25,11 +27,11 @@
25#include <time.h> 27#include <time.h>
26#include <unistd.h> 28#include <unistd.h>
27 29
30#include <string>
28#include <vector> 31#include <vector>
29 32
30#include "common.h" 33#include "common.h"
31#include "device.h" 34#include "device.h"
32#include "wear_ui.h"
33#include "android-base/properties.h" 35#include "android-base/properties.h"
34#include "android-base/strings.h" 36#include "android-base/strings.h"
35#include "android-base/stringprintf.h" 37#include "android-base/stringprintf.h"
@@ -204,51 +206,48 @@ bool WearRecoveryUI::InitTextParams() {
204 return true; 206 return true;
205} 207}
206 208
207bool WearRecoveryUI::Init() { 209bool WearRecoveryUI::Init(const std::string& locale) {
208 if (!ScreenRecoveryUI::Init()) { 210 if (!ScreenRecoveryUI::Init(locale)) {
209 return false; 211 return false;
210 } 212 }
211 213
212 LoadBitmap("icon_error", &backgroundIcon[ERROR]); 214 LoadBitmap("icon_error", &backgroundIcon[ERROR]);
213 backgroundIcon[NO_COMMAND] = backgroundIcon[ERROR]; 215 backgroundIcon[NO_COMMAND] = backgroundIcon[ERROR];
214 216
215 // This leaves backgroundIcon[INSTALLING_UPDATE] and backgroundIcon[ERASING] 217 // This leaves backgroundIcon[INSTALLING_UPDATE] and backgroundIcon[ERASING]
216 // as NULL which is fine since draw_background_locked() doesn't use them. 218 // as NULL which is fine since draw_background_locked() doesn't use them.
217 219
218 return true; 220 return true;
219} 221}
220 222
221void WearRecoveryUI::SetStage(int current, int max) 223void WearRecoveryUI::SetStage(int current, int max) {}
222{
223}
224 224
225void WearRecoveryUI::Print(const char *fmt, ...) 225void WearRecoveryUI::Print(const char* fmt, ...) {
226{ 226 char buf[256];
227 char buf[256]; 227 va_list ap;
228 va_list ap; 228 va_start(ap, fmt);
229 va_start(ap, fmt); 229 vsnprintf(buf, 256, fmt, ap);
230 vsnprintf(buf, 256, fmt, ap); 230 va_end(ap);
231 va_end(ap);
232 231
233 fputs(buf, stdout); 232 fputs(buf, stdout);
234 233
235 // This can get called before ui_init(), so be careful. 234 // This can get called before ui_init(), so be careful.
236 pthread_mutex_lock(&updateMutex); 235 pthread_mutex_lock(&updateMutex);
237 if (text_rows_ > 0 && text_cols_ > 0) { 236 if (text_rows_ > 0 && text_cols_ > 0) {
238 char *ptr; 237 char* ptr;
239 for (ptr = buf; *ptr != '\0'; ++ptr) { 238 for (ptr = buf; *ptr != '\0'; ++ptr) {
240 if (*ptr == '\n' || text_col_ >= text_cols_) { 239 if (*ptr == '\n' || text_col_ >= text_cols_) {
241 text_[text_row_][text_col_] = '\0';
242 text_col_ = 0;
243 text_row_ = (text_row_ + 1) % text_rows_;
244 if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_;
245 }
246 if (*ptr != '\n') text_[text_row_][text_col_++] = *ptr;
247 }
248 text_[text_row_][text_col_] = '\0'; 240 text_[text_row_][text_col_] = '\0';
249 update_screen_locked(); 241 text_col_ = 0;
242 text_row_ = (text_row_ + 1) % text_rows_;
243 if (text_row_ == text_top_) text_top_ = (text_top_ + 1) % text_rows_;
244 }
245 if (*ptr != '\n') text_[text_row_][text_col_++] = *ptr;
250 } 246 }
251 pthread_mutex_unlock(&updateMutex); 247 text_[text_row_][text_col_] = '\0';
248 update_screen_locked();
249 }
250 pthread_mutex_unlock(&updateMutex);
252} 251}
253 252
254void WearRecoveryUI::StartMenu(const char* const * headers, const char* const * items, 253void WearRecoveryUI::StartMenu(const char* const * headers, const char* const * items,
diff --git a/wear_ui.h b/wear_ui.h
index 5ac6f49d..4cd852f2 100644
--- a/wear_ui.h
+++ b/wear_ui.h
@@ -19,11 +19,13 @@
19 19
20#include "screen_ui.h" 20#include "screen_ui.h"
21 21
22#include <string>
23
22class WearRecoveryUI : public ScreenRecoveryUI { 24class WearRecoveryUI : public ScreenRecoveryUI {
23 public: 25 public:
24 WearRecoveryUI(); 26 WearRecoveryUI();
25 27
26 bool Init() override; 28 bool Init(const std::string& locale) override;
27 29
28 void SetStage(int current, int max) override; 30 void SetStage(int current, int max) override;
29 31