Refactor HW config to use hw.camera_back, and hw.camera_front properties.

This is a continuation of an effort to simplify HW config, and make the UI for it clearer.
This CL gets rid of multiple camera emulation properties, combining everything into just
two properties:
- hw.camera_back that controls emulation of a camera facing back, and
- hw.camera_front that controls emulation of a camera facing front.

Change-Id: Ia114ae4caf2053685cbff00f39088e5b5be2952c
diff --git a/android/avd/hardware-properties.ini b/android/avd/hardware-properties.ini
index fdabcb5..4ea63ca 100644
--- a/android/avd/hardware-properties.ini
+++ b/android/avd/hardware-properties.ini
@@ -114,13 +114,6 @@
 abstract    = GSM modem support
 description = Whether there is a GSM modem in the device.
 
-# Camera support
-name        = hw.camera
-type        = boolean
-default     = yes
-abstract    = Camera support
-description = Whether the device has a camera.
-
 # GPS support
 name        = hw.gps
 type        = boolean
@@ -227,119 +220,21 @@
 abstract    = GPU emulation
 description = Enable/Disable emulated OpenGLES GPU
 
-# Fake camera support
+# Configures camera facing back
 #
-name        = hw.fakeCamera
+name        = hw.camera.back
 type        = string
-default     = back
-abstract    = Fake camera control
-description = Must be 'back', if fake camera is facing back, 'front', if fake camera is facing front, or 'off' if fake camera is disabled.
+default     = emulated
+abstract    = Configures camera facing back
+description = Must be 'emulated' for a fake camera, 'webcam<N>' for a web camera, or 'none' if back camera is disabled.
 
-# Number of emulated web cameras
+# Configures camera facing front
 #
-name        = hw.webcam.count
-type        = integer
-default     = 6
-abstract    = Number of emulated web cameras
-description = Defines number of web cameras to emulate. 0 disables webcam emulation.
-
-# Defines name of the emulated webcam with index 0
-#
-name        = hw.webcam.0.name
+name        = hw.camera.front
 type        = string
-default     = webcam0
-abstract    = Name of the 1-st emulated web camera
-description = Emulator-generated platform-independent name identifying a camera in the list of enumerated web cameras.
-
-# Defines name of the emulated webcam with index 1
-#
-name        = hw.webcam.1.name
-type        = string
-default     = webcam1
-abstract    = Name of the 2-nd emulated web camera
-description = Emulator-generated platform-independent camera name.
-
-# Defines name of the emulated webcam with index 2
-#
-name        = hw.webcam.2.name
-type        = string
-default     = webcam2
-abstract    = Name of the 3-rd emulated web camera
-description = Emulator-generated platform-independent camera name.
-
-# Defines name of the emulated webcam with index 3
-#
-name        = hw.webcam.3.name
-type        = string
-default     = webcam3
-abstract    = Name of the 4-th emulated web camera
-description = Emulator-generated platform-independent camera name.
-
-# Defines name of the emulated webcam with index 4
-#
-name        = hw.webcam.4.name
-type        = string
-default     = webcam4
-abstract    = Name of the 5-th emulated web camera
-description = Emulator-generated platform-independent camera name.
-
-# Defines name of the emulated webcam with index 5
-#
-name        = hw.webcam.5.name
-type        = string
-default     = webcam5
-abstract    = Name of the 6-th emulated web camera
-description = Emulator-generated platform-independent camera name.
-
-# Defines direction of the emulated webcam with index 0
-#
-name        = hw.webcam.0.direction
-type        = string
-default     = front
-abstract    = 1-st emulated web camera direction
-description = Direction of the 1-st emulated web camera
-
-# Defines direction of the emulated webcam with index 1
-# Note that first two cameras must face in opposite directions in order to enable
-# camera switch in the camera application.
-#
-name        = hw.webcam.1.direction
-type        = string
-default     = back
-abstract    = 2-nd emulated web camera direction
-description = Direction of the 2-nd emulated web camera
-
-# Defines direction of the emulated webcam with index 2
-#
-name        = hw.webcam.2.direction
-type        = string
-default     = front
-abstract    = 3-rd emulated web camera direction
-description = Direction of the 3-rd emulated web camera
-
-# Defines direction of the emulated webcam with index 3
-#
-name        = hw.webcam.3.direction
-type        = string
-default     = front
-abstract    = 4-th emulated web camera direction
-description = Direction of the 4-th emulated web camera
-
-# Defines direction of the emulated webcam with index 4
-#
-name        = hw.webcam.4.direction
-type        = string
-default     = front
-abstract    = 5-th emulated web camera direction
-description = Direction of the 5-th emulated web camera
-
-# Defines direction of the emulated webcam with index 5
-#
-name        = hw.webcam.5.direction
-type        = string
-default     = front
-abstract    = 6-th emulated web camera direction
-description = Direction of the 6-th emulated web camera
+default     = none
+abstract    = Configures camera facing front
+description = Must be 'emulated' for a fake camera, 'webcam<N>' for a web camera, or 'none' if front camera is disabled.
 
 # Maximum VM heap size
 # Higher values are required for high-dpi devices
