|
@@ -42,6 +42,8 @@
|
42
|
42
|
#include <android-base/strings.h>
|
43
|
43
|
#include <minui/minui.h>
|
44
|
44
|
|
|
45
|
+#include <healthd/BatteryMonitor.h>
|
|
46
|
+
|
45
|
47
|
#include "common.h"
|
46
|
48
|
#include "device.h"
|
47
|
49
|
#include "ui.h"
|
|
@@ -53,6 +55,69 @@ static double now() {
|
53
|
55
|
return tv.tv_sec + tv.tv_usec / 1000000.0;
|
54
|
56
|
}
|
55
|
57
|
|
|
58
|
+static void get_battery_status(bool& charged, int& capacity) {
|
|
59
|
+ struct healthd_config healthd_config = {
|
|
60
|
+ .batteryStatusPath = android::String8(android::String8::kEmptyString),
|
|
61
|
+ .batteryHealthPath = android::String8(android::String8::kEmptyString),
|
|
62
|
+ .batteryPresentPath = android::String8(android::String8::kEmptyString),
|
|
63
|
+ .batteryCapacityPath = android::String8(android::String8::kEmptyString),
|
|
64
|
+ .batteryVoltagePath = android::String8(android::String8::kEmptyString),
|
|
65
|
+ .batteryTemperaturePath = android::String8(android::String8::kEmptyString),
|
|
66
|
+ .batteryTechnologyPath = android::String8(android::String8::kEmptyString),
|
|
67
|
+ .batteryCurrentNowPath = android::String8(android::String8::kEmptyString),
|
|
68
|
+ .batteryCurrentAvgPath = android::String8(android::String8::kEmptyString),
|
|
69
|
+ .batteryChargeCounterPath = android::String8(android::String8::kEmptyString),
|
|
70
|
+ .batteryFullChargePath = android::String8(android::String8::kEmptyString),
|
|
71
|
+ .batteryCycleCountPath = android::String8(android::String8::kEmptyString),
|
|
72
|
+ .energyCounter = NULL,
|
|
73
|
+ .boot_min_cap = 0,
|
|
74
|
+ .screen_on = NULL
|
|
75
|
+ };
|
|
76
|
+ healthd_board_init(&healthd_config);
|
|
77
|
+
|
|
78
|
+ android::BatteryMonitor monitor;
|
|
79
|
+ monitor.init(&healthd_config);
|
|
80
|
+
|
|
81
|
+ int charge_status = monitor.getChargeStatus();
|
|
82
|
+ // Treat unknown status as charged.
|
|
83
|
+ charged = (charge_status != android::BATTERY_STATUS_DISCHARGING &&
|
|
84
|
+ charge_status != android::BATTERY_STATUS_NOT_CHARGING);
|
|
85
|
+ android::BatteryProperty prop;
|
|
86
|
+ android::status_t status = monitor.getProperty(android::BATTERY_PROP_CAPACITY, &prop);
|
|
87
|
+ // If we can't read battery percentage, it may be a device without battery. In this
|
|
88
|
+ // situation, use 100 as a fake battery percentage.
|
|
89
|
+ if (status != 0) {
|
|
90
|
+ prop.valueInt64 = 100;
|
|
91
|
+ }
|
|
92
|
+ capacity = (int)prop.valueInt64;
|
|
93
|
+}
|
|
94
|
+
|
|
95
|
+ScreenMenuItem::~ScreenMenuItem() {
|
|
96
|
+ if (icon_) {
|
|
97
|
+ res_free_surface(icon_);
|
|
98
|
+ }
|
|
99
|
+ if (icon_sel_) {
|
|
100
|
+ res_free_surface(icon_sel_);
|
|
101
|
+ }
|
|
102
|
+}
|
|
103
|
+
|
|
104
|
+GRSurface* ScreenMenuItem::icon() {
|
|
105
|
+ if (!icon_) {
|
|
106
|
+ res_create_display_surface(icon_name_.c_str(), &icon_);
|
|
107
|
+ }
|
|
108
|
+ return icon_;
|
|
109
|
+}
|
|
110
|
+
|
|
111
|
+GRSurface* ScreenMenuItem::icon_sel() {
|
|
112
|
+ if (icon_name_sel_.empty()) {
|
|
113
|
+ return icon();
|
|
114
|
+ }
|
|
115
|
+ if (!icon_sel_) {
|
|
116
|
+ res_create_display_surface(icon_name_sel_.c_str(), &icon_sel_);
|
|
117
|
+ }
|
|
118
|
+ return icon_sel_;
|
|
119
|
+}
|
|
120
|
+
|
56
|
121
|
ScreenRecoveryUI::ScreenRecoveryUI()
|
57
|
122
|
: kMarginWidth(RECOVERY_UI_MARGIN_WIDTH),
|
58
|
123
|
kMarginHeight(RECOVERY_UI_MARGIN_HEIGHT),
|
|
@@ -71,9 +136,13 @@ ScreenRecoveryUI::ScreenRecoveryUI()
|
71
|
136
|
text_row_(0),
|
72
|
137
|
show_text(false),
|
73
|
138
|
show_text_ever(false),
|
|
139
|
+ menu_is_main_(true),
|
|
140
|
+ menu_type_(MT_NONE),
|
74
|
141
|
menu_headers_(nullptr),
|
|
142
|
+ menu_start_y_(0),
|
75
|
143
|
show_menu(false),
|
76
|
|
- menu_items(0),
|
|
144
|
+ menu_show_start(0),
|
|
145
|
+ menu_show_count(0),
|
77
|
146
|
menu_sel(0),
|
78
|
147
|
file_viewer_text_(nullptr),
|
79
|
148
|
intro_frames(0),
|
|
@@ -183,7 +252,7 @@ void ScreenRecoveryUI::draw_background_locked() {
|
183
|
252
|
// Draws the animation and progress bar (if any) on the screen. Does not flip pages. Should only be
|
184
|
253
|
// called with updateMutex locked.
|
185
|
254
|
void ScreenRecoveryUI::draw_foreground_locked() {
|
186
|
|
- if (currentIcon != NONE) {
|
|
255
|
+ if (currentIcon != NONE && currentIcon != NO_COMMAND) {
|
187
|
256
|
gr_color(0, 0, 0, 255);
|
188
|
257
|
gr_clear();
|
189
|
258
|
GRSurface* frame = GetCurrentFrame();
|
|
@@ -231,8 +300,12 @@ void ScreenRecoveryUI::draw_foreground_locked() {
|
231
|
300
|
}
|
232
|
301
|
}
|
233
|
302
|
|
|
303
|
+/* Lineage teal: #167c80 */
|
234
|
304
|
void ScreenRecoveryUI::SetColor(UIElement e) const {
|
235
|
305
|
switch (e) {
|
|
306
|
+ case STATUSBAR:
|
|
307
|
+ gr_color(255, 255, 255, 255);
|
|
308
|
+ break;
|
236
|
309
|
case INFO:
|
237
|
310
|
gr_color(249, 194, 0, 255);
|
238
|
311
|
break;
|
|
@@ -241,13 +314,13 @@ void ScreenRecoveryUI::SetColor(UIElement e) const {
|
241
|
314
|
break;
|
242
|
315
|
case MENU:
|
243
|
316
|
case MENU_SEL_BG:
|
244
|
|
- gr_color(106, 103, 102, 255);
|
|
317
|
+ gr_color(0xd8, 0xd8, 0xd8, 255);
|
245
|
318
|
break;
|
246
|
319
|
case MENU_SEL_BG_ACTIVE:
|
247
|
320
|
gr_color(138, 135, 134, 255);
|
248
|
321
|
break;
|
249
|
322
|
case MENU_SEL_FG:
|
250
|
|
- gr_color(0, 177, 229, 255);
|
|
323
|
+ gr_color(0x16, 0x7c, 0x80, 255);
|
251
|
324
|
break;
|
252
|
325
|
case LOG:
|
253
|
326
|
gr_color(196, 196, 196, 255);
|
|
@@ -321,13 +394,16 @@ void ScreenRecoveryUI::CheckBackgroundTextImages(const std::string& saved_locale
|
321
|
394
|
|
322
|
395
|
FlushKeys();
|
323
|
396
|
while (true) {
|
324
|
|
- int key = WaitKey();
|
325
|
|
- if (key == KEY_POWER || key == KEY_ENTER) {
|
|
397
|
+ RecoveryUI::InputEvent evt = WaitInputEvent();
|
|
398
|
+ if (evt.type() != RecoveryUI::EVENT_TYPE_KEY) {
|
326
|
399
|
break;
|
327
|
|
- } else if (key == KEY_UP || key == KEY_VOLUMEUP) {
|
|
400
|
+ }
|
|
401
|
+ if (evt.key() == KEY_POWER || evt.key() == KEY_ENTER) {
|
|
402
|
+ break;
|
|
403
|
+ } else if (evt.key() == KEY_UP || evt.key() == KEY_VOLUMEUP) {
|
328
|
404
|
selected = (selected == 0) ? locales_entries.size() - 1 : selected - 1;
|
329
|
405
|
SelectAndShowBackgroundText(locales_entries, selected);
|
330
|
|
- } else if (key == KEY_DOWN || key == KEY_VOLUMEDOWN) {
|
|
406
|
+ } else if (evt.key() == KEY_DOWN || evt.key() == KEY_VOLUMEDOWN) {
|
331
|
407
|
selected = (selected == locales_entries.size() - 1) ? 0 : selected + 1;
|
332
|
408
|
SelectAndShowBackgroundText(locales_entries, selected);
|
333
|
409
|
}
|
|
@@ -401,22 +477,216 @@ int ScreenRecoveryUI::DrawWrappedTextLines(int x, int y, const char* const* line
|
401
|
477
|
next_start += last_space + 1;
|
402
|
478
|
}
|
403
|
479
|
}
|
404
|
|
- offset += DrawTextLine(x, y + offset, sub.c_str(), false);
|
|
480
|
+ gr_text(gr_menu_font(), x, y + offset, sub.c_str(), false);
|
|
481
|
+ offset += menu_char_height_ + 4;
|
405
|
482
|
}
|
406
|
483
|
}
|
407
|
484
|
return offset;
|
408
|
485
|
}
|
409
|
486
|
|
410
|
|
-static const char* REGULAR_HELP[] = {
|
411
|
|
- "Use volume up/down and power.",
|
412
|
|
- NULL
|
413
|
|
-};
|
|
487
|
+void ScreenRecoveryUI::draw_statusbar_locked() {
|
|
488
|
+ int y = kMarginHeight;
|
|
489
|
+ int x;
|
|
490
|
+
|
|
491
|
+ int icon_x, icon_y, icon_h, icon_w;
|
|
492
|
+
|
|
493
|
+ // Local time
|
|
494
|
+ char localtm_str[] = "--:--";
|
|
495
|
+ time_t now;
|
|
496
|
+ struct tm localtm;
|
|
497
|
+ time(&now);
|
|
498
|
+ if (now > TV_MIN) {
|
|
499
|
+ localtime_r(&now, &localtm);
|
|
500
|
+ snprintf(localtm_str, sizeof(localtm_str), "%02d:%02d",
|
|
501
|
+ localtm.tm_hour, localtm.tm_min);
|
|
502
|
+ }
|
414
|
503
|
|
415
|
|
-static const char* LONG_PRESS_HELP[] = {
|
416
|
|
- "Any button cycles highlight.",
|
417
|
|
- "Long-press activates.",
|
418
|
|
- NULL
|
419
|
|
-};
|
|
504
|
+ // Battery status
|
|
505
|
+ bool batt_charged;
|
|
506
|
+ int batt_capacity;
|
|
507
|
+ get_battery_status(batt_charged, batt_capacity);
|
|
508
|
+ char batt_capacity_str[3+1+1];
|
|
509
|
+ snprintf(batt_capacity_str, sizeof(batt_capacity_str), "%d%%", batt_capacity);
|
|
510
|
+
|
|
511
|
+ // Draw status bar from right to left
|
|
512
|
+
|
|
513
|
+ // Time
|
|
514
|
+ SetColor(STATUSBAR);
|
|
515
|
+ x = gr_fb_width();
|
|
516
|
+ x -= 5 * char_width_;
|
|
517
|
+ gr_text(gr_sys_font(), x, y, localtm_str, false);
|
|
518
|
+
|
|
519
|
+ x -= char_width_; // Separator
|
|
520
|
+
|
|
521
|
+ // Battery icon
|
|
522
|
+ x -= 1 * char_width_;
|
|
523
|
+ SetColor((batt_capacity < 20) ? HEADER : STATUSBAR);
|
|
524
|
+
|
|
525
|
+ // Top
|
|
526
|
+ icon_x = x + char_width_ / 3;
|
|
527
|
+ icon_y = y;
|
|
528
|
+ icon_w = char_width_ / 3;
|
|
529
|
+ icon_h = char_height_ / 12;
|
|
530
|
+ gr_fill(icon_x, icon_y, icon_x + icon_w, icon_y + icon_h);
|
|
531
|
+
|
|
532
|
+ // Main rect
|
|
533
|
+ icon_x = x;
|
|
534
|
+ icon_y = y + icon_h;
|
|
535
|
+ icon_w = char_width_;
|
|
536
|
+ icon_h = char_height_ - (char_height_ / 12);
|
|
537
|
+ gr_fill(icon_x, icon_y, icon_x + icon_w, icon_y + icon_h);
|
|
538
|
+
|
|
539
|
+ // Capacity
|
|
540
|
+ icon_x = x + char_width_ / 6;
|
|
541
|
+ icon_y = y + char_height_ / 12;
|
|
542
|
+ icon_w = char_width_ - (2 * char_width_ / 6);
|
|
543
|
+ icon_h = char_height_ - (3 * char_height_ / 12);
|
|
544
|
+ int cap_h = icon_h * batt_capacity / 100;
|
|
545
|
+ gr_fill(icon_x, icon_y + icon_h - cap_h, icon_x + icon_w, icon_y + icon_h);
|
|
546
|
+ gr_color(0, 0, 0, 255);
|
|
547
|
+ gr_fill(icon_x, icon_y, icon_x + icon_w, icon_y + icon_h - cap_h);
|
|
548
|
+ SetColor(STATUSBAR);
|
|
549
|
+
|
|
550
|
+ x -= char_width_; // Separator
|
|
551
|
+
|
|
552
|
+ // Battery text
|
|
553
|
+ x -= strlen(batt_capacity_str) * char_width_;
|
|
554
|
+ gr_text(gr_sys_font(), x, y, batt_capacity_str, false);
|
|
555
|
+}
|
|
556
|
+
|
|
557
|
+/*
|
|
558
|
+ * Header layout:
|
|
559
|
+ * * 1/32: Status bar
|
|
560
|
+ * * Header image
|
|
561
|
+ * * 1/32: Margin
|
|
562
|
+ */
|
|
563
|
+void ScreenRecoveryUI::draw_header_locked(int& y) {
|
|
564
|
+ int h_unit = gr_fb_width() / 9;
|
|
565
|
+ int v_unit = gr_fb_height() / 16;
|
|
566
|
+
|
|
567
|
+ GRSurface* icon;
|
|
568
|
+ int icon_x, icon_y, icon_h, icon_w;
|
|
569
|
+
|
|
570
|
+ y += v_unit / 2; // Margin
|
|
571
|
+
|
|
572
|
+ // Draw back icon if not in main menu
|
|
573
|
+ if (!menu_is_main_) {
|
|
574
|
+ icon = (menu_sel == -1 ? ic_back_sel : ic_back);
|
|
575
|
+ icon_w = gr_get_width(icon);
|
|
576
|
+ icon_h = gr_get_height(icon);
|
|
577
|
+ icon_x = kMarginWidth + (h_unit / 2) + ((h_unit * 1) - icon_w) / 2;
|
|
578
|
+ icon_y = y + ((v_unit * 1) - icon_h) / 2;
|
|
579
|
+ gr_blit(icon, 0, 0, icon_w, icon_h, icon_x, icon_y);
|
|
580
|
+ }
|
|
581
|
+ y += v_unit;
|
|
582
|
+
|
|
583
|
+ // Draw logo
|
|
584
|
+ icon = logo_image;
|
|
585
|
+ icon_w = gr_get_width(icon);
|
|
586
|
+ icon_h = gr_get_height(icon);
|
|
587
|
+ icon_x = kMarginWidth + (gr_fb_width() - icon_w) / 2;
|
|
588
|
+ icon_y = y + ((v_unit * 4) - icon_h) / 2;
|
|
589
|
+ gr_blit(icon, 0, 0, icon_w, icon_h, icon_x, icon_y);
|
|
590
|
+ y += v_unit * 4;
|
|
591
|
+
|
|
592
|
+ y += v_unit * 1; // Margin
|
|
593
|
+}
|
|
594
|
+
|
|
595
|
+void ScreenRecoveryUI::draw_text_menu_locked(int& y) {
|
|
596
|
+ static constexpr int kMenuIndent = 4;
|
|
597
|
+ int x = kMarginWidth + kMenuIndent;
|
|
598
|
+
|
|
599
|
+ draw_statusbar_locked();
|
|
600
|
+ draw_header_locked(y);
|
|
601
|
+
|
|
602
|
+ if (menu_headers_) {
|
|
603
|
+ SetColor(HEADER);
|
|
604
|
+ // Ignore kMenuIndent, which is not taken into account by text_cols_.
|
|
605
|
+ y += DrawWrappedTextLines(kMarginWidth, y, menu_headers_);
|
|
606
|
+
|
|
607
|
+ SetColor(MENU);
|
|
608
|
+ y += DrawHorizontalRule(y) + 4;
|
|
609
|
+ }
|
|
610
|
+
|
|
611
|
+ menu_start_y_ = y;
|
|
612
|
+ int i;
|
|
613
|
+ for (i = menu_show_start; i < (int)menu_items_.size() && y < gr_fb_height(); ++i) {
|
|
614
|
+ const ScreenMenuItem& item = menu_items_.at(i);
|
|
615
|
+ if (i == menu_sel) {
|
|
616
|
+ SetColor(MENU_SEL_FG);
|
|
617
|
+ y += menu_char_height_;
|
|
618
|
+ gr_text(gr_menu_font(), x, y, item.text().c_str(), false);
|
|
619
|
+ y += menu_char_height_;
|
|
620
|
+ y += menu_char_height_;
|
|
621
|
+ } else {
|
|
622
|
+ SetColor(MENU);
|
|
623
|
+ y += menu_char_height_;
|
|
624
|
+ gr_text(gr_menu_font(), x, y, item.text().c_str(), false);
|
|
625
|
+ y += menu_char_height_;
|
|
626
|
+ y += menu_char_height_;
|
|
627
|
+ }
|
|
628
|
+ }
|
|
629
|
+ menu_show_count = i - menu_show_start;
|
|
630
|
+}
|
|
631
|
+
|
|
632
|
+/*
|
|
633
|
+ * Grid layout.
|
|
634
|
+ *
|
|
635
|
+ * Grid item:
|
|
636
|
+ * Horizontal:
|
|
637
|
+ * * 3/9 of screen per item.
|
|
638
|
+ * * 1/9 of screen margin around/between items.
|
|
639
|
+ * Vertical:
|
|
640
|
+ * * 3/16 of screen per item.
|
|
641
|
+ * * No margin between items.
|
|
642
|
+ *
|
|
643
|
+ * Within a grid item:
|
|
644
|
+ * Asher's icons 1/5 of grid both dimensions.
|
|
645
|
+ * Current icons 2/5 of grid both dimensions.
|
|
646
|
+ * Horizontal:
|
|
647
|
+ * * All items centered.
|
|
648
|
+ * Vertical:
|
|
649
|
+ * * Icon lower aligned in top 2/3.
|
|
650
|
+ * * Text upper aligned in low 1/3 plus half line margin.
|
|
651
|
+ */
|
|
652
|
+void ScreenRecoveryUI::draw_grid_menu_locked(int& y) {
|
|
653
|
+ int h_unit = gr_fb_width() / 9;
|
|
654
|
+ int v_unit = gr_fb_height() / 16;
|
|
655
|
+
|
|
656
|
+ int grid_w = h_unit * 3;
|
|
657
|
+ int grid_h = v_unit * 3;
|
|
658
|
+
|
|
659
|
+ draw_statusbar_locked();
|
|
660
|
+ draw_header_locked(y);
|
|
661
|
+
|
|
662
|
+ menu_start_y_ = y;
|
|
663
|
+ int i;
|
|
664
|
+ for (i = menu_show_start; i < (int)menu_items_.size() && y + grid_h < gr_fb_height(); ++i) {
|
|
665
|
+ ScreenMenuItem& item = menu_items_.at(i);
|
|
666
|
+ int grid_x = kMarginWidth + ((i % 2) ? h_unit * 5 : h_unit * 1);
|
|
667
|
+ int grid_y = y;
|
|
668
|
+ if (item.icon()) {
|
|
669
|
+ GRSurface* icon = (i == menu_sel) ? item.icon_sel() : item.icon();
|
|
670
|
+ int icon_w = gr_get_width(icon);
|
|
671
|
+ int icon_h = gr_get_height(icon);
|
|
672
|
+ int icon_x = grid_x + (grid_w - icon_w) / 2;
|
|
673
|
+ int icon_y = grid_y + ((grid_h * 2 / 3) - icon_h) / 2;
|
|
674
|
+ gr_blit(icon, 0, 0, icon_w, icon_h, icon_x, icon_y);
|
|
675
|
+ }
|
|
676
|
+ if (!item.text().empty()) {
|
|
677
|
+ int text_w = item.text().size() * char_width_;
|
|
678
|
+ int text_x = grid_x + (grid_w - text_w) / 2;
|
|
679
|
+ int text_y = grid_y + (grid_h * 2 / 3) + (char_height_ / 2);
|
|
680
|
+ SetColor(i == menu_sel ? MENU_SEL_FG : MENU);
|
|
681
|
+ gr_text(gr_sys_font(), text_x, text_y, item.text().c_str(), false);
|
|
682
|
+ }
|
|
683
|
+ if (i % 2) {
|
|
684
|
+ y += grid_h;
|
|
685
|
+ grid_y = y;
|
|
686
|
+ }
|
|
687
|
+ }
|
|
688
|
+ menu_show_count = i - menu_show_start;
|
|
689
|
+}
|
420
|
690
|
|
421
|
691
|
// Redraws everything on the screen. Does not flip pages. Should only be called with updateMutex
|
422
|
692
|
// locked.
|
|
@@ -432,50 +702,41 @@ void ScreenRecoveryUI::draw_screen_locked() {
|
432
|
702
|
|
433
|
703
|
int y = kMarginHeight;
|
434
|
704
|
if (show_menu) {
|
435
|
|
- static constexpr int kMenuIndent = 4;
|
436
|
|
- int x = kMarginWidth + kMenuIndent;
|
437
|
|
-
|
438
|
|
- SetColor(INFO);
|
439
|
|
- y += DrawTextLine(x, y, "Android Recovery", true);
|
440
|
|
- std::string recovery_fingerprint =
|
441
|
|
- android::base::GetProperty("ro.bootimage.build.fingerprint", "");
|
442
|
|
- for (const auto& chunk : android::base::Split(recovery_fingerprint, ":")) {
|
443
|
|
- y += DrawTextLine(x, y, chunk.c_str(), false);
|
|
705
|
+ switch (menu_type_) {
|
|
706
|
+ case MT_LIST:
|
|
707
|
+ draw_text_menu_locked(y);
|
|
708
|
+ break;
|
|
709
|
+ case MT_GRID:
|
|
710
|
+ draw_grid_menu_locked(y);
|
|
711
|
+ break;
|
|
712
|
+ default:
|
|
713
|
+ break;
|
444
|
714
|
}
|
445
|
|
- y += DrawTextLines(x, y, HasThreeButtons() ? REGULAR_HELP : LONG_PRESS_HELP);
|
446
|
715
|
|
447
|
|
- SetColor(HEADER);
|
448
|
|
- // Ignore kMenuIndent, which is not taken into account by text_cols_.
|
449
|
|
- y += DrawWrappedTextLines(kMarginWidth, y, menu_headers_);
|
450
|
|
-
|
451
|
|
- SetColor(MENU);
|
452
|
|
- y += DrawHorizontalRule(y) + 4;
|
453
|
|
- for (int i = 0; i < menu_items; ++i) {
|
454
|
|
- if (i == menu_sel) {
|
455
|
|
- // Draw the highlight bar.
|
456
|
|
- SetColor(IsLongPress() ? MENU_SEL_BG_ACTIVE : MENU_SEL_BG);
|
457
|
|
- DrawHighlightBar(0, y - 2, ScreenWidth(), char_height_ + 4);
|
458
|
|
- // Bold white text for the selected item.
|
459
|
|
- SetColor(MENU_SEL_FG);
|
460
|
|
- y += DrawTextLine(x, y, menu_[i].c_str(), true);
|
461
|
|
- SetColor(MENU);
|
462
|
|
- } else {
|
463
|
|
- y += DrawTextLine(x, y, menu_[i].c_str(), false);
|
464
|
|
- }
|
|
716
|
+ // Draw version info
|
|
717
|
+ if (menu_is_main_) {
|
|
718
|
+ int text_x, text_y;
|
|
719
|
+ text_x = kMarginWidth + (gr_fb_width() - (android_version_.size() * char_width_)) / 2;
|
|
720
|
+ text_y = gr_fb_height() - 2 * (char_height_ + 4);
|
|
721
|
+ SetColor(MENU);
|
|
722
|
+ DrawTextLine(text_x, text_y, android_version_.c_str(), false);
|
|
723
|
+ text_x = kMarginWidth + (gr_fb_width() - (lineage_version_.size() * char_width_)) / 2;
|
|
724
|
+ text_y = gr_fb_height() - 1 * (char_height_ + 4);
|
|
725
|
+ DrawTextLine(text_x, text_y, lineage_version_.c_str(), false);
|
465
|
726
|
}
|
466
|
|
- y += DrawHorizontalRule(y);
|
467
|
727
|
}
|
468
|
|
-
|
469
|
|
- // Display from the bottom up, until we hit the top of the screen, the bottom of the menu, or
|
470
|
|
- // we've displayed the entire text buffer.
|
471
|
|
- SetColor(LOG);
|
472
|
|
- int row = text_row_;
|
473
|
|
- size_t count = 0;
|
474
|
|
- for (int ty = ScreenHeight() - kMarginHeight - char_height_; ty >= y && count < text_rows_;
|
475
|
|
- ty -= char_height_, ++count) {
|
476
|
|
- DrawTextLine(kMarginWidth, ty, text_[row], false);
|
477
|
|
- --row;
|
478
|
|
- if (row < 0) row = text_rows_ - 1;
|
|
728
|
+ else {
|
|
729
|
+ // Display from the bottom up, until we hit the top of the screen, the bottom of the menu, or
|
|
730
|
+ // we've displayed the entire text buffer.
|
|
731
|
+ SetColor(LOG);
|
|
732
|
+ int row = (text_rows_ - 1) % text_rows_;
|
|
733
|
+ size_t count = 0;
|
|
734
|
+ for (int ty = gr_fb_height() - kMarginHeight - char_height_; ty >= y && count < text_rows_;
|
|
735
|
+ ty -= char_height_, ++count) {
|
|
736
|
+ DrawTextLine(kMarginWidth, ty, text_[row], false);
|
|
737
|
+ --row;
|
|
738
|
+ if (row < 0) row = text_rows_ - 1;
|
|
739
|
+ }
|
479
|
740
|
}
|
480
|
741
|
}
|
481
|
742
|
|
|
@@ -558,6 +819,10 @@ void ScreenRecoveryUI::LoadBitmap(const char* filename, GRSurface** surface) {
|
558
|
819
|
}
|
559
|
820
|
}
|
560
|
821
|
|
|
822
|
+void ScreenRecoveryUI::FreeBitmap(GRSurface* surface) {
|
|
823
|
+ res_free_surface(surface);
|
|
824
|
+}
|
|
825
|
+
|
561
|
826
|
void ScreenRecoveryUI::LoadLocalizedBitmap(const char* filename, GRSurface** surface) {
|
562
|
827
|
int result = res_create_localized_alpha_surface(filename, locale_.c_str(), surface);
|
563
|
828
|
if (result < 0) {
|
|
@@ -590,6 +855,7 @@ bool ScreenRecoveryUI::InitTextParams() {
|
590
|
855
|
}
|
591
|
856
|
|
592
|
857
|
gr_font_size(gr_sys_font(), &char_width_, &char_height_);
|
|
858
|
+ gr_font_size(gr_menu_font(), &menu_char_width_, &menu_char_height_);
|
593
|
859
|
text_rows_ = (ScreenHeight() - kMarginHeight * 2) / char_height_;
|
594
|
860
|
text_cols_ = (ScreenWidth() - kMarginWidth * 2) / char_width_;
|
595
|
861
|
return true;
|
|
@@ -615,6 +881,10 @@ bool ScreenRecoveryUI::Init(const std::string& locale) {
|
615
|
881
|
// Set up the locale info.
|
616
|
882
|
SetLocale(locale);
|
617
|
883
|
|
|
884
|
+ LoadBitmap("logo_image", &logo_image);
|
|
885
|
+ LoadBitmap("ic_back", &ic_back);
|
|
886
|
+ LoadBitmap("ic_back_sel", &ic_back_sel);
|
|
887
|
+
|
618
|
888
|
LoadBitmap("icon_error", &error_icon);
|
619
|
889
|
|
620
|
890
|
LoadBitmap("progress_empty", &progressBarEmpty);
|
|
@@ -681,8 +951,10 @@ void ScreenRecoveryUI::LoadAnimation() {
|
681
|
951
|
void ScreenRecoveryUI::SetBackground(Icon icon) {
|
682
|
952
|
pthread_mutex_lock(&updateMutex);
|
683
|
953
|
|
684
|
|
- currentIcon = icon;
|
685
|
|
- update_screen_locked();
|
|
954
|
+ if (icon != currentIcon) {
|
|
955
|
+ currentIcon = icon;
|
|
956
|
+ update_screen_locked();
|
|
957
|
+ }
|
686
|
958
|
|
687
|
959
|
pthread_mutex_unlock(&updateMutex);
|
688
|
960
|
}
|
|
@@ -795,7 +1067,7 @@ void ScreenRecoveryUI::ClearText() {
|
795
|
1067
|
pthread_mutex_unlock(&updateMutex);
|
796
|
1068
|
}
|
797
|
1069
|
|
798
|
|
-void ScreenRecoveryUI::ShowFile(FILE* fp) {
|
|
1070
|
+int ScreenRecoveryUI::ShowFile(FILE* fp) {
|
799
|
1071
|
std::vector<off_t> offsets;
|
800
|
1072
|
offsets.push_back(ftello(fp));
|
801
|
1073
|
ClearText();
|
|
@@ -812,10 +1084,16 @@ void ScreenRecoveryUI::ShowFile(FILE* fp) {
|
812
|
1084
|
Redraw();
|
813
|
1085
|
while (show_prompt) {
|
814
|
1086
|
show_prompt = false;
|
815
|
|
- int key = WaitKey();
|
816
|
|
- if (key == KEY_POWER || key == KEY_ENTER) {
|
817
|
|
- return;
|
818
|
|
- } else if (key == KEY_UP || key == KEY_VOLUMEUP) {
|
|
1087
|
+ RecoveryUI::InputEvent evt = WaitInputEvent();
|
|
1088
|
+ if (evt.type() != RecoveryUI::EVENT_TYPE_KEY) {
|
|
1089
|
+ show_prompt = true;
|
|
1090
|
+ continue;
|
|
1091
|
+ }
|
|
1092
|
+ if (evt.key() == KEY_POWER || evt.key() == KEY_ENTER ||
|
|
1093
|
+ evt.key() == KEY_BACKSPACE || evt.key() == KEY_BACK ||
|
|
1094
|
+ evt.key() == KEY_HOME || evt.key() == KEY_HOMEPAGE) {
|
|
1095
|
+ return evt.key();
|
|
1096
|
+ } else if (evt.key() == KEY_UP || evt.key() == KEY_VOLUMEUP) {
|
819
|
1097
|
if (offsets.size() <= 1) {
|
820
|
1098
|
show_prompt = true;
|
821
|
1099
|
} else {
|
|
@@ -824,7 +1102,7 @@ void ScreenRecoveryUI::ShowFile(FILE* fp) {
|
824
|
1102
|
}
|
825
|
1103
|
} else {
|
826
|
1104
|
if (feof(fp)) {
|
827
|
|
- return;
|
|
1105
|
+ return -1;
|
828
|
1106
|
}
|
829
|
1107
|
offsets.push_back(ftello(fp));
|
830
|
1108
|
}
|
|
@@ -843,13 +1121,14 @@ void ScreenRecoveryUI::ShowFile(FILE* fp) {
|
843
|
1121
|
}
|
844
|
1122
|
}
|
845
|
1123
|
}
|
|
1124
|
+ return -1;
|
846
|
1125
|
}
|
847
|
1126
|
|
848
|
|
-void ScreenRecoveryUI::ShowFile(const char* filename) {
|
|
1127
|
+int ScreenRecoveryUI::ShowFile(const char* filename) {
|
849
|
1128
|
FILE* fp = fopen_path(filename, "re");
|
850
|
1129
|
if (fp == nullptr) {
|
851
|
1130
|
Print(" Unable to open %s: %s\n", filename, strerror(errno));
|
852
|
|
- return;
|
|
1131
|
+ return -1;
|
853
|
1132
|
}
|
854
|
1133
|
|
855
|
1134
|
char** old_text = text_;
|
|
@@ -860,43 +1139,106 @@ void ScreenRecoveryUI::ShowFile(const char* filename) {
|
860
|
1139
|
text_ = file_viewer_text_;
|
861
|
1140
|
ClearText();
|
862
|
1141
|
|
863
|
|
- ShowFile(fp);
|
|
1142
|
+ int key = ShowFile(fp);
|
864
|
1143
|
fclose(fp);
|
865
|
1144
|
|
866
|
1145
|
text_ = old_text;
|
867
|
1146
|
text_col_ = old_text_col;
|
868
|
1147
|
text_row_ = old_text_row;
|
|
1148
|
+ return key;
|
869
|
1149
|
}
|
870
|
1150
|
|
871
|
|
-void ScreenRecoveryUI::StartMenu(const char* const* headers, const char* const* items,
|
|
1151
|
+void ScreenRecoveryUI::StartMenu(bool is_main,
|
|
1152
|
+ menu_type_t type,
|
|
1153
|
+ const char* const* headers,
|
|
1154
|
+ const MenuItemVector& items,
|
872
|
1155
|
int initial_selection) {
|
873
|
1156
|
pthread_mutex_lock(&updateMutex);
|
874
|
|
- if (text_rows_ > 0 && text_cols_ > 0) {
|
875
|
|
- menu_headers_ = headers;
|
876
|
|
- menu_.clear();
|
877
|
|
- for (size_t i = 0; i < text_rows_ && items[i] != nullptr; ++i) {
|
878
|
|
- menu_.emplace_back(std::string(items[i], strnlen(items[i], text_cols_ - 1)));
|
879
|
|
- }
|
880
|
|
- menu_items = static_cast<int>(menu_.size());
|
881
|
|
- show_menu = true;
|
882
|
|
- menu_sel = initial_selection;
|
883
|
|
- update_screen_locked();
|
|
1157
|
+ menu_is_main_ = is_main;
|
|
1158
|
+ menu_type_ = type;
|
|
1159
|
+ menu_headers_ = headers;
|
|
1160
|
+ for (auto& item : items) {
|
|
1161
|
+ menu_items_.push_back(ScreenMenuItem(item));
|
884
|
1162
|
}
|
|
1163
|
+ show_menu = true;
|
|
1164
|
+ menu_sel = initial_selection;
|
|
1165
|
+ draw_screen_locked();
|
|
1166
|
+ if (menu_sel < menu_show_start) {
|
|
1167
|
+ menu_show_start = menu_sel;
|
|
1168
|
+ }
|
|
1169
|
+ if (menu_sel >= menu_show_start + menu_show_count) {
|
|
1170
|
+ menu_show_start = menu_sel - (menu_show_count - 1);
|
|
1171
|
+ }
|
|
1172
|
+ update_screen_locked();
|
885
|
1173
|
pthread_mutex_unlock(&updateMutex);
|
886
|
1174
|
}
|
887
|
1175
|
|
888
|
1176
|
int ScreenRecoveryUI::SelectMenu(int sel) {
|
889
|
1177
|
pthread_mutex_lock(&updateMutex);
|
890
|
1178
|
if (show_menu) {
|
891
|
|
- int old_sel = menu_sel;
|
|
1179
|
+ int old_menu_sel = menu_sel;
|
|
1180
|
+
|
|
1181
|
+ // Handle wrapping and back item
|
|
1182
|
+ if (sel < 0 && (menu_is_main_ || sel < -1)) {
|
|
1183
|
+ sel = (int)menu_items_.size() - 1;
|
|
1184
|
+ }
|
|
1185
|
+ if (sel >= (int)menu_items_.size()) {
|
|
1186
|
+ sel = (menu_is_main_ ? 0 : -1);
|
|
1187
|
+ }
|
892
|
1188
|
menu_sel = sel;
|
893
|
1189
|
|
894
|
|
- // Wrap at top and bottom.
|
895
|
|
- if (menu_sel < 0) menu_sel = menu_items - 1;
|
896
|
|
- if (menu_sel >= menu_items) menu_sel = 0;
|
|
1190
|
+ // Scroll
|
|
1191
|
+ if (menu_sel != -1 && sel < menu_show_start) {
|
|
1192
|
+ menu_show_start = sel;
|
|
1193
|
+ }
|
|
1194
|
+ if (sel >= menu_show_start + menu_show_count) {
|
|
1195
|
+ menu_show_start = sel - (menu_show_count - 1);
|
|
1196
|
+ }
|
|
1197
|
+
|
|
1198
|
+ if (menu_sel != old_menu_sel) update_screen_locked();
|
|
1199
|
+ }
|
|
1200
|
+ pthread_mutex_unlock(&updateMutex);
|
|
1201
|
+ return sel;
|
|
1202
|
+}
|
897
|
1203
|
|
898
|
|
- sel = menu_sel;
|
899
|
|
- if (menu_sel != old_sel) update_screen_locked();
|
|
1204
|
+int ScreenRecoveryUI::SelectMenu(const Point& point) {
|
|
1205
|
+ int sel = Device::kNoAction;
|
|
1206
|
+ int h_unit = gr_fb_width() / 9;
|
|
1207
|
+ int v_unit = gr_fb_height() / 16;
|
|
1208
|
+ pthread_mutex_lock(&updateMutex);
|
|
1209
|
+ if (show_menu) {
|
|
1210
|
+ if (point.y() < menu_start_y_) {
|
|
1211
|
+ if (!menu_is_main_ &&
|
|
1212
|
+ point.x() >= h_unit / 2 && point.x() < h_unit * 3 / 2 &&
|
|
1213
|
+ point.y() >= v_unit * 1 / 2 && point.y() < v_unit * 3 / 2) {
|
|
1214
|
+ sel = Device::kGoBack;
|
|
1215
|
+ }
|
|
1216
|
+ }
|
|
1217
|
+ else {
|
|
1218
|
+ int row = -1, col = -1;
|
|
1219
|
+ switch (menu_type_) {
|
|
1220
|
+ case MT_LIST:
|
|
1221
|
+ sel = (point.y() - menu_start_y_) / (menu_char_height_ * 3);
|
|
1222
|
+ break;
|
|
1223
|
+ case MT_GRID:
|
|
1224
|
+ row = (point.y() - menu_start_y_) / (gr_fb_height() * 3 / 16);
|
|
1225
|
+ col = (point.x()) / (gr_fb_width() / 9);
|
|
1226
|
+ if ((col % 4) != 0) {
|
|
1227
|
+ sel = row * 2 + ((col - 1) / 4);
|
|
1228
|
+ }
|
|
1229
|
+ break;
|
|
1230
|
+ default:
|
|
1231
|
+ break;
|
|
1232
|
+ }
|
|
1233
|
+ if (sel >= (int)menu_items_.size()) {
|
|
1234
|
+ sel = Device::kNoAction;
|
|
1235
|
+ }
|
|
1236
|
+ }
|
|
1237
|
+ if (sel != -1 && sel != menu_sel) {
|
|
1238
|
+ menu_sel = sel;
|
|
1239
|
+ update_screen_locked();
|
|
1240
|
+ usleep(100*1000);
|
|
1241
|
+ }
|
900
|
1242
|
}
|
901
|
1243
|
pthread_mutex_unlock(&updateMutex);
|
902
|
1244
|
return sel;
|
|
@@ -907,6 +1249,9 @@ void ScreenRecoveryUI::EndMenu() {
|
907
|
1249
|
if (show_menu && text_rows_ > 0 && text_cols_ > 0) {
|
908
|
1250
|
show_menu = false;
|
909
|
1251
|
}
|
|
1252
|
+ menu_type_ = MT_NONE;
|
|
1253
|
+ menu_headers_ = nullptr;
|
|
1254
|
+ menu_items_.clear();
|
910
|
1255
|
pthread_mutex_unlock(&updateMutex);
|
911
|
1256
|
}
|
912
|
1257
|
|