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/ui-core-protocol.h" 18 19#define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0) 20static double get_default_scale( AndroidOptions* opts ); 21 22/* QEmulator structure instance. */ 23static QEmulator qemulator[1]; 24 25static void 26qemulator_light_brightness( void* opaque, const char* light, int value ) 27{ 28 QEmulator* emulator = opaque; 29 30 VERBOSE_PRINT(hw_control,"%s: light='%s' value=%d window=%p", __FUNCTION__, light, value, emulator->window); 31 if ( !strcmp(light, "lcd_backlight") ) { 32 emulator->lcd_brightness = value; 33 if (emulator->window) 34 skin_window_set_lcd_brightness( emulator->window, value ); 35 return; 36 } 37} 38 39static void 40qemulator_setup( QEmulator* emulator ) 41{ 42 AndroidOptions* opts = emulator->opts; 43 44 if ( !emulator->window && !opts->no_window ) { 45 SkinLayout* layout = emulator->layout; 46 double scale = get_default_scale(emulator->opts); 47 48 emulator->window = skin_window_create( layout, emulator->win_x, emulator->win_y, scale, 0); 49 if (emulator->window == NULL) 50 return; 51 52 { 53 SkinTrackBall* ball; 54 SkinTrackBallParameters params; 55 56 params.diameter = 30; 57 params.ring = 2; 58 params.ball_color = 0xffe0e0e0; 59 params.dot_color = 0xff202020; 60 params.ring_color = 0xff000000; 61 62 ball = skin_trackball_create( ¶ms ); 63 emulator->trackball = ball; 64 skin_window_set_trackball( emulator->window, ball ); 65 66 emulator->lcd_brightness = 128; /* 50% */ 67 skin_window_set_lcd_brightness( emulator->window, emulator->lcd_brightness ); 68 } 69 70 if ( emulator->onion != NULL ) 71 skin_window_set_onion( emulator->window, 72 emulator->onion, 73 emulator->onion_rotation, 74 emulator->onion_alpha ); 75 76 qemulator_set_title(emulator); 77 78 skin_window_enable_touch ( emulator->window, android_hw->hw_touchScreen != 0 ); 79 skin_window_enable_dpad ( emulator->window, android_hw->hw_dPad != 0 ); 80 skin_window_enable_qwerty( emulator->window, android_hw->hw_keyboard != 0 ); 81 skin_window_enable_trackball( emulator->window, android_hw->hw_trackBall != 0 ); 82 } 83 84 /* initialize hardware control support */ 85 android_core_set_brightness_change_callback(qemulator_light_brightness, 86 emulator); 87} 88 89static void 90qemulator_fb_update( void* _emulator, int x, int y, int w, int h ) 91{ 92 QEmulator* emulator = _emulator; 93 94 if (emulator->window) 95 skin_window_update_display( emulator->window, x, y, w, h ); 96} 97 98static void 99qemulator_fb_rotate( void* _emulator, int rotation ) 100{ 101 QEmulator* emulator = _emulator; 102 103 qemulator_setup( emulator ); 104} 105 106QEmulator* 107qemulator_get(void) 108{ 109 return qemulator; 110} 111 112int 113qemulator_init( QEmulator* emulator, 114 AConfig* aconfig, 115 const char* basepath, 116 int x, 117 int y, 118 AndroidOptions* opts ) 119{ 120 emulator->aconfig = aconfig; 121 emulator->layout_file = skin_file_create_from_aconfig(aconfig, basepath); 122 emulator->layout = emulator->layout_file->layouts; 123 // If we have a custom charmap use it to initialize keyboard. 124 // Otherwise initialize keyboard from configuration settings. 125 // Another way to configure keyboard to use a custom charmap would 126 // be saving a custom charmap name into AConfig's keyboard->charmap 127 // property, and calling single skin_keyboard_create_from_aconfig 128 // routine to initialize keyboard. 129 if (NULL != opts->charmap) { 130 emulator->keyboard = skin_keyboard_create_from_kcm(opts->charmap, opts->raw_keys); 131 } else { 132 emulator->keyboard = skin_keyboard_create_from_aconfig(aconfig, opts->raw_keys); 133 } 134 emulator->window = NULL; 135 emulator->win_x = x; 136 emulator->win_y = y; 137 emulator->opts[0] = opts[0]; 138 139 /* register as a framebuffer clients for all displays defined in the skin file */ 140 SKIN_FILE_LOOP_PARTS( emulator->layout_file, part ) 141 SkinDisplay* disp = part->display; 142 if (disp->valid) { 143 qframebuffer_add_client( disp->qfbuff, 144 emulator, 145 qemulator_fb_update, 146 qemulator_fb_rotate, 147 NULL ); 148 } 149 SKIN_FILE_LOOP_END_PARTS 150 return 0; 151} 152 153void 154qemulator_done(QEmulator* emulator) 155{ 156 if (emulator->window) { 157 skin_window_free(emulator->window); 158 emulator->window = NULL; 159 } 160 if (emulator->trackball) { 161 skin_trackball_destroy(emulator->trackball); 162 emulator->trackball = NULL; 163 } 164 if (emulator->keyboard) { 165 skin_keyboard_free(emulator->keyboard); 166 emulator->keyboard = NULL; 167 } 168 emulator->layout = NULL; 169 if (emulator->layout_file) { 170 skin_file_free(emulator->layout_file); 171 emulator->layout_file = NULL; 172 } 173} 174 175SkinLayout* 176qemulator_get_layout(QEmulator* emulator) 177{ 178 return emulator->layout; 179} 180 181void 182qemulator_set_title(QEmulator* emulator) 183{ 184 char temp[128], *p=temp, *end=p+sizeof temp;; 185 186 if (emulator->window == NULL) 187 return; 188 189 if (emulator->show_trackball) { 190 SkinKeyBinding bindings[ SKIN_KEY_COMMAND_MAX_BINDINGS ]; 191 int count; 192 193 count = skin_keyset_get_bindings( android_keyset, 194 SKIN_KEY_COMMAND_TOGGLE_TRACKBALL, 195 bindings ); 196 197 if (count > 0) { 198 int nn; 199 p = bufprint( p, end, "Press " ); 200 for (nn = 0; nn < count; nn++) { 201 if (nn > 0) { 202 if (nn < count-1) 203 p = bufprint(p, end, ", "); 204 else 205 p = bufprint(p, end, " or "); 206 } 207 p = bufprint(p, end, "%s", 208 skin_key_symmod_to_str( bindings[nn].sym, 209 bindings[nn].mod ) ); 210 } 211 p = bufprint(p, end, " to leave trackball mode. "); 212 } 213 } 214 215 p = bufprint(p, end, "%d:%s", 216 android_core_get_base_port(), 217 avdInfo_getName( android_avdInfo )); 218 219 skin_window_set_title( emulator->window, temp ); 220} 221 222/* 223 * Helper routines 224 */ 225 226int 227get_device_dpi( AndroidOptions* opts ) 228{ 229 int dpi_device = android_core_get_hw_lcd_density(); 230 231 if (opts->dpi_device != NULL) { 232 char* end; 233 dpi_device = strtol( opts->dpi_device, &end, 0 ); 234 if (end == NULL || *end != 0 || dpi_device <= 0) { 235 fprintf(stderr, "argument for -dpi-device must be a positive integer. Aborting\n" ); 236 exit(1); 237 } 238 } 239 return dpi_device; 240} 241 242static double 243get_default_scale( AndroidOptions* opts ) 244{ 245 int dpi_device = get_device_dpi( opts ); 246 int dpi_monitor = -1; 247 double scale = 0.0; 248 249 /* possible values for the 'scale' option are 250 * 'auto' : try to determine the scale automatically 251 * '<number>dpi' : indicates the host monitor dpi, compute scale accordingly 252 * '<fraction>' : use direct scale coefficient 253 */ 254 255 if (opts->scale) { 256 if (!strcmp(opts->scale, "auto")) 257 { 258 /* we need to get the host dpi resolution ? */ 259 int xdpi, ydpi; 260 261 if ( SDL_WM_GetMonitorDPI( &xdpi, &ydpi ) < 0 ) { 262 fprintf(stderr, "could not get monitor DPI resolution from system. please use -dpi-monitor to specify one\n" ); 263 exit(1); 264 } 265 D( "system reported monitor resolutions: xdpi=%d ydpi=%d\n", xdpi, ydpi); 266 dpi_monitor = (xdpi + ydpi+1)/2; 267 } 268 else 269 { 270 char* end; 271 scale = strtod( opts->scale, &end ); 272 273 if (end && end[0] == 'd' && end[1] == 'p' && end[2] == 'i' && end[3] == 0) { 274 if ( scale < 20 || scale > 1000 ) { 275 fprintf(stderr, "emulator: ignoring bad -scale argument '%s': %s\n", opts->scale, 276 "host dpi number must be between 20 and 1000" ); 277 exit(1); 278 } 279 dpi_monitor = scale; 280 scale = 0.0; 281 } 282 else if (end == NULL || *end != 0) { 283 fprintf(stderr, "emulator: ignoring bad -scale argument '%s': %s\n", opts->scale, 284 "not a number or the 'auto' keyword" ); 285 exit(1); 286 } 287 else if ( scale < 0.1 || scale > 3. ) { 288 fprintf(stderr, "emulator: ignoring bad -window-scale argument '%s': %s\n", opts->scale, 289 "must be between 0.1 and 3.0" ); 290 exit(1); 291 } 292 } 293 } 294 295 if (scale == 0.0 && dpi_monitor > 0) 296 scale = dpi_monitor*1.0/dpi_device; 297 298 if (scale == 0.0) 299 scale = 1.0; 300 301 return scale; 302} 303 304/* 305 * android/console.c helper routines. 306 */ 307 308SkinKeyboard* 309android_emulator_get_keyboard(void) 310{ 311 return qemulator->keyboard; 312} 313 314void 315android_emulator_set_window_scale( double scale, int is_dpi ) 316{ 317 QEmulator* emulator = qemulator; 318 319 if (is_dpi) 320 scale /= get_device_dpi( emulator->opts ); 321 322 if (emulator->window) 323 skin_window_set_scale( emulator->window, scale ); 324} 325 326