diff options
-rw-r--r-- | android/cmdline-options.h | 1 | ||||
-rw-r--r-- | android/help.c | 9 | ||||
-rw-r--r-- | android/main-common.c | 215 | ||||
-rw-r--r-- | docs/ANDROID-SKIN-FILES.TXT | 20 |
4 files changed, 242 insertions, 3 deletions
diff --git a/android/cmdline-options.h b/android/cmdline-options.h index 5e8d59f..16edeac 100644 --- a/android/cmdline-options.h +++ b/android/cmdline-options.h @@ -90,6 +90,7 @@ CFG_PARAM( skindir, "<dir>", "search skins in <dir> (default <system>/skins)" ) CFG_PARAM( skin, "<name>", "select a given skin" ) CFG_FLAG ( no_skin, "don't use any emulator skin" ) CFG_FLAG ( noskin, "same as -no-skin" ) +CFG_FLAG ( dynamic_skin, "dynamically construct a skin of given size, requires -skin WxH option" ) CFG_PARAM( memory, "<size>", "physical RAM size in MBs" ) OPT_PARAM( netspeed, "<speed>", "maximum network download/upload speeds" ) diff --git a/android/help.c b/android/help.c index 1570160..0a9eed8 100644 --- a/android/help.c +++ b/android/help.c @@ -759,6 +759,15 @@ help_skin(stralloc_t* out) " specify an exact framebuffer size, without any visual ornaments.\n\n" ); } +static void +help_dynamic_skin(stralloc_t* out) +{ + PRINTF( + " use '-dynamic_skin' to dynamically generate a skin based on the settings\n" + " in the AVD. This option only has effect if the -skin WxH option is used\n" + " to specify the width and height of the framebuffer\n"); +} + /* default network settings for emulator */ #define DEFAULT_NETSPEED "full" #define DEFAULT_NETDELAY "none" diff --git a/android/main-common.c b/android/main-common.c index 2d535c7..5c82005 100644 --- a/android/main-common.c +++ b/android/main-common.c @@ -321,6 +321,207 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) #endif } +typedef struct part_properties part_properties; +struct part_properties { + const char* name; + int width; + int height; + part_properties* next; +}; + +part_properties* +read_all_part_properties(AConfig* parts) +{ + part_properties* head = NULL; + part_properties* prev = NULL; + + AConfig *node = parts->first_child; + while (node) { + part_properties* t = calloc(1, sizeof(part_properties)); + t->name = node->name; + + AConfig* bg = aconfig_find(node, "background"); + if (bg != NULL) { + t->width = aconfig_int(bg, "width", 0); + t->height = aconfig_int(bg, "height", 0); + } + + if (prev == NULL) { + head = t; + } else { + prev->next = t; + } + prev = t; + node = node->next; + } + + return head; +} + +void +free_all_part_properties(part_properties* head) +{ + part_properties* prev = head; + while (head) { + prev = head; + head = head->next; + free(prev); + } +} + +part_properties* +get_part_properties(part_properties* allparts, char *partname) +{ + part_properties* p; + for (p = allparts; p != NULL; p = p->next) { + if (!strcmp(partname, p->name)) + return p; + } + + return NULL; +} + +void +add_parts_to_layout(AConfig* layout, + char* parts[], + int n_parts, + part_properties *props, + int xoffset, + int x_margin, + int y_margin) +{ + int i; + int y = 10; + char tmp[512]; + for (i = 0; i < n_parts; i++) { + part_properties *p = get_part_properties(props, parts[i]); + snprintf(tmp, sizeof tmp, + "part%d {\n \ + name %s\n \ + x %d\n \ + y %d\n \ + }", + i + 2, // layout already has the device part as part1, so start from part2 + p->name, + xoffset + x_margin, + y + ); + y += p->height + y_margin; + aconfig_load(layout, strdup(tmp)); + } +} + +int +load_dynamic_skin(AndroidHwConfig* hwConfig, + const char* skinDirPath, + int width, + int height, + AConfig* root) +{ + char tmp[1024]; + AConfig* node; + int i; + int max_part_width; + + if (skinDirPath == NULL) + return 0; + + snprintf(tmp, sizeof(tmp), "%s/dynamic", skinDirPath); + if (!path_exists(tmp)) + return 0; + + snprintf(tmp, sizeof(tmp), "%s/dynamic/layout", skinDirPath); + D("trying to load skin file '%s'", tmp); + + if(aconfig_load_file(root, tmp) < 0) { + dwarning("could not load skin file '%s', won't use a skin\n", tmp); + return 0; + } + + /* Fix the width and height specified for the "device" part in the layout */ + node = aconfig_find(root, "parts"); + if (node != NULL) { + node = aconfig_find(node, "device"); + if (node != NULL) { + node = aconfig_find(node, "display"); + if (node != NULL) { + snprintf(tmp, sizeof tmp, "%d", width); + aconfig_set(node, "width", strdup(tmp)); + snprintf(tmp, sizeof tmp, "%d", height); + aconfig_set(node, "height", strdup(tmp)); + } + } + } + + /* The dynamic layout declares all the parts that are available statically + in the layout file. Now we need to dynamically generate the + appropriate layout based on the hardware config */ + + part_properties* props = read_all_part_properties(aconfig_find(root, "parts")); + + const int N_PARTS = 3; + char* parts[N_PARTS]; + parts[0] = hwConfig->hw_mainKeys ? "hwkeys_on" : "hwkeys_off"; + parts[1] = hwConfig->hw_dPad ? "dpad_on" : "dpad_off"; + parts[2] = hwConfig->hw_keyboard ? "keyboard_on" : "keyboard_off"; + + for (i = 0, max_part_width = 0; i < N_PARTS; i++) { + part_properties *p = get_part_properties(props, parts[i]); + if (p != NULL && p->width > max_part_width) + max_part_width = p->width; + } + + int x_margin = 10; + int y_margin = 10; + snprintf(tmp, sizeof tmp, + "layouts {\n \ + portrait {\n \ + width %d\n \ + height %d\n \ + color 0x404040\n \ + event EV_SW:0:1\n \ + part1 {\n name device\n x 0\n y 0\n}\n \ + }\n \ + landscape {\n \ + width %d\n \ + height %d\n \ + color 0x404040\n \ + event EV_SW:0:0\n \ + dpad-rotation 3\n \ + part1 {\n name device\n x 0\n y %d\n rotation 3\n }\n \ + }\n \ + }\n \ + }\n", + width + max_part_width + 2 * x_margin, + height, + height + max_part_width + 2 * x_margin, + width, + width); + aconfig_load(root, strdup(tmp)); + + /* Add parts to portrait orientation */ + node = aconfig_find(root, "layouts"); + if (node != NULL) { + node = aconfig_find(node, "portrait"); + if (node != NULL) { + add_parts_to_layout(node, parts, N_PARTS, props, width, x_margin, y_margin); + } + } + + /* Add parts to landscape orientation */ + node = aconfig_find(root, "layouts"); + if (node != NULL) { + node = aconfig_find(node, "landscape"); + if (node != NULL) { + add_parts_to_layout(node, parts, N_PARTS, props, height, x_margin, y_margin); + } + } + + free_all_part_properties(props); + + return 1; +} + /* list of skin aliases */ static const struct { const char* name; @@ -396,9 +597,19 @@ parse_skin_files(const char* skinDirPath, if (y && isdigit(y[1])) { bpp = atoi(y+1); } + + if (opts->dynamic_skin) { + if (load_dynamic_skin(hwConfig, skinDirPath, width, height, root)) { + snprintf(tmp, sizeof tmp, "%s/dynamic/", skinDirPath); + path = tmp; + D("loaded dynamic skin width=%d height=%d bpp=%d\n", width, height, bpp); + goto FOUND_SKIN; + } + } + snprintf(tmp, sizeof tmp, - "display {\n width %d\n height %d\n bpp %d}\n", - width, height,bpp); + "display {\n width %d\n height %d\n bpp %d}\n", + width, height,bpp); aconfig_load(root, strdup(tmp)); path = ":"; D("found magic skin width=%d height=%d bpp=%d\n", width, height, bpp); diff --git a/docs/ANDROID-SKIN-FILES.TXT b/docs/ANDROID-SKIN-FILES.TXT index 004f83d..edd7545 100644 --- a/docs/ANDROID-SKIN-FILES.TXT +++ b/docs/ANDROID-SKIN-FILES.TXT @@ -1,8 +1,10 @@ Android Emulator Skin File Specification: ========================================= +Revisions: +---------- Revision 2. Dated 2009-12-07 - + Dynamic Layout support added 10/2012 Introduction: ------------- @@ -18,6 +20,9 @@ corresponding to different orientation / physical configurations of the emulated handset. This document specifies how to generate a new skin for the emulator. +The emulator also supports dynamically creating the layout section of +the skin, thereby removing the necessity to create skins for each new +handset type. See the last section regarding info on dynamic controls. General File Format: -------------------- @@ -219,3 +224,16 @@ file instead: - 'network.delay': Default network latency for this skin. Values correspond to the -netdelay <delay> emulator command-line option. + +Dynamic Layouts: +---------------- + +The emulator also supports a skin that is dynamically generated. This +skin (present in folder "dynamic" in the skins folder) follows the same +format as other skins, except that it only defines the list of parts/controls +that can be used in the skin. The layouts section is generated at +runtime by the emulator. The parts section describes all the controls that +can be used in any handset. All these parts have both an enabled and a +disabled version defined in the skin, and at runtime the emulator reads +the hardware definition and decides which of those two controls to actually +use. |