blob: 92eab29837b3027301a4542c75d44d66bb3dd1a5 [file] [log] [blame]
Dees_Troy51a0e822012-09-05 15:24:24 -04001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <linux/input.h>
18#include <pthread.h>
19#include <stdarg.h>
20#include <stdio.h>
21#include <errno.h>
22#include <stdlib.h>
23#include <string.h>
24#include <fcntl.h>
25#include <sys/reboot.h>
26#include <sys/stat.h>
27#include <sys/time.h>
28#include <sys/mman.h>
29#include <sys/types.h>
30#include <sys/ioctl.h>
31#include <sys/mount.h>
32#include <time.h>
33#include <unistd.h>
34#include <stdlib.h>
35
36
37extern "C" {
38#include "../common.h"
39#include "../roots.h"
40#include "../minuitwrp/minui.h"
41#include "../recovery_ui.h"
42#include "../minzip/Zip.h"
43#include <pixelflinger/pixelflinger.h>
44}
45
46#include "rapidxml.hpp"
47#include "objects.hpp"
48#include "../data.hpp"
49#include "../variables.h"
Dees_Troy5bf43922012-09-07 16:07:55 -040050#include "../partitions.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040051
Dees_Troy51a0e822012-09-05 15:24:24 -040052const static int CURTAIN_FADE = 32;
53
54using namespace rapidxml;
55
56// Global values
57static gr_surface gCurtain = NULL;
58static int gGuiInitialized = 0;
59static int gGuiConsoleRunning = 0;
60static int gGuiConsoleTerminate = 0;
61static int gForceRender = 0;
Dees_Troyc8b199c2012-09-24 11:55:07 -040062static int gNoAnimation = 1;
Dees_Troy4bc09ae2013-01-18 17:00:54 +000063static int gGuiInputRunning = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -040064
65// Needed by pages.cpp too
66int gGuiRunning = 0;
67
68static int gRecorder = -1;
69
70extern "C" void gr_write_frame_to_file(int fd);
71
72void flip(void)
73{
74 if (gRecorder != -1)
75 {
76 timespec time;
77 clock_gettime(CLOCK_MONOTONIC, &time);
78 write(gRecorder, &time, sizeof(timespec));
79 gr_write_frame_to_file(gRecorder);
80 }
81 gr_flip();
82 return;
83}
84
85void rapidxml::parse_error_handler(const char *what, void *where)
86{
87 fprintf(stderr, "Parser error: %s\n", what);
88 fprintf(stderr, " Start of string: %s\n", (char*) where);
89 abort();
90}
91
92static void curtainSet()
93{
94 gr_color(0, 0, 0, 255);
95 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
96 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain), gr_get_height(gCurtain), 0, 0);
97 gr_flip();
98 return;
99}
100
101static void curtainRaise(gr_surface surface)
102{
103 int sy = 0;
104 int h = gr_get_height(gCurtain) - 1;
105 int w = gr_get_width(gCurtain);
106 int fy = 1;
107
108 int msw = gr_get_width(surface);
109 int msh = gr_get_height(surface);
110 int CURTAIN_RATE = msh / 30;
111
112 if (gNoAnimation == 0)
113 {
114 for (; h > 0; h -= CURTAIN_RATE, sy += CURTAIN_RATE, fy += CURTAIN_RATE)
115 {
116 gr_blit(surface, 0, 0, msw, msh, 0, 0);
117 gr_blit(gCurtain, 0, sy, w, h, 0, 0);
118 gr_flip();
119 }
120 }
121 gr_blit(surface, 0, 0, msw, msh, 0, 0);
122 flip();
123 return;
124}
125
126void curtainClose()
127{
128#if 0
129 int w = gr_get_width(gCurtain);
130 int h = 1;
131 int sy = gr_get_height(gCurtain) - 1;
132 int fbh = gr_fb_height();
133 int CURTAIN_RATE = fbh / 30;
134
135 if (gNoAnimation == 0)
136 {
137 for (; h < fbh; h += CURTAIN_RATE, sy -= CURTAIN_RATE)
138 {
139 gr_blit(gCurtain, 0, sy, w, h, 0, 0);
140 gr_flip();
141 }
142 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain), gr_get_height(gCurtain), 0, 0);
143 gr_flip();
144
145 if (gRecorder != -1)
146 close(gRecorder);
147
148 int fade;
149 for (fade = 16; fade < 255; fade += CURTAIN_FADE)
150 {
151 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain), gr_get_height(gCurtain), 0, 0);
152 gr_color(0, 0, 0, fade);
153 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
154 gr_flip();
155 }
156 gr_color(0, 0, 0, 255);
157 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
158 gr_flip();
159 }
160#else
161 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain), gr_get_height(gCurtain), 0, 0);
162 gr_flip();
163#endif
164 return;
165}
166
167timespec timespec_diff(timespec& start, timespec& end)
168{
169 timespec temp;
170 if ((end.tv_nsec-start.tv_nsec)<0) {
171 temp.tv_sec = end.tv_sec-start.tv_sec-1;
172 temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
173 } else {
174 temp.tv_sec = end.tv_sec-start.tv_sec;
175 temp.tv_nsec = end.tv_nsec-start.tv_nsec;
176 }
177 return temp;
178}
179
180static void *input_thread(void *cookie)
181{
182 int drag = 0;
183 static int touch_and_hold = 0, dontwait = 0, touch_repeat = 0, x = 0, y = 0, lshift = 0, rshift = 0, key_repeat = 0;
184 static struct timeval touchStart;
185 HardwareKeyboard kb;
186
187 for (;;) {
188
189 // wait for the next event
190 struct input_event ev;
191 int state = 0, ret = 0;
192
193 ret = ev_get(&ev, dontwait);
194
195 if (ret < 0) {
196 struct timeval curTime;
197 gettimeofday(&curTime, NULL);
198 long mtime, seconds, useconds;
199
200 seconds = curTime.tv_sec - touchStart.tv_sec;
201 useconds = curTime.tv_usec - touchStart.tv_usec;
202
203 mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;
204 if (touch_and_hold && mtime > 500) {
205 touch_and_hold = 0;
206 touch_repeat = 1;
207 gettimeofday(&touchStart, NULL);
208#ifdef _EVENT_LOGGING
209 LOGE("TOUCH_HOLD: %d,%d\n", x, y);
210#endif
211 PageManager::NotifyTouch(TOUCH_HOLD, x, y);
212 } else if (touch_repeat && mtime > 100) {
213#ifdef _EVENT_LOGGING
214 LOGE("TOUCH_REPEAT: %d,%d\n", x, y);
215#endif
216 gettimeofday(&touchStart, NULL);
217 PageManager::NotifyTouch(TOUCH_REPEAT, x, y);
218 } else if (key_repeat == 1 && mtime > 500) {
219#ifdef _EVENT_LOGGING
220 LOGE("KEY_HOLD: %d,%d\n", x, y);
221#endif
222 gettimeofday(&touchStart, NULL);
223 key_repeat = 2;
224 kb.KeyRepeat();
225 } else if (key_repeat == 2 && mtime > 100) {
226#ifdef _EVENT_LOGGING
227 LOGE("KEY_REPEAT: %d,%d\n", x, y);
228#endif
229 gettimeofday(&touchStart, NULL);
230 kb.KeyRepeat();
231 }
232 } else if (ev.type == EV_ABS) {
233
234 x = ev.value >> 16;
235 y = ev.value & 0xFFFF;
236
237 if (ev.code == 0)
238 {
239 if (state == 0)
240 {
241#ifdef _EVENT_LOGGING
242 LOGE("TOUCH_RELEASE: %d,%d\n", x, y);
243#endif
244 PageManager::NotifyTouch(TOUCH_RELEASE, x, y);
245 touch_and_hold = 0;
246 touch_repeat = 0;
247 if (!key_repeat)
248 dontwait = 0;
249 }
250 state = 0;
251 drag = 0;
252 }
253 else
254 {
255 if (!drag)
256 {
257#ifdef _EVENT_LOGGING
258 LOGE("TOUCH_START: %d,%d\n", x, y);
259#endif
260 if (PageManager::NotifyTouch(TOUCH_START, x, y) > 0)
261 state = 1;
262 drag = 1;
263 touch_and_hold = 1;
264 dontwait = 1;
265 key_repeat = 0;
266 gettimeofday(&touchStart, NULL);
267 }
268 else
269 {
270 if (state == 0)
271 {
272#ifdef _EVENT_LOGGING
273 LOGE("TOUCH_DRAG: %d,%d\n", x, y);
274#endif
275 if (PageManager::NotifyTouch(TOUCH_DRAG, x, y) > 0)
276 state = 1;
277 key_repeat = 0;
278 }
279 }
280 }
281 }
282 else if (ev.type == EV_KEY)
283 {
284 // Handle key-press here
285#ifdef _EVENT_LOGGING
286 LOGE("TOUCH_KEY: %d\n", ev.code);
287#endif
288 if (ev.value != 0) {
289 // This is a key press
290 if (kb.KeyDown(ev.code)) {
291 key_repeat = 1;
292 touch_and_hold = 0;
293 touch_repeat = 0;
294 dontwait = 1;
295 gettimeofday(&touchStart, NULL);
296 } else {
297 key_repeat = 0;
298 touch_and_hold = 0;
299 touch_repeat = 0;
300 dontwait = 0;
301 }
302 } else {
303 // This is a key release
304 kb.KeyUp(ev.code);
305 key_repeat = 0;
306 touch_and_hold = 0;
307 touch_repeat = 0;
308 dontwait = 0;
309 }
310 }
311 }
312 return NULL;
313}
314
315// This special function will return immediately the first time, but then
316// always returns 1/30th of a second (or immediately if called later) from
317// the last time it was called
318static void loopTimer(void)
319{
320 static timespec lastCall;
321 static int initialized = 0;
322
323 if (!initialized)
324 {
325 clock_gettime(CLOCK_MONOTONIC, &lastCall);
326 initialized = 1;
327 return;
328 }
329
330 do
331 {
332 timespec curTime;
333 clock_gettime(CLOCK_MONOTONIC, &curTime);
334
335 timespec diff = timespec_diff(lastCall, curTime);
336
337 // This is really 30 times per second
338 if (diff.tv_sec || diff.tv_nsec > 33333333)
339 {
340 lastCall = curTime;
341 return;
342 }
343
344 // We need to sleep some period time microseconds
345 unsigned int sleepTime = 33333 - (diff.tv_nsec / 1000);
346 usleep(sleepTime);
347 } while(1);
348 return;
349}
350
351static int runPages(void)
352{
353 // Raise the curtain
354 if (gCurtain != NULL)
355 {
356 gr_surface surface;
357
358 PageManager::Render();
359 gr_get_surface(&surface);
360 curtainRaise(surface);
361 gr_free_surface(surface);
362 }
363
364 gGuiRunning = 1;
365
366 DataManager::SetValue("tw_loaded", 1);
367
368 for (;;)
369 {
370 loopTimer();
371
372 if (!gForceRender)
373 {
374 int ret;
375
376 ret = PageManager::Update();
377 if (ret > 1)
378 PageManager::Render();
379
380 if (ret > 0)
381 flip();
382 }
383 else
384 {
385 gForceRender = 0;
386 PageManager::Render();
387 flip();
388 }
389 }
390
391 gGuiRunning = 0;
392 return 0;
393}
394
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000395static int runPage(const char* page_name)
396{
397 gui_changePage(page_name);
398
399 // Raise the curtain
400 if (gCurtain != NULL)
401 {
402 gr_surface surface;
403
404 PageManager::Render();
405 gr_get_surface(&surface);
406 curtainRaise(surface);
407 gr_free_surface(surface);
408 }
409
410 gGuiRunning = 1;
411
412 DataManager::SetValue("tw_loaded", 1);
413
414 for (;;)
415 {
416 loopTimer();
417
418 if (!gForceRender)
419 {
420 int ret;
421
422 ret = PageManager::Update();
423 if (ret > 1)
424 PageManager::Render();
425
426 if (ret > 0)
427 flip();
428 }
429 else
430 {
431 gForceRender = 0;
432 PageManager::Render();
433 flip();
434 }
435 if (DataManager::GetIntValue("tw_page_done") != 0) {
436 gui_changePage("main");
437 break;
438 }
439 }
440
441 gGuiRunning = 0;
442 return 0;
443}
444
Dees_Troy51a0e822012-09-05 15:24:24 -0400445int gui_forceRender(void)
446{
447 gForceRender = 1;
448 return 0;
449}
450
451int gui_changePage(std::string newPage)
452{
453 LOGI("Set page: '%s'\n", newPage.c_str());
454 PageManager::ChangePage(newPage);
455 gForceRender = 1;
456 return 0;
457}
458
459int gui_changeOverlay(std::string overlay)
460{
461 PageManager::ChangeOverlay(overlay);
462 gForceRender = 1;
463 return 0;
464}
465
466int gui_changePackage(std::string newPackage)
467{
468 PageManager::SelectPackage(newPackage);
469 gForceRender = 1;
470 return 0;
471}
472
473std::string gui_parse_text(string inText)
474{
475 // Copied from std::string GUIText::parseText(void)
476 // This function parses text for DataManager values encompassed by %value% in the XML
477 static int counter = 0;
478 std::string str = inText;
479 size_t pos = 0;
480 size_t next = 0, end = 0;
481
482 while (1)
483 {
484 next = str.find('%', pos);
485 if (next == std::string::npos) return str;
486 end = str.find('%', next + 1);
487 if (end == std::string::npos) return str;
488
489 // We have a block of data
490 std::string var = str.substr(next + 1, (end - next) - 1);
491 str.erase(next, (end - next) + 1);
492
493 if (next + 1 == end)
494 {
495 str.insert(next, 1, '%');
496 }
497 else
498 {
499 std::string value;
500 if (DataManager::GetValue(var, value) == 0)
501 str.insert(next, value);
502 }
503
504 pos = next + 1;
505 }
506}
507
508extern "C" int gui_init()
509{
510 int fd;
511
512 gr_init();
513
Dees_Troyc8b199c2012-09-24 11:55:07 -0400514 if (res_create_surface("/res/images/curtain.jpg", &gCurtain))
515 {
516 printf("Unable to locate '/res/images/curtain.jpg'\nDid you set a DEVICE_RESOLUTION in your config files?\n");
517 return -1;
518 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400519
520 curtainSet();
521
522 ev_init();
523 return 0;
524}
525
526extern "C" int gui_loadResources()
527{
Dees_Troy51a0e822012-09-05 15:24:24 -0400528// unlink("/sdcard/video.last");
529// rename("/sdcard/video.bin", "/sdcard/video.last");
530// gRecorder = open("/sdcard/video.bin", O_CREAT | O_WRONLY);
531
532 int check = 0;
Dees_Troy5bf43922012-09-07 16:07:55 -0400533 DataManager::GetValue(TW_IS_ENCRYPTED, check);
Dees_Troy51a0e822012-09-05 15:24:24 -0400534 if (check) {
Dees_Troy5bf43922012-09-07 16:07:55 -0400535 if (PageManager::LoadPackage("TWRP", "/res/ui.xml", "decrypt"))
536 {
537 LOGE("Failed to load base packages.\n");
538 goto error;
Dees_Troy51a0e822012-09-05 15:24:24 -0400539 } else
Dees_Troy5bf43922012-09-07 16:07:55 -0400540 check = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400541 }
542 if (check == 0 && PageManager::LoadPackage("TWRP", "/script/ui.xml", "main")) {
543 std::string theme_path;
544
545 theme_path = DataManager::GetSettingsStoragePath();
Dees_Troy5bf43922012-09-07 16:07:55 -0400546 if (!PartitionManager.Mount_Settings_Storage(false)) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400547 int retry_count = 5;
Dees_Troy5bf43922012-09-07 16:07:55 -0400548 while (retry_count > 0 && !PartitionManager.Mount_Settings_Storage(false)) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400549 usleep(500000);
Dees_Troy51a0e822012-09-05 15:24:24 -0400550 retry_count--;
551 }
Dees_Troy5bf43922012-09-07 16:07:55 -0400552 if (!PartitionManager.Mount_Settings_Storage(false)) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400553 LOGE("Unable to mount %s during GUI startup.\n", theme_path.c_str());
554 check = 1;
555 }
556 }
557
558 theme_path += "/TWRP/theme/ui.zip";
559 if (check || PageManager::LoadPackage("TWRP", theme_path, "main"))
560 {
561 if (PageManager::LoadPackage("TWRP", "/res/ui.xml", "main"))
562 {
563 LOGE("Failed to load base packages.\n");
564 goto error;
565 }
566 }
567 }
568
569 // Set the default package
570 PageManager::SelectPackage("TWRP");
571
572 gGuiInitialized = 1;
573 return 0;
574
575error:
576 LOGE("An internal error has occurred.\n");
577 gGuiInitialized = 0;
578 return -1;
579}
580
581extern "C" int gui_start()
582{
583 if (!gGuiInitialized) return -1;
584
585 gGuiConsoleTerminate = 1;
586 while (gGuiConsoleRunning) loopTimer();
587
588 // Set the default package
589 PageManager::SelectPackage("TWRP");
590
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000591 if (!gGuiInputRunning) {
592 // Start by spinning off an input handler.
593 pthread_t t;
594 pthread_create(&t, NULL, input_thread, NULL);
595 gGuiInputRunning = 1;
596 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400597
598 return runPages();
599}
600
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000601extern "C" int gui_startPage(const char* page_name)
602{
603 if (!gGuiInitialized) return -1;
604
605 gGuiConsoleTerminate = 1;
606 while (gGuiConsoleRunning) loopTimer();
607
608 // Set the default package
609 PageManager::SelectPackage("TWRP");
610
611 if (!gGuiInputRunning) {
612 // Start by spinning off an input handler.
613 pthread_t t;
614 pthread_create(&t, NULL, input_thread, NULL);
615 gGuiInputRunning = 1;
616 }
617
Dees_Troy6ed34b72013-01-25 15:01:29 +0000618 DataManager::SetValue("tw_page_done", 0);
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000619 return runPage(page_name);
620}
621
Dees_Troy51a0e822012-09-05 15:24:24 -0400622static void *console_thread(void *cookie)
623{
624 PageManager::SwitchToConsole();
625
626 while (!gGuiConsoleTerminate)
627 {
628 loopTimer();
629
630 if (!gForceRender)
631 {
632 int ret;
633
634 ret = PageManager::Update();
635 if (ret > 1)
636 PageManager::Render();
637
638 if (ret > 0)
639 flip();
640
641 if (ret < 0)
642 LOGE("An update request has failed.\n");
643 }
644 else
645 {
646 gForceRender = 0;
647 PageManager::Render();
648 flip();
649 }
650 }
651 gGuiConsoleRunning = 0;
652 return NULL;
653}
654
655extern "C" int gui_console_only()
656{
657 if (!gGuiInitialized) return -1;
658
659 gGuiConsoleTerminate = 0;
660 gGuiConsoleRunning = 1;
661
662 // Start by spinning off an input handler.
663 pthread_t t;
664 pthread_create(&t, NULL, console_thread, NULL);
665
666 return 0;
667}