diff --git a/android/camera/camera-service.c b/android/camera/camera-service.c
index 51af2de..173b6f5 100644
--- a/android/camera/camera-service.c
+++ b/android/camera/camera-service.c
@@ -233,7 +233,8 @@
 {
     int n;
     for (n = 0; n < num; n++) {
-        if (arr[n].display_name != NULL && !strcmp(arr[n].display_name, disp_name)) {
+        if (!arr[n].in_use && arr[n].display_name != NULL &&
+            !strcmp(arr[n].display_name, disp_name)) {
             return &arr[n];
         }
     }
@@ -265,6 +266,47 @@
  * CameraServiceDesc API
  *******************************************************************************/
 
+/* Initialized webcam emulation record in camera service descriptor.
+ * Param:
+ *  csd - Camera service descriptor to initialize a record in.
+ *  disp_name - Display name of a web camera ('webcam<N>') to use for emulation.
+ *  dir - Direction ('back', or 'front') that emulated camera is facing.
+ *  ci, ci_cnt - Array of webcam information for enumerated web cameras connected
+ *      to the host.
+ */
+static void
+_wecam_setup(CameraServiceDesc* csd,
+             const char* disp_name,
+             const char* dir,
+             CameraInfo* ci,
+             int ci_cnt)
+{
+    /* Find webcam record in the list of enumerated web cameras. */
+    CameraInfo* found = _camera_info_get_by_display_name(disp_name, ci, ci_cnt);
+    if (found == NULL) {
+        W("Camera name '%s' is not found in the list of connected cameras.\n"
+          "Use '-webcam-list' emulator option to obtain the list of connected camera names.\n",
+          disp_name);
+        return;
+    }
+
+    /* Save to the camera info array that will be used by the service. */
+    memcpy(csd->camera_info + csd->camera_count, found, sizeof(CameraInfo));
+    /* This camera is taken. */
+    found->in_use = 1;
+    /* Update direction parameter. */
+    if (csd->camera_info[csd->camera_count].direction != NULL) {
+        free(csd->camera_info[csd->camera_count].direction);
+    }
+    csd->camera_info[csd->camera_count].direction = ASTRDUP(dir);
+    D("Camera %d '%s' connected to '%s' facing %s using %.4s pixel format",
+      csd->camera_count, csd->camera_info[csd->camera_count].display_name,
+      csd->camera_info[csd->camera_count].device_name,
+      csd->camera_info[csd->camera_count].direction,
+      (const char*)(&csd->camera_info[csd->camera_count].pixel_format));
+      csd->camera_count++;
+}
+
 /* Initializes camera service descriptor.
  */
 static void
@@ -272,107 +314,34 @@
 {
     CameraInfo ci[MAX_CAMERA];
     int connected_cnt;
-    int i;
 
     /* Enumerate camera devices connected to the host. */
     memset(ci, 0, sizeof(CameraInfo) * MAX_CAMERA);
     memset(csd->camera_info, 0, sizeof(CameraInfo) * MAX_CAMERA);
     csd->camera_count = 0;
 
-    if (android_hw->hw_camera == 0) {
-        /* Camera emulation is disabled. Skip enumeration of webcameras. */
+    /* Lets see if HW config uses web cameras. */
+    if (memcmp(android_hw->hw_camera_back, "webcam", 6) &&
+        memcmp(android_hw->hw_camera_front, "webcam", 6)) {
+        /* Web camera emulation is disabled. Skip enumeration of webcameras. */
         return;
     }
 
+    /* Enumerate web cameras connected to the host. */
     connected_cnt = enumerate_camera_devices(ci, MAX_CAMERA);
     if (connected_cnt <= 0) {
         /* Nothing is connected - nothing to emulate. */
         return;
     }
 
-    /* For each webcam declared in hw.ini find an actual camera information
-     * descriptor, and save it into the service descriptor for the emulation.
-     * Stop the loop when all the connected cameras have been added to the
-     * service. */
-    for (i = 0; i < android_hw->hw_webcam_count &&
-                csd->camera_count < connected_cnt; i++) {
-        const char* disp_name;
-        const char* dir;
-        CameraInfo* found;
-
-        switch (i) {
-            case 0:
-                disp_name = android_hw->hw_webcam_0_name;
-                dir = android_hw->hw_webcam_0_direction;
-                break;
-            case 1:
-                disp_name = android_hw->hw_webcam_1_name;
-                dir = android_hw->hw_webcam_1_direction;
-                break;
-            case 2:
-                disp_name = android_hw->hw_webcam_2_name;
-                dir = android_hw->hw_webcam_2_direction;
-                break;
-            case 3:
-                disp_name = android_hw->hw_webcam_3_name;
-                dir = android_hw->hw_webcam_3_direction;
-                break;
-            case 4:
-                disp_name = android_hw->hw_webcam_4_name;
-                dir = android_hw->hw_webcam_4_direction;
-                break;
-            case 5:
-            default:
-                disp_name = android_hw->hw_webcam_5_name;
-                dir = android_hw->hw_webcam_5_direction;
-                break;
-        }
-        found = _camera_info_get_by_display_name(disp_name, ci, connected_cnt);
-        if (found != NULL) {
-            /* Save to the camera info array that will be used by the service.
-             * Note that we just copy everything over, and NULL the source
-             * record. */
-            memcpy(csd->camera_info + csd->camera_count, found, sizeof(CameraInfo));
-            /* Update direction parameter. */
-            if (csd->camera_info[csd->camera_count].direction != NULL) {
-                free(csd->camera_info[csd->camera_count].direction);
-            }
-            csd->camera_info[csd->camera_count].direction = ASTRDUP(dir);
-            D("Camera %d '%s' connected to '%s' facing %s using %.4s pixel format",
-              csd->camera_count, csd->camera_info[csd->camera_count].display_name,
-              csd->camera_info[csd->camera_count].device_name,
-              csd->camera_info[csd->camera_count].direction,
-              (const char*)(&csd->camera_info[csd->camera_count].pixel_format));
-            csd->camera_count++;
-            memset(found, 0, sizeof(CameraInfo));
-        } else {
-            W("Camera name '%s' is not found in the list of connected cameras.\n"
-              "Use '-webcam list' emulator option to obtain the list of connected camera names.\n",
-              disp_name);
-        }
+    /* Set up back camera emulation. */
+    if (!memcmp(android_hw->hw_camera_back, "webcam", 6)) {
+        _wecam_setup(csd, android_hw->hw_camera_back, "back", ci, connected_cnt);
     }
 
-    /* Make sure that camera 0 and camera 1 are facing in opposite directions.
-     * If they don't the camera application will crash on an attempt to switch
-     * cameras. */
-    if (csd->camera_count > 0) {
-        const char* cam2_dir = NULL;
-        const char* cam2_name = NULL;
-        if (csd->camera_count >= 2) {
-            cam2_dir = csd->camera_info[1].direction;
-            cam2_name = csd->camera_info[1].display_name;
-        } else if (strcmp(android_hw->hw_fakeCamera, "off")) {
-            cam2_dir = android_hw->hw_fakeCamera;
-            cam2_name = "fake camera";
-        }
-        if (cam2_dir != NULL && !strcmp(csd->camera_info[0].direction, cam2_dir)) {
-            W("Cameras '%s' and '%s' are both facing %s.\n"
-              "It is required by the camera application that first two emulated cameras\n"
-              "are facing in opposite directions. If they both are facing in the same direction,\n"
-              "the camera application will crash on an attempt to switch the camera.\n",
-              csd->camera_info[0].display_name, cam2_name, cam2_dir);
-
-        }
+    /* Set up front camera emulation. */
+    if (!memcmp(android_hw->hw_camera_front, "webcam", 6)) {
+        _wecam_setup(csd, android_hw->hw_camera_front, "front", ci, connected_cnt);
     }
 }
 
diff --git a/android/cmdline-options.h b/android/cmdline-options.h
index d490e40..aa85c0e 100644
--- a/android/cmdline-options.h
+++ b/android/cmdline-options.h
@@ -156,8 +156,9 @@
 
 OPT_PARAM( gpu, "<mode>", "set hardware OpenGLES emulation mode" )
 
-OPT_PARAM( fake_camera, "<mode>", "set fake camera emulation mode" )
-OPT_LIST( webcam, "name=<name>[,dir=<direction>]", "setup web camera emulation" )
+OPT_PARAM( camera_back, "<mode>", "set emulation mode for a camera facing back" )
+OPT_PARAM( camera_front, "<mode>", "set emulation mode for a camera facing front" )
+OPT_FLAG( webcam_list, "lists web cameras available for emulation" )
 
 OPT_PARAM( screen, "<mode>", "set emulated screen mode" )
 
diff --git a/android/help.c b/android/help.c
index db630e0..54d2f10 100644
--- a/android/help.c
+++ b/android/help.c
@@ -1457,34 +1457,36 @@
 }
 
 static void
-help_fake_camera(stralloc_t* out)
+help_camera_back(stralloc_t* out)
 {
     PRINTF(
-    "  Use -fake-camera <mode> to control fake camera emulation.\n"
+    "  Use -camera-back <mode> to control emulation of a camera facing back.\n"
     "  Valid values for <mode> are:\n\n"
 
-    "     off   -> disable fake camera emulation\n"
-    "     back  -> fake camera is facing back\n"
-    "     front -> fake camera is facing front\n\n"
+    "     emulated  -> camera will be emulated using software ('fake') camera emulation\n"
+    "     webcam<N> -> camera will be emulated using a webcamera connected to the host\n"
+    "     none      -> camera emulation will be disabled\n\n"
     );
 }
 
 static void
-help_webcam(stralloc_t* out)
+help_camera_front(stralloc_t* out)
 {
     PRINTF(
-    "  Use -webcam off to disable web camera emulation.\n"
-    "  Use -webcam list to list web cameras available for emulation.\n"
-    "  Use -webcam name=<name>[,dir=<direction>] to setup parameters for web camera emulation.\n"
+    "  Use -camera-front <mode> to control emulation of a camera facing front.\n"
+    "  Valid values for <mode> are:\n\n"
 
-    "  <name> platform-independent name identifying emulated camera device.\n"
-    "  use '-webcam list' to obtain the list of emulated camera devices.\n"
-    "  <direction> defines direction the camera is facing. Valid values are:\n\n"
+    "     emulated  -> camera will be emulated using software ('fake') camera emulation\n"
+    "     webcam<N> -> camera will be emulated using a webcamera connected to the host\n"
+    "     none      -> camera emulation will be disabled\n\n"
+    );
+}
 
-    "     front -> emulate camera as facing front\n"
-    "     back  -> emulate camera as facing back\n\n"
-
-    "  Default direction value for emulated web camera is 'front'\n\n"
+static void
+help_webcam_list(stralloc_t* out)
+{
+    PRINTF(
+    "  Use -webcam-list to list web cameras available for emulation.\n\n"
     );
 }
 
diff --git a/android/main.c b/android/main.c
index f8ad54b..9a763e5 100644
--- a/android/main.c
+++ b/android/main.c
@@ -155,65 +155,6 @@
     return convertMBToBytes(imageMB);
 }
 
-/* Parses a -webcam option, extracting 'name', and 'dir' values.
- * Param:
- *  param - -webcam option, that should be formatted as such:
- *      name=<name>[,dir=<direction>]
- * name, name_size - buffer (and its size) where to receive <name>
- * dir, dir_size - buffer (and its size) where to receive <direction>
- */
-static void
-_parseWebcamOption(const char* param,
-                   char* name, size_t name_size,
-                   char* dir, size_t dir_size)
-{
-    const char* dr;
-    const char* wc_opt = param;
-
-    /* Must start with 'name=' */
-    if (strlen(wc_opt) <= 5 || memcmp(wc_opt, "name=", 5)) {
-        derror("Invalid value for -webcam parameter: %s\n", param);
-        exit(1);
-    }
-
-    /* Move on to 'name' value. */
-    wc_opt += 5;
-    dr = strchr(wc_opt, ',');
-    if (dr == NULL) {
-        dr = wc_opt + strlen(wc_opt);
-    }
-
-    /* Make sure that <name> fits */
-    if ((dr - wc_opt) < name_size) {
-        memcpy(name, wc_opt, dr - wc_opt);
-        name[dr - wc_opt] = '\0';
-        if (*dr == '\0') {
-            /* Default direction value is 'front' */
-            strcpy(dir, "front");
-            return;
-        } else {
-            dr++;
-        }
-    } else {
-        derror("Invalid <name> value for -webcam parameter: %s\n", param);
-        exit(1);
-    }
-
-    /* Parse 'dir'. Must begin with 'dir=' */
-    if (strlen(dr) <= 4 || memcmp(dr, "dir=", 4)) {
-        derror("Invalid value for -webcam parameter: %s\n", param);
-        exit(1);
-    }
-    dr += 4;
-    /* Check the bounds, and the values */
-    if (strlen(dr) >= dir_size || (strcmp(dr, "front") && strcmp(dr, "back"))) {
-        derror("Invalid <direction> value for -webcam parameter: %s\n"
-               "Valid values are: 'front', or 'back'\n", param);
-        exit(1);
-    }
-    strcpy(dir, dr);
-}
-
 int main(int argc, char **argv)
 {
     char   tmp[MAX_PATH];
@@ -1164,90 +1105,36 @@
         exit(1);
     }
 
-    if (opts->fake_camera) {
-        if (!strcmp(opts->fake_camera, "back") ||
-            !strcmp(opts->fake_camera, "front") ||
-            !strcmp(opts->fake_camera, "off")) {
-            hw->hw_fakeCamera = ASTRDUP(opts->fake_camera);
-        } else {
-            derror("Invalid value for -fake-camera <mode> parameter: %s\n",
-                   opts->fake_camera);
-            derror("Valid values are: back, front, or off\n");
+    /* Deal with camera emulation */
+    if (opts->webcam_list) {
+        /* List connected webcameras */
+        args[n++] = "-list-webcam";
+    }
+
+    if (opts->camera_back) {
+        /* Validate parameter. */
+        if (memcmp(opts->camera_back, "webcam", 6) &&
+            strcmp(opts->camera_back, "emulated") &&
+            strcmp(opts->camera_back, "none")) {
+            derror("Invalid value for -camera-back <mode> parameter: %s\n"
+                   "Valid values are: 'emulated', 'webcam<N>', or 'none'\n",
+                   opts->camera_back);
             exit(1);
         }
+        hw->hw_camera_back = ASTRDUP(opts->camera_back);
     }
 
-    int webcam_num = 0;
-    if (opts->webcam != NULL) {
-        ParamList*  pl = opts->webcam;
-        for ( ; pl != NULL; pl = pl->next ) {
-            char webcam_name[64];
-            char webcam_dir[16];
-            if (!strcmp(pl->param, "off")) {
-                /* If 'off' is passed, there must be no other -webcam options. */
-                if (webcam_num || pl->next != NULL) {
-                    derror("'-webcam off' cannot be combined with other -webcam otions\n");
-                    exit(1);
-                }
-                break;
-            }
-            if (!strcmp(pl->param, "list")) {
-                /* If 'list' is passed, there must be no other -webcam options. */
-                if (webcam_num || pl->next != NULL) {
-                    derror("'-webcam list' cannot be combined with other -webcam otions\n");
-                    exit(1);
-                }
-                args[n++] = "-list-webcam";
-                break;
-            }
-            /* Extract name, and direction */
-            _parseWebcamOption(pl->param, webcam_name, sizeof(webcam_name),
-                               webcam_dir, sizeof(webcam_dir));
-            /* Save them to appropriate field in hw.ini */
-            switch (webcam_num) {
-                case 0:
-                    hw->hw_webcam_0_name        = ASTRDUP(webcam_name);
-                    hw->hw_webcam_0_direction   = ASTRDUP(webcam_dir);
-                    break;
-                case 1:
-                    hw->hw_webcam_1_name        = ASTRDUP(webcam_name);
-                    hw->hw_webcam_1_direction   = ASTRDUP(webcam_dir);
-                    break;
-                case 2:
-                    hw->hw_webcam_2_name        = ASTRDUP(webcam_name);
-                    hw->hw_webcam_2_direction   = ASTRDUP(webcam_dir);
-                    break;
-                case 3:
-                    hw->hw_webcam_3_name        = ASTRDUP(webcam_name);
-                    hw->hw_webcam_3_direction   = ASTRDUP(webcam_dir);
-                    break;
-                case 4:
-                    hw->hw_webcam_4_name        = ASTRDUP(webcam_name);
-                    hw->hw_webcam_4_direction   = ASTRDUP(webcam_dir);
-                    break;
-                case 5:
-                    hw->hw_webcam_5_name        = ASTRDUP(webcam_name);
-                    hw->hw_webcam_5_direction   = ASTRDUP(webcam_dir);
-                    break;
-                default:
-                    derror("Too many -webcam options. Maximum number of -webcam options is 6\n");
-                    exit(1);
-            }
-            webcam_num++;
+    if (opts->camera_front) {
+        /* Validate parameter. */
+        if (memcmp(opts->camera_front, "webcam", 6) &&
+            strcmp(opts->camera_front, "emulated") &&
+            strcmp(opts->camera_front, "none")) {
+            derror("Invalid value for -camera-front <mode> parameter: %s\n"
+                   "Valid values are: 'emulated', 'webcam<N>', or 'none'\n",
+                   opts->camera_front);
+            exit(1);
         }
-        hw->hw_webcam_count = webcam_num;
-    }
-
-    /* Command line options related to webcam, and fake camera should
-     * override camera emulation flag, set in AVD. */
-    if (hw->hw_camera == 0) {
-        /* Camera emulation is disabled in AVD. Lets see if command line enables
-         * webcam, or fake camera emulation. */
-        if (webcam_num != 0 ||
-            (opts->fake_camera && strcmp(hw->hw_fakeCamera, "off") != 0)) {
-            /* Command line parameters enable camera emulation. */
-            hw->hw_camera = 1;
-        }
+        hw->hw_camera_front = ASTRDUP(opts->camera_front);
     }
 
     /* physical memory is now in hw->hw_ramSize */