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