public void createAndroidVirtualDeviceAvailable(
      @Observes AndroidVirtualDeviceEvent event,
      AndroidBridge bridge,
      AndroidExtensionConfiguration configuration,
      AndroidSdk sdk,
      ProcessExecutor executor)
      throws AndroidExecutionException {

    if (!bridge.isConnected()) {
      throw new IllegalStateException(
          "Android debug bridge must be connected in order to spawn emulator");
    }

    String name = configuration.getAvdName();
    AndroidDevice running = null;
    for (AndroidDevice device : bridge.getDevices()) {
      if (equalsIgnoreNulls(name, device.getAvdName())) {
        running = device;
        break;
      }
    }

    if (running == null) {

      CountDownWatch countdown =
          new CountDownWatch(configuration.getEmulatorBootupTimeoutInSeconds(), TimeUnit.SECONDS);
      log.log(
          Level.INFO,
          "Waiting {0} seconds for emulator {1} to be started and connected.",
          new Object[] {countdown.timeout(), name});

      // discover what device was added here
      DeviceConnectDiscovery deviceDiscovery = new DeviceConnectDiscovery();
      AndroidDebugBridge.addDeviceChangeListener(deviceDiscovery);

      Process emulator = startEmulator(executor, sdk, name, configuration.getEmulatorOptions());
      androidEmulator.set(new AndroidEmulator(emulator));

      log.log(
          Level.FINE,
          "Emulator process started, {0} seconds remaining to start the device {1}",
          new Object[] {countdown.timeLeft(), name});

      waitUntilBootUpIsComplete(deviceDiscovery, executor, sdk, countdown);
      running = deviceDiscovery.getDiscoveredDevice();

      AndroidDebugBridge.removeDeviceChangeListener(deviceDiscovery);

    } else {
      log.info(
          "Emulator for device "
              + name
              + " is already started, device serial is "
              + running.getSerialNumber()
              + ". Emulator will not be reinitialized.");
    }

    // fire event that we have a device ready
    androidDevice.set(running);
    androidDeviceReady.fire(new AndroidDeviceReady(running));
  }
  private void waitUntilBootUpIsComplete(
      final DeviceConnectDiscovery deviceDiscovery,
      final ProcessExecutor executor,
      final AndroidSdk sdk,
      final CountDownWatch countdown)
      throws AndroidExecutionException {

    try {
      boolean isOnline =
          executor.scheduleUntilTrue(
              new Callable<Boolean>() {
                @Override
                public Boolean call() throws Exception {
                  return deviceDiscovery.isOnline();
                }
              },
              countdown.timeLeft(),
              countdown.getTimeUnit().convert(1, TimeUnit.SECONDS),
              countdown.getTimeUnit());

      if (isOnline == false) {
        throw new IllegalStateException(
            "No emulator device was brough online during "
                + countdown.timeout()
                + " seconds to Android Debug Bridge. Please increase the time limit in order to get emulator connected.");
      }

      // device is connected to ADB
      final AndroidDevice connectedDevice = deviceDiscovery.getDiscoveredDevice();
      isOnline =
          executor.scheduleUntilTrue(
              new Callable<Boolean>() {
                @Override
                public Boolean call() throws Exception {
                  // check properties of underlying process
                  List<String> props =
                      executor.execute(
                          Collections.<String, String>emptyMap(),
                          sdk.getAdbPath(),
                          "-s",
                          connectedDevice.getSerialNumber(),
                          "shell",
                          "getprop");
                  for (String line : props) {
                    if (line.contains("[ro.runtime.firstboot]")) {
                      // boot is completed
                      return true;
                    }
                  }
                  return false;
                }
              },
              countdown.timeLeft(),
              countdown.getTimeUnit().convert(1, TimeUnit.SECONDS),
              countdown.getTimeUnit());

      if (log.isLoggable(Level.INFO)) {
        log.log(
            Level.INFO,
            "Android emulator {0} was started within {1} seconds",
            new Object[] {connectedDevice.getAvdName(), countdown.timeElapsed()});
      }

      if (isOnline == false) {
        throw new AndroidExecutionException(
            "Emulator device hasn't started properly in "
                + countdown.timeout()
                + " seconds. Please increase the time limit in order to get emulator booted.");
      }
    } catch (InterruptedException e) {
      throw new AndroidExecutionException(e, "Emulator device startup failed.");
    } catch (ExecutionException e) {
      throw new AndroidExecutionException(e, "Emulator device startup failed.");
    }
  }