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