blob: cb2b7c12cb442111b52d53cca985921169053bb8 [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"
50
51#include "curtain.h"
52
53const static int CURTAIN_FADE = 32;
54
55using namespace rapidxml;
56
57// Global values
58static gr_surface gCurtain = NULL;
59static int gGuiInitialized = 0;
60static int gGuiConsoleRunning = 0;
61static int gGuiConsoleTerminate = 0;
62static int gForceRender = 0;
63static int gNoAnimation = 0;
64
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
395int gui_forceRender(void)
396{
397 gForceRender = 1;
398 return 0;
399}
400
401int gui_changePage(std::string newPage)
402{
403 LOGI("Set page: '%s'\n", newPage.c_str());
404 PageManager::ChangePage(newPage);
405 gForceRender = 1;
406 return 0;
407}
408
409int gui_changeOverlay(std::string overlay)
410{
411 PageManager::ChangeOverlay(overlay);
412 gForceRender = 1;
413 return 0;
414}
415
416int gui_changePackage(std::string newPackage)
417{
418 PageManager::SelectPackage(newPackage);
419 gForceRender = 1;
420 return 0;
421}
422
423std::string gui_parse_text(string inText)
424{
425 // Copied from std::string GUIText::parseText(void)
426 // This function parses text for DataManager values encompassed by %value% in the XML
427 static int counter = 0;
428 std::string str = inText;
429 size_t pos = 0;
430 size_t next = 0, end = 0;
431
432 while (1)
433 {
434 next = str.find('%', pos);
435 if (next == std::string::npos) return str;
436 end = str.find('%', next + 1);
437 if (end == std::string::npos) return str;
438
439 // We have a block of data
440 std::string var = str.substr(next + 1, (end - next) - 1);
441 str.erase(next, (end - next) + 1);
442
443 if (next + 1 == end)
444 {
445 str.insert(next, 1, '%');
446 }
447 else
448 {
449 std::string value;
450 if (DataManager::GetValue(var, value) == 0)
451 str.insert(next, value);
452 }
453
454 pos = next + 1;
455 }
456}
457
458extern "C" int gui_init()
459{
460 int fd;
461
462 gr_init();
463
464 // We need to write out the curtain blob
465 if (sizeof(gCurtainBlob) > 32)
466 {
467 fd = open("/tmp/extract.jpg", O_CREAT | O_WRONLY | O_TRUNC);
468 if (fd < 0)
469 return 0;
470
471 write(fd, gCurtainBlob, sizeof(gCurtainBlob));
472 close(fd);
473
474 if (res_create_surface("/tmp/extract.jpg", &gCurtain))
475 {
476 return -1;
477 }
478 }
479 else
480 {
481 gNoAnimation = 1;
482 if (res_create_surface("bootup", &gCurtain))
483 return 0;
484 }
485 unlink("/tmp/extract.png");
486
487 curtainSet();
488
489 ev_init();
490 return 0;
491}
492
493extern "C" int gui_loadResources()
494{
495 // Make sure the sdcard is mounted before we continue
496//#ifdef RECOVERY_SDCARD_ON_DATA
497 /*mkdir("/mnt/data-sdc", 0777);
498 mount(dat.blk, "/mnt/data-sdc", dat.fst, 0, NULL);
499 if (symlink("/mnt/data-sdc/media", "/sdcard"))
500 {
501 LOGE("Unable to symlink (errno %d)\n", errno);
502 }*/
503//#else
504//#endif
505
506// unlink("/sdcard/video.last");
507// rename("/sdcard/video.bin", "/sdcard/video.last");
508// gRecorder = open("/sdcard/video.bin", O_CREAT | O_WRONLY);
509
510 int check = 0;
511 DataManager::GetValue(TW_HAS_CRYPTO, check);
512 if (check) {
513 if (ensure_path_mounted("/data") < 0) {
514 // Data failed to mount - probably encrypted
515 DataManager::SetValue(TW_IS_ENCRYPTED, 1);
516 DataManager::SetValue(TW_CRYPTO_PASSWORD, "");
517 DataManager::SetValue("tw_crypto_display", "");
518 if (PageManager::LoadPackage("TWRP", "/res/ui.xml", "decrypt"))
519 {
520 LOGE("Failed to load base packages.\n");
521 goto error;
522 } else
523 check = 1;
524 } else
525 check = 0; // Data mounted, not ecrypted, keep going like normal
526 }
527 if (check == 0 && PageManager::LoadPackage("TWRP", "/script/ui.xml", "main")) {
528 std::string theme_path;
529
530 theme_path = DataManager::GetSettingsStoragePath();
531 if (ensure_path_mounted(theme_path.c_str()) < 0) {
532 int retry_count = 5;
533 while (retry_count > 0 && (ensure_path_mounted(theme_path.c_str()) < 0)) {
534 usleep(500000);
535 ensure_path_mounted(theme_path.c_str());
536 retry_count--;
537 }
538 if (ensure_path_mounted(theme_path.c_str()) < 0) {
539 LOGE("Unable to mount %s during GUI startup.\n", theme_path.c_str());
540 check = 1;
541 }
542 }
543
544 theme_path += "/TWRP/theme/ui.zip";
545 if (check || PageManager::LoadPackage("TWRP", theme_path, "main"))
546 {
547 if (PageManager::LoadPackage("TWRP", "/res/ui.xml", "main"))
548 {
549 LOGE("Failed to load base packages.\n");
550 goto error;
551 }
552 }
553 }
554
555 // Set the default package
556 PageManager::SelectPackage("TWRP");
557
558 gGuiInitialized = 1;
559 return 0;
560
561error:
562 LOGE("An internal error has occurred.\n");
563 gGuiInitialized = 0;
564 return -1;
565}
566
567extern "C" int gui_start()
568{
569 if (!gGuiInitialized) return -1;
570
571 gGuiConsoleTerminate = 1;
572 while (gGuiConsoleRunning) loopTimer();
573
574 // Set the default package
575 PageManager::SelectPackage("TWRP");
576
577 // Start by spinning off an input handler.
578 pthread_t t;
579 pthread_create(&t, NULL, input_thread, NULL);
580
581 return runPages();
582}
583
584static void *console_thread(void *cookie)
585{
586 PageManager::SwitchToConsole();
587
588 while (!gGuiConsoleTerminate)
589 {
590 loopTimer();
591
592 if (!gForceRender)
593 {
594 int ret;
595
596 ret = PageManager::Update();
597 if (ret > 1)
598 PageManager::Render();
599
600 if (ret > 0)
601 flip();
602
603 if (ret < 0)
604 LOGE("An update request has failed.\n");
605 }
606 else
607 {
608 gForceRender = 0;
609 PageManager::Render();
610 flip();
611 }
612 }
613 gGuiConsoleRunning = 0;
614 return NULL;
615}
616
617extern "C" int gui_console_only()
618{
619 if (!gGuiInitialized) return -1;
620
621 gGuiConsoleTerminate = 0;
622 gGuiConsoleRunning = 1;
623
624 // Start by spinning off an input handler.
625 pthread_t t;
626 pthread_create(&t, NULL, console_thread, NULL);
627
628 return 0;
629}