• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 2006-2010 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 ** GNU General Public License for more details.
11 */
12 
13 #include "android/utils/debug.h"
14 #include "android/utils/bufprint.h"
15 #include "android/globals.h"
16 #include "android/qemulator.h"
17 #include "android/protocol/core-commands-api.h"
18 #include "android/protocol/ui-commands-api.h"
19 #include "user-events.h"
20 
21 #define  D(...)  do {  if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
22 static double get_default_scale( AndroidOptions*  opts );
23 
24 /* QEmulator structure instance. */
25 static QEmulator   qemulator[1];
26 
27 static void handle_key_command( void*  opaque, SkinKeyCommand  command, int  param );
28 static void qemulator_refresh(QEmulator* emulator);
29 extern void qemu_system_shutdown_request(void);
30 
31 static void
qemulator_light_brightness(void * opaque,const char * light,int value)32 qemulator_light_brightness( void* opaque, const char*  light, int  value )
33 {
34     QEmulator*  emulator = opaque;
35 
36     VERBOSE_PRINT(hw_control,"%s: light='%s' value=%d window=%p", __FUNCTION__, light, value, emulator->window);
37     if ( !strcmp(light, "lcd_backlight") ) {
38         emulator->lcd_brightness = value;
39         if (emulator->window)
40             skin_window_set_lcd_brightness( emulator->window, value );
41         return;
42     }
43 }
44 
45 static void
qemulator_setup(QEmulator * emulator)46 qemulator_setup( QEmulator*  emulator )
47 {
48     AndroidOptions*  opts = emulator->opts;
49 
50     if ( !emulator->window && !opts->no_window ) {
51         SkinLayout*  layout = emulator->layout;
52         double       scale  = get_default_scale(emulator->opts);
53 
54         emulator->window = skin_window_create( layout, emulator->win_x, emulator->win_y, scale, 0);
55         if (emulator->window == NULL)
56             return;
57 
58         {
59             SkinTrackBall*           ball;
60             SkinTrackBallParameters  params;
61 
62             params.diameter   = 30;
63             params.ring       = 2;
64             params.ball_color = 0xffe0e0e0;
65             params.dot_color  = 0xff202020;
66             params.ring_color = 0xff000000;
67 
68             ball = skin_trackball_create( &params );
69             emulator->trackball = ball;
70             skin_window_set_trackball( emulator->window, ball );
71 
72             emulator->lcd_brightness = 128;  /* 50% */
73             skin_window_set_lcd_brightness( emulator->window, emulator->lcd_brightness );
74         }
75 
76         if ( emulator->onion != NULL )
77             skin_window_set_onion( emulator->window,
78                                    emulator->onion,
79                                    emulator->onion_rotation,
80                                    emulator->onion_alpha );
81 
82         qemulator_set_title(emulator);
83 
84         skin_window_enable_touch ( emulator->window, android_hw->hw_touchScreen != 0 );
85         skin_window_enable_dpad  ( emulator->window, android_hw->hw_dPad != 0 );
86         skin_window_enable_qwerty( emulator->window, android_hw->hw_keyboard != 0 );
87         skin_window_enable_trackball( emulator->window, android_hw->hw_trackBall != 0 );
88     }
89 
90     /* initialize hardware control support */
91     uicmd_set_brightness_change_callback(qemulator_light_brightness,
92                                          emulator);
93 }
94 
95 static void
qemulator_fb_update(void * _emulator,int x,int y,int w,int h)96 qemulator_fb_update( void*   _emulator, int  x, int  y, int  w, int  h )
97 {
98     QEmulator*  emulator = _emulator;
99 
100     if (!emulator->window) {
101         if (emulator->opts->no_window)
102             return;
103         qemulator_setup( emulator );
104     }
105     skin_window_update_display( emulator->window, x, y, w, h );
106 }
107 
108 static void
qemulator_fb_rotate(void * _emulator,int rotation)109 qemulator_fb_rotate( void*  _emulator, int  rotation )
110 {
111     QEmulator*  emulator = _emulator;
112 
113     qemulator_setup( emulator );
114 }
115 
116 static void
qemulator_fb_poll(void * _emulator)117 qemulator_fb_poll( void* _emulator )
118 {
119     QEmulator* emulator = _emulator;
120     qemulator_refresh(emulator);
121 }
122 
123 QEmulator*
qemulator_get(void)124 qemulator_get(void)
125 {
126     return qemulator;
127 }
128 
129 int
qemulator_init(QEmulator * emulator,AConfig * aconfig,const char * basepath,int x,int y,AndroidOptions * opts)130 qemulator_init( QEmulator*       emulator,
131                 AConfig*         aconfig,
132                 const char*      basepath,
133                 int              x,
134                 int              y,
135                 AndroidOptions*  opts )
136 {
137     emulator->aconfig     = aconfig;
138     emulator->layout_file = skin_file_create_from_aconfig(aconfig, basepath);
139     emulator->layout      = emulator->layout_file->layouts;
140     emulator->keyboard    = skin_keyboard_create(opts->charmap, opts->raw_keys);
141     emulator->window      = NULL;
142     emulator->win_x       = x;
143     emulator->win_y       = y;
144     emulator->opts[0]     = opts[0];
145 
146     /* register as a framebuffer clients for all displays defined in the skin file */
147     SKIN_FILE_LOOP_PARTS( emulator->layout_file, part )
148         SkinDisplay*  disp = part->display;
149         if (disp->valid) {
150             qframebuffer_add_client( disp->qfbuff,
151                                      emulator,
152                                      qemulator_fb_update,
153                                      qemulator_fb_rotate,
154                                      qemulator_fb_poll,
155                                      NULL );
156         }
157     SKIN_FILE_LOOP_END_PARTS
158 
159     skin_keyboard_enable( emulator->keyboard, 1 );
160     skin_keyboard_on_command( emulator->keyboard, handle_key_command, emulator );
161 
162     return 0;
163 }
164 
165 void
qemulator_done(QEmulator * emulator)166 qemulator_done(QEmulator* emulator)
167 {
168     if (emulator->window) {
169         skin_window_free(emulator->window);
170         emulator->window = NULL;
171     }
172     if (emulator->trackball) {
173         skin_trackball_destroy(emulator->trackball);
174         emulator->trackball = NULL;
175     }
176     if (emulator->keyboard) {
177         skin_keyboard_free(emulator->keyboard);
178         emulator->keyboard = NULL;
179     }
180     emulator->layout = NULL;
181     if (emulator->layout_file) {
182         skin_file_free(emulator->layout_file);
183         emulator->layout_file = NULL;
184     }
185 }
186 
187 SkinLayout*
qemulator_get_layout(QEmulator * emulator)188 qemulator_get_layout(QEmulator* emulator)
189 {
190     return emulator->layout;
191 }
192 
193 QFrameBuffer*
qemulator_get_first_framebuffer(QEmulator * emulator)194 qemulator_get_first_framebuffer(QEmulator* emulator)
195 {
196     /* register as a framebuffer clients for all displays defined in the skin file */
197     SKIN_FILE_LOOP_PARTS( emulator->layout_file, part )
198         SkinDisplay*  disp = part->display;
199         if (disp->valid) {
200             return disp->qfbuff;
201         }
202     SKIN_FILE_LOOP_END_PARTS
203     return NULL;
204 }
205 
206 void
qemulator_set_title(QEmulator * emulator)207 qemulator_set_title(QEmulator* emulator)
208 {
209     char  temp[128], *p=temp, *end=p+sizeof temp;;
210 
211     if (emulator->window == NULL)
212         return;
213 
214     if (emulator->show_trackball) {
215         SkinKeyBinding  bindings[ SKIN_KEY_COMMAND_MAX_BINDINGS ];
216         int             count;
217 
218         count = skin_keyset_get_bindings( android_keyset,
219                                           SKIN_KEY_COMMAND_TOGGLE_TRACKBALL,
220                                           bindings );
221 
222         if (count > 0) {
223             int  nn;
224             p = bufprint( p, end, "Press " );
225             for (nn = 0; nn < count; nn++) {
226                 if (nn > 0) {
227                     if (nn < count-1)
228                         p = bufprint(p, end, ", ");
229                     else
230                         p = bufprint(p, end, " or ");
231                 }
232                 p = bufprint(p, end, "%s",
233                              skin_key_symmod_to_str( bindings[nn].sym,
234                                                      bindings[nn].mod ) );
235             }
236             p = bufprint(p, end, " to leave trackball mode. ");
237         }
238     }
239 
240     p = bufprint(p, end, "%d:%s",
241                  android_base_port,
242                  avdInfo_getName( android_avdInfo ));
243 
244     skin_window_set_title( emulator->window, temp );
245 }
246 
247 /*
248  * Helper routines
249  */
250 
251 static int
get_device_dpi(AndroidOptions * opts)252 get_device_dpi( AndroidOptions*  opts )
253 {
254     int    dpi_device  = corecmd_get_hw_lcd_density();
255 
256     if (opts->dpi_device != NULL) {
257         char*  end;
258         dpi_device = strtol( opts->dpi_device, &end, 0 );
259         if (end == NULL || *end != 0 || dpi_device <= 0) {
260             fprintf(stderr, "argument for -dpi-device must be a positive integer. Aborting\n" );
261             exit(1);
262         }
263     }
264     return  dpi_device;
265 }
266 
267 static double
get_default_scale(AndroidOptions * opts)268 get_default_scale( AndroidOptions*  opts )
269 {
270     int     dpi_device  = get_device_dpi( opts );
271     int     dpi_monitor = -1;
272     double  scale       = 0.0;
273 
274     /* possible values for the 'scale' option are
275      *   'auto'        : try to determine the scale automatically
276      *   '<number>dpi' : indicates the host monitor dpi, compute scale accordingly
277      *   '<fraction>'  : use direct scale coefficient
278      */
279 
280     if (opts->scale) {
281         if (!strcmp(opts->scale, "auto"))
282         {
283             /* we need to get the host dpi resolution ? */
284             int   xdpi, ydpi;
285 
286             if ( SDL_WM_GetMonitorDPI( &xdpi, &ydpi ) < 0 ) {
287                 fprintf(stderr, "could not get monitor DPI resolution from system. please use -dpi-monitor to specify one\n" );
288                 exit(1);
289             }
290             D( "system reported monitor resolutions: xdpi=%d ydpi=%d\n", xdpi, ydpi);
291             dpi_monitor = (xdpi + ydpi+1)/2;
292         }
293         else
294         {
295             char*   end;
296             scale = strtod( opts->scale, &end );
297 
298             if (end && end[0] == 'd' && end[1] == 'p' && end[2] == 'i' && end[3] == 0) {
299                 if ( scale < 20 || scale > 1000 ) {
300                     fprintf(stderr, "emulator: ignoring bad -scale argument '%s': %s\n", opts->scale,
301                             "host dpi number must be between 20 and 1000" );
302                     exit(1);
303                 }
304                 dpi_monitor = scale;
305                 scale       = 0.0;
306             }
307             else if (end == NULL || *end != 0) {
308                 fprintf(stderr, "emulator: ignoring bad -scale argument '%s': %s\n", opts->scale,
309                         "not a number or the 'auto' keyword" );
310                 exit(1);
311             }
312             else if ( scale < 0.1 || scale > 3. ) {
313                 fprintf(stderr, "emulator: ignoring bad -window-scale argument '%s': %s\n", opts->scale,
314                         "must be between 0.1 and 3.0" );
315                 exit(1);
316             }
317         }
318     }
319 
320     if (scale == 0.0 && dpi_monitor > 0)
321         scale = dpi_monitor*1.0/dpi_device;
322 
323     return scale;
324 }
325 
326 /* used to respond to a given keyboard command shortcut
327  */
328 static void
handle_key_command(void * opaque,SkinKeyCommand command,int down)329 handle_key_command( void*  opaque, SkinKeyCommand  command, int  down )
330 {
331     static const struct { SkinKeyCommand  cmd; AndroidKeyCode  kcode; }  keycodes[] =
332     {
333         { SKIN_KEY_COMMAND_BUTTON_CALL,        kKeyCodeCall },
334         { SKIN_KEY_COMMAND_BUTTON_HOME,        kKeyCodeHome },
335         { SKIN_KEY_COMMAND_BUTTON_BACK,        kKeyCodeBack },
336         { SKIN_KEY_COMMAND_BUTTON_HANGUP,      kKeyCodeEndCall },
337         { SKIN_KEY_COMMAND_BUTTON_POWER,       kKeyCodePower },
338         { SKIN_KEY_COMMAND_BUTTON_SEARCH,      kKeyCodeSearch },
339         { SKIN_KEY_COMMAND_BUTTON_MENU,        kKeyCodeMenu },
340         { SKIN_KEY_COMMAND_BUTTON_DPAD_UP,     kKeyCodeDpadUp },
341         { SKIN_KEY_COMMAND_BUTTON_DPAD_LEFT,   kKeyCodeDpadLeft },
342         { SKIN_KEY_COMMAND_BUTTON_DPAD_RIGHT,  kKeyCodeDpadRight },
343         { SKIN_KEY_COMMAND_BUTTON_DPAD_DOWN,   kKeyCodeDpadDown },
344         { SKIN_KEY_COMMAND_BUTTON_DPAD_CENTER, kKeyCodeDpadCenter },
345         { SKIN_KEY_COMMAND_BUTTON_VOLUME_UP,   kKeyCodeVolumeUp },
346         { SKIN_KEY_COMMAND_BUTTON_VOLUME_DOWN, kKeyCodeVolumeDown },
347         { SKIN_KEY_COMMAND_BUTTON_CAMERA,      kKeyCodeCamera },
348         { SKIN_KEY_COMMAND_BUTTON_TV,          kKeyCodeTV },
349         { SKIN_KEY_COMMAND_BUTTON_EPG,         kKeyCodeEPG },
350         { SKIN_KEY_COMMAND_BUTTON_DVR,         kKeyCodeDVR },
351         { SKIN_KEY_COMMAND_BUTTON_PREV,        kKeyCodePrevious },
352         { SKIN_KEY_COMMAND_BUTTON_NEXT,        kKeyCodeNext },
353         { SKIN_KEY_COMMAND_BUTTON_PLAY,        kKeyCodePlay },
354         { SKIN_KEY_COMMAND_BUTTON_PAUSE,       kKeyCodePause },
355         { SKIN_KEY_COMMAND_BUTTON_STOP,        kKeyCodeStop },
356         { SKIN_KEY_COMMAND_BUTTON_REWIND,      kKeyCodeRewind },
357         { SKIN_KEY_COMMAND_BUTTON_FFWD,        kKeyCodeFastForward },
358         { SKIN_KEY_COMMAND_BUTTON_BOOKMARKS,   kKeyCodeBookmarks },
359         { SKIN_KEY_COMMAND_BUTTON_WINDOW,      kKeyCodeCycleWindows },
360         { SKIN_KEY_COMMAND_BUTTON_CHANNELUP,   kKeyCodeChannelUp },
361         { SKIN_KEY_COMMAND_BUTTON_CHANNELDOWN, kKeyCodeChannelDown },
362         { SKIN_KEY_COMMAND_NONE, 0 }
363     };
364     int          nn;
365 #ifdef CONFIG_TRACE
366     static int   tracing = 0;
367 #endif
368     QEmulator*   emulator = opaque;
369 
370 
371     for (nn = 0; keycodes[nn].kcode != 0; nn++) {
372         if (command == keycodes[nn].cmd) {
373             unsigned  code = keycodes[nn].kcode;
374             if (down)
375                 code |= 0x200;
376             user_event_keycode( code );
377             return;
378         }
379     }
380 
381     // for the show-trackball command, handle down events to enable, and
382     // up events to disable
383     if (command == SKIN_KEY_COMMAND_SHOW_TRACKBALL) {
384         emulator->show_trackball = (down != 0);
385         skin_window_show_trackball( emulator->window, emulator->show_trackball );
386         //qemulator_set_title( emulator );
387         return;
388     }
389 
390     // only handle down events for the rest
391     if (down == 0)
392         return;
393 
394     switch (command)
395     {
396     case SKIN_KEY_COMMAND_TOGGLE_NETWORK:
397         {
398             corecmd_toggle_network();
399             D( "network is now %s", corecmd_is_network_disabled() ?
400                                     "disconnected" : "connected" );
401         }
402         break;
403 
404     case SKIN_KEY_COMMAND_TOGGLE_FULLSCREEN:
405         if (emulator->window) {
406             skin_window_toggle_fullscreen(emulator->window);
407         }
408         break;
409 
410     case SKIN_KEY_COMMAND_TOGGLE_TRACING:
411         {
412 #ifdef CONFIG_TRACE
413             tracing = !tracing;
414             corecmd_trace_control(tracing);
415 #endif
416         }
417         break;
418 
419     case SKIN_KEY_COMMAND_TOGGLE_TRACKBALL:
420         emulator->show_trackball = !emulator->show_trackball;
421         skin_window_show_trackball( emulator->window, emulator->show_trackball );
422         qemulator_set_title(emulator);
423         break;
424 
425     case SKIN_KEY_COMMAND_ONION_ALPHA_UP:
426     case SKIN_KEY_COMMAND_ONION_ALPHA_DOWN:
427         if (emulator->onion)
428         {
429             int  alpha = emulator->onion_alpha;
430 
431             if (command == SKIN_KEY_COMMAND_ONION_ALPHA_UP)
432                 alpha += 16;
433             else
434                 alpha -= 16;
435 
436             if (alpha > 256)
437                 alpha = 256;
438             else if (alpha < 0)
439                 alpha = 0;
440 
441             emulator->onion_alpha = alpha;
442             skin_window_set_onion( emulator->window, emulator->onion, emulator->onion_rotation, alpha );
443             skin_window_redraw( emulator->window, NULL );
444             //dprint( "onion alpha set to %d (%.f %%)", alpha, alpha/2.56 );
445         }
446         break;
447 
448     case SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV:
449     case SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT:
450         {
451             SkinLayout*  layout = NULL;
452 
453             if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT) {
454                 layout = emulator->layout->next;
455                 if (layout == NULL)
456                     layout = emulator->layout_file->layouts;
457             }
458             else if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV) {
459                 layout = emulator->layout_file->layouts;
460                 while (layout->next && layout->next != emulator->layout)
461                     layout = layout->next;
462             }
463             if (layout != NULL) {
464                 SkinRotation  rotation;
465 
466                 emulator->layout = layout;
467                 skin_window_reset( emulator->window, layout );
468 
469                 rotation = skin_layout_get_dpad_rotation( layout );
470 
471                 if (emulator->keyboard)
472                     skin_keyboard_set_rotation( emulator->keyboard, rotation );
473 
474                 if (emulator->trackball) {
475                     skin_trackball_set_rotation( emulator->trackball, rotation );
476                     skin_window_set_trackball( emulator->window, emulator->trackball );
477                     skin_window_show_trackball( emulator->window, emulator->show_trackball );
478                 }
479 
480                 skin_window_set_lcd_brightness( emulator->window, emulator->lcd_brightness );
481 
482                 qframebuffer_invalidate_all();
483                 qframebuffer_check_updates();
484             }
485         }
486         break;
487 
488     default:
489         /* XXX: TODO ? */
490         ;
491     }
492 }
493 
494 /* called periodically to poll for user input events */
qemulator_refresh(QEmulator * emulator)495 static void qemulator_refresh(QEmulator* emulator)
496 {
497     SDL_Event      ev;
498     SkinWindow*    window   = emulator->window;
499     SkinKeyboard*  keyboard = emulator->keyboard;
500 
501    /* this will eventually call sdl_update if the content of the VGA framebuffer
502     * has changed */
503     qframebuffer_check_updates();
504 
505     if (window == NULL)
506         return;
507 
508     while(SDL_PollEvent(&ev)){
509         switch(ev.type){
510         case SDL_VIDEOEXPOSE:
511             skin_window_redraw( window, NULL );
512             break;
513 
514         case SDL_KEYDOWN:
515 #ifdef _WIN32
516             /* special code to deal with Alt-F4 properly */
517             if (ev.key.keysym.sym == SDLK_F4 &&
518                 ev.key.keysym.mod & KMOD_ALT) {
519               goto CleanExit;
520             }
521 #endif
522 #ifdef __APPLE__
523             /* special code to deal with Command-Q properly */
524             if (ev.key.keysym.sym == SDLK_q &&
525                 ev.key.keysym.mod & KMOD_META) {
526               goto CleanExit;
527             }
528 #endif
529             skin_keyboard_process_event( keyboard, &ev, 1 );
530             break;
531 
532         case SDL_KEYUP:
533             skin_keyboard_process_event( keyboard, &ev, 0 );
534             break;
535 
536         case SDL_MOUSEMOTION:
537             skin_window_process_event( window, &ev );
538             break;
539 
540         case SDL_MOUSEBUTTONDOWN:
541         case SDL_MOUSEBUTTONUP:
542             {
543                 int  down = (ev.type == SDL_MOUSEBUTTONDOWN);
544                 if (ev.button.button == 4)
545                 {
546                     /* scroll-wheel simulates DPad up */
547                     AndroidKeyCode  kcode;
548 
549                     kcode = // qemulator_rotate_keycode(kKeyCodeDpadUp);
550                         android_keycode_rotate(kKeyCodeDpadUp,
551                             skin_layout_get_dpad_rotation(qemulator_get_layout(qemulator_get())));
552                     user_event_key( kcode, down );
553                 }
554                 else if (ev.button.button == 5)
555                 {
556                     /* scroll-wheel simulates DPad down */
557                     AndroidKeyCode  kcode;
558 
559                     kcode = // qemulator_rotate_keycode(kKeyCodeDpadDown);
560                         android_keycode_rotate(kKeyCodeDpadDown,
561                             skin_layout_get_dpad_rotation(qemulator_get_layout(qemulator_get())));
562                     user_event_key( kcode, down );
563                 }
564                 else if (ev.button.button == SDL_BUTTON_LEFT) {
565                     skin_window_process_event( window, &ev );
566                 }
567 #if 0
568                 else {
569                 fprintf(stderr, "... mouse button %s: button=%d state=%04x x=%d y=%d\n",
570                                 down ? "down" : "up  ",
571                                 ev.button.button, ev.button.state, ev.button.x, ev.button.y);
572                 }
573 #endif
574             }
575             break;
576 
577         case SDL_QUIT:
578 #if defined _WIN32 || defined __APPLE__
579         CleanExit:
580 #endif
581             /* only save emulator config through clean exit */
582             qemulator_done(qemulator_get());
583             qemu_system_shutdown_request();
584             return;
585         }
586     }
587 
588     skin_keyboard_flush( keyboard );
589 }
590 
591 /*
592  * android/console.c helper routines.
593  */
594 
595 SkinKeyboard*
android_emulator_get_keyboard(void)596 android_emulator_get_keyboard(void)
597 {
598     return qemulator->keyboard;
599 }
600 
601 void
android_emulator_set_window_scale(double scale,int is_dpi)602 android_emulator_set_window_scale( double  scale, int  is_dpi )
603 {
604     QEmulator*  emulator = qemulator;
605 
606     if (is_dpi)
607         scale /= get_device_dpi( emulator->opts );
608 
609     if (emulator->window)
610         skin_window_set_scale( emulator->window, scale );
611 }
612 
613 
614 void
android_emulator_set_base_port(int port)615 android_emulator_set_base_port( int  port )
616 {
617     /* Base port is already set in the emulator's core. */
618     qemulator_set_title(qemulator);
619 }
620