blob: ccde9f096a12c0bd4ab85537f0308978edefdc24 [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
52#include "curtain.h"
53
54const static int CURTAIN_FADE = 32;
55
56using namespace rapidxml;
57
58// Global values
59static gr_surface gCurtain = NULL;
60static int gGuiInitialized = 0;
61static int gGuiConsoleRunning = 0;
62static int gGuiConsoleTerminate = 0;
63static int gForceRender = 0;
64static int gNoAnimation = 0;
65
66// Needed by pages.cpp too
67int gGuiRunning = 0;
68
69static int gRecorder = -1;
70
71extern "C" void gr_write_frame_to_file(int fd);
72
73void flip(void)
74{
75 if (gRecorder != -1)
76 {
77 timespec time;
78 clock_gettime(CLOCK_MONOTONIC, &time);
79 write(gRecorder, &time, sizeof(timespec));
80 gr_write_frame_to_file(gRecorder);
81 }
82 gr_flip();
83 return;
84}
85
86void rapidxml::parse_error_handler(const char *what, void *where)
87{
88 fprintf(stderr, "Parser error: %s\n", what);
89 fprintf(stderr, " Start of string: %s\n", (char*) where);
90 abort();
91}
92
93static void curtainSet()
94{
95 gr_color(0, 0, 0, 255);
96 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
97 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain), gr_get_height(gCurtain), 0, 0);
98 gr_flip();
99 return;
100}
101
102static void curtainRaise(gr_surface surface)
103{
104 int sy = 0;
105 int h = gr_get_height(gCurtain) - 1;
106 int w = gr_get_width(gCurtain);
107 int fy = 1;
108
109 int msw = gr_get_width(surface);
110 int msh = gr_get_height(surface);
111 int CURTAIN_RATE = msh / 30;
112
113 if (gNoAnimation == 0)
114 {
115 for (; h > 0; h -= CURTAIN_RATE, sy += CURTAIN_RATE, fy += CURTAIN_RATE)
116 {
117 gr_blit(surface, 0, 0, msw, msh, 0, 0);
118 gr_blit(gCurtain, 0, sy, w, h, 0, 0);
119 gr_flip();
120 }
121 }
122 gr_blit(surface, 0, 0, msw, msh, 0, 0);
123 flip();
124 return;
125}
126
127void curtainClose()
128{
129#if 0
130 int w = gr_get_width(gCurtain);
131 int h = 1;
132 int sy = gr_get_height(gCurtain) - 1;
133 int fbh = gr_fb_height();
134 int CURTAIN_RATE = fbh / 30;
135
136 if (gNoAnimation == 0)
137 {
138 for (; h < fbh; h += CURTAIN_RATE, sy -= CURTAIN_RATE)
139 {
140 gr_blit(gCurtain, 0, sy, w, h, 0, 0);
141 gr_flip();
142 }
143 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain), gr_get_height(gCurtain), 0, 0);
144 gr_flip();
145
146 if (gRecorder != -1)
147 close(gRecorder);
148
149 int fade;
150 for (fade = 16; fade < 255; fade += CURTAIN_FADE)
151 {
152 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain), gr_get_height(gCurtain), 0, 0);
153 gr_color(0, 0, 0, fade);
154 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
155 gr_flip();
156 }
157 gr_color(0, 0, 0, 255);
158 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
159 gr_flip();
160 }
161#else
162 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain), gr_get_height(gCurtain), 0, 0);
163 gr_flip();
164#endif
165 return;
166}
167
168timespec timespec_diff(timespec& start, timespec& end)
169{
170 timespec temp;
171 if ((end.tv_nsec-start.tv_nsec)<0) {
172 temp.tv_sec = end.tv_sec-start.tv_sec-1;
173 temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
174 } else {
175 temp.tv_sec = end.tv_sec-start.tv_sec;
176 temp.tv_nsec = end.tv_nsec-start.tv_nsec;
177 }
178 return temp;
179}
180
181static void *input_thread(void *cookie)
182{
183 int drag = 0;
184 static int touch_and_hold = 0, dontwait = 0, touch_repeat = 0, x = 0, y = 0, lshift = 0, rshift = 0, key_repeat = 0;
185 static struct timeval touchStart;
186 HardwareKeyboard kb;
187
188 for (;;) {
189
190 // wait for the next event
191 struct input_event ev;
192 int state = 0, ret = 0;
193
194 ret = ev_get(&ev, dontwait);
195
196 if (ret < 0) {
197 struct timeval curTime;
198 gettimeofday(&curTime, NULL);
199 long mtime, seconds, useconds;
200
201 seconds = curTime.tv_sec - touchStart.tv_sec;
202 useconds = curTime.tv_usec - touchStart.tv_usec;
203
204 mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;
205 if (touch_and_hold && mtime > 500) {
206 touch_and_hold = 0;
207 touch_repeat = 1;
208 gettimeofday(&touchStart, NULL);
209#ifdef _EVENT_LOGGING
210 LOGE("TOUCH_HOLD: %d,%d\n", x, y);
211#endif
212 PageManager::NotifyTouch(TOUCH_HOLD, x, y);
213 } else if (touch_repeat && mtime > 100) {
214#ifdef _EVENT_LOGGING
215 LOGE("TOUCH_REPEAT: %d,%d\n", x, y);
216#endif
217 gettimeofday(&touchStart, NULL);
218 PageManager::NotifyTouch(TOUCH_REPEAT, x, y);
219 } else if (key_repeat == 1 && mtime > 500) {
220#ifdef _EVENT_LOGGING
221 LOGE("KEY_HOLD: %d,%d\n", x, y);
222#endif
223 gettimeofday(&touchStart, NULL);
224 key_repeat = 2;
225 kb.KeyRepeat();
226 } else if (key_repeat == 2 && mtime > 100) {
227#ifdef _EVENT_LOGGING
228 LOGE("KEY_REPEAT: %d,%d\n", x, y);
229#endif
230 gettimeofday(&touchStart, NULL);
231 kb.KeyRepeat();
232 }
233 } else if (ev.type == EV_ABS) {
234
235 x = ev.value >> 16;
236 y = ev.value & 0xFFFF;
237
238 if (ev.code == 0)
239 {
240 if (state == 0)
241 {
242#ifdef _EVENT_LOGGING
243 LOGE("TOUCH_RELEASE: %d,%d\n", x, y);
244#endif
245 PageManager::NotifyTouch(TOUCH_RELEASE, x, y);
246 touch_and_hold = 0;
247 touch_repeat = 0;
248 if (!key_repeat)
249 dontwait = 0;
250 }
251 state = 0;
252 drag = 0;
253 }
254 else
255 {
256 if (!drag)
257 {
258#ifdef _EVENT_LOGGING
259 LOGE("TOUCH_START: %d,%d\n", x, y);
260#endif
261 if (PageManager::NotifyTouch(TOUCH_START, x, y) > 0)
262 state = 1;
263 drag = 1;
264 touch_and_hold = 1;
265 dontwait = 1;
266 key_repeat = 0;
267 gettimeofday(&touchStart, NULL);
268 }
269 else
270 {
271 if (state == 0)
272 {
273#ifdef _EVENT_LOGGING
274 LOGE("TOUCH_DRAG: %d,%d\n", x, y);
275#endif
276 if (PageManager::NotifyTouch(TOUCH_DRAG, x, y) > 0)
277 state = 1;
278 key_repeat = 0;
279 }
280 }
281 }
282 }
283 else if (ev.type == EV_KEY)
284 {
285 // Handle key-press here
286#ifdef _EVENT_LOGGING
287 LOGE("TOUCH_KEY: %d\n", ev.code);
288#endif
289 if (ev.value != 0) {
290 // This is a key press
291 if (kb.KeyDown(ev.code)) {
292 key_repeat = 1;
293 touch_and_hold = 0;
294 touch_repeat = 0;
295 dontwait = 1;
296 gettimeofday(&touchStart, NULL);
297 } else {
298 key_repeat = 0;
299 touch_and_hold = 0;
300 touch_repeat = 0;
301 dontwait = 0;
302 }
303 } else {
304 // This is a key release
305 kb.KeyUp(ev.code);
306 key_repeat = 0;
307 touch_and_hold = 0;
308 touch_repeat = 0;
309 dontwait = 0;
310 }
311 }
312 }
313 return NULL;
314}
315
316// This special function will return immediately the first time, but then
317// always returns 1/30th of a second (or immediately if called later) from
318// the last time it was called
319static void loopTimer(void)
320{
321 static timespec lastCall;
322 static int initialized = 0;
323
324 if (!initialized)
325 {
326 clock_gettime(CLOCK_MONOTONIC, &lastCall);
327 initialized = 1;
328 return;
329 }
330
331 do
332 {
333 timespec curTime;
334 clock_gettime(CLOCK_MONOTONIC, &curTime);
335
336 timespec diff = timespec_diff(lastCall, curTime);
337
338 // This is really 30 times per second
339 if (diff.tv_sec || diff.tv_nsec > 33333333)
340 {
341 lastCall = curTime;
342 return;
343 }
344
345 // We need to sleep some period time microseconds
346 unsigned int sleepTime = 33333 - (diff.tv_nsec / 1000);
347 usleep(sleepTime);
348 } while(1);
349 return;
350}
351
352static int runPages(void)
353{
354 // Raise the curtain
355 if (gCurtain != NULL)
356 {
357 gr_surface surface;
358
359 PageManager::Render();
360 gr_get_surface(&surface);
361 curtainRaise(surface);
362 gr_free_surface(surface);
363 }
364
365 gGuiRunning = 1;
366
367 DataManager::SetValue("tw_loaded", 1);
368
369 for (;;)
370 {
371 loopTimer();
372
373 if (!gForceRender)
374 {
375 int ret;
376
377 ret = PageManager::Update();
378 if (ret > 1)
379 PageManager::Render();
380
381 if (ret > 0)
382 flip();
383 }
384 else
385 {
386 gForceRender = 0;
387 PageManager::Render();
388 flip();
389 }
390 }
391
392 gGuiRunning = 0;
393 return 0;
394}
395
396int gui_forceRender(void)
397{
398 gForceRender = 1;
399 return 0;
400}
401
402int gui_changePage(std::string newPage)
403{
404 LOGI("Set page: '%s'\n", newPage.c_str());
405 PageManager::ChangePage(newPage);
406 gForceRender = 1;
407 return 0;
408}
409
410int gui_changeOverlay(std::string overlay)
411{
412 PageManager::ChangeOverlay(overlay);
413 gForceRender = 1;
414 return 0;
415}
416
417int gui_changePackage(std::string newPackage)
418{
419 PageManager::SelectPackage(newPackage);
420 gForceRender = 1;
421 return 0;
422}
423
424std::string gui_parse_text(string inText)
425{
426 // Copied from std::string GUIText::parseText(void)
427 // This function parses text for DataManager values encompassed by %value% in the XML
428 static int counter = 0;
429 std::string str = inText;
430 size_t pos = 0;
431 size_t next = 0, end = 0;
432
433 while (1)
434 {
435 next = str.find('%', pos);
436 if (next == std::string::npos) return str;
437 end = str.find('%', next + 1);
438 if (end == std::string::npos) return str;
439
440 // We have a block of data
441 std::string var = str.substr(next + 1, (end - next) - 1);
442 str.erase(next, (end - next) + 1);
443
444 if (next + 1 == end)
445 {
446 str.insert(next, 1, '%');
447 }
448 else
449 {
450 std::string value;
451 if (DataManager::GetValue(var, value) == 0)
452 str.insert(next, value);
453 }
454
455 pos = next + 1;
456 }
457}
458
459extern "C" int gui_init()
460{
461 int fd;
462
463 gr_init();
464
465 // We need to write out the curtain blob
466 if (sizeof(gCurtainBlob) > 32)
467 {
468 fd = open("/tmp/extract.jpg", O_CREAT | O_WRONLY | O_TRUNC);
469 if (fd < 0)
470 return 0;
471
472 write(fd, gCurtainBlob, sizeof(gCurtainBlob));
473 close(fd);
474
475 if (res_create_surface("/tmp/extract.jpg", &gCurtain))
476 {
477 return -1;
478 }
479 }
480 else
481 {
482 gNoAnimation = 1;
483 if (res_create_surface("bootup", &gCurtain))
484 return 0;
485 }
486 unlink("/tmp/extract.png");
487
488 curtainSet();
489
490 ev_init();
491 return 0;
492}
493
494extern "C" int gui_loadResources()
495{
496 // Make sure the sdcard is mounted before we continue
497//#ifdef RECOVERY_SDCARD_ON_DATA
498 /*mkdir("/mnt/data-sdc", 0777);
499 mount(dat.blk, "/mnt/data-sdc", dat.fst, 0, NULL);
500 if (symlink("/mnt/data-sdc/media", "/sdcard"))
501 {
502 LOGE("Unable to symlink (errno %d)\n", errno);
503 }*/
504//#else
505//#endif
506
507// unlink("/sdcard/video.last");
508// rename("/sdcard/video.bin", "/sdcard/video.last");
509// gRecorder = open("/sdcard/video.bin", O_CREAT | O_WRONLY);
510
511 int check = 0;
Dees_Troy5bf43922012-09-07 16:07:55 -0400512 DataManager::GetValue(TW_IS_ENCRYPTED, check);
Dees_Troy51a0e822012-09-05 15:24:24 -0400513 if (check) {
Dees_Troy5bf43922012-09-07 16:07:55 -0400514 if (PageManager::LoadPackage("TWRP", "/res/ui.xml", "decrypt"))
515 {
516 LOGE("Failed to load base packages.\n");
517 goto error;
Dees_Troy51a0e822012-09-05 15:24:24 -0400518 } else
Dees_Troy5bf43922012-09-07 16:07:55 -0400519 check = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400520 }
521 if (check == 0 && PageManager::LoadPackage("TWRP", "/script/ui.xml", "main")) {
522 std::string theme_path;
523
524 theme_path = DataManager::GetSettingsStoragePath();
Dees_Troy5bf43922012-09-07 16:07:55 -0400525 if (!PartitionManager.Mount_Settings_Storage(false)) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400526 int retry_count = 5;
Dees_Troy5bf43922012-09-07 16:07:55 -0400527 while (retry_count > 0 && !PartitionManager.Mount_Settings_Storage(false)) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400528 usleep(500000);
Dees_Troy51a0e822012-09-05 15:24:24 -0400529 retry_count--;
530 }
Dees_Troy5bf43922012-09-07 16:07:55 -0400531 if (!PartitionManager.Mount_Settings_Storage(false)) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400532 LOGE("Unable to mount %s during GUI startup.\n", theme_path.c_str());
533 check = 1;
534 }
535 }
536
537 theme_path += "/TWRP/theme/ui.zip";
538 if (check || PageManager::LoadPackage("TWRP", theme_path, "main"))
539 {
540 if (PageManager::LoadPackage("TWRP", "/res/ui.xml", "main"))
541 {
542 LOGE("Failed to load base packages.\n");
543 goto error;
544 }
545 }
546 }
547
548 // Set the default package
549 PageManager::SelectPackage("TWRP");
550
551 gGuiInitialized = 1;
552 return 0;
553
554error:
555 LOGE("An internal error has occurred.\n");
556 gGuiInitialized = 0;
557 return -1;
558}
559
560extern "C" int gui_start()
561{
562 if (!gGuiInitialized) return -1;
563
564 gGuiConsoleTerminate = 1;
565 while (gGuiConsoleRunning) loopTimer();
566
567 // Set the default package
568 PageManager::SelectPackage("TWRP");
569
570 // Start by spinning off an input handler.
571 pthread_t t;
572 pthread_create(&t, NULL, input_thread, NULL);
573
574 return runPages();
575}
576
577static void *console_thread(void *cookie)
578{
579 PageManager::SwitchToConsole();
580
581 while (!gGuiConsoleTerminate)
582 {
583 loopTimer();
584
585 if (!gForceRender)
586 {
587 int ret;
588
589 ret = PageManager::Update();
590 if (ret > 1)
591 PageManager::Render();
592
593 if (ret > 0)
594 flip();
595
596 if (ret < 0)
597 LOGE("An update request has failed.\n");
598 }
599 else
600 {
601 gForceRender = 0;
602 PageManager::Render();
603 flip();
604 }
605 }
606 gGuiConsoleRunning = 0;
607 return NULL;
608}
609
610extern "C" int gui_console_only()
611{
612 if (!gGuiInitialized) return -1;
613
614 gGuiConsoleTerminate = 0;
615 gGuiConsoleRunning = 1;
616
617 // Start by spinning off an input handler.
618 pthread_t t;
619 pthread_create(&t, NULL, console_thread, NULL);
620
621 return 0;
622}