public static CameraProxy getCameraProxy(MavLinkDrone drone, List<CameraDetail> cameraDetails) {
    final CameraDetail camDetail;
    final FootPrint currentFieldOfView;
    final List<FootPrint> proxyPrints = new ArrayList<>();

    if (drone == null) {
      camDetail = new CameraDetail();
      currentFieldOfView = new FootPrint();
    } else {
      Camera droneCamera = drone.getCamera();

      camDetail = ProxyUtils.getCameraDetail(droneCamera.getCamera());

      List<Footprint> footprints = droneCamera.getFootprints();
      for (Footprint footprint : footprints) {
        proxyPrints.add(CommonApiUtils.getProxyCameraFootPrint(footprint));
      }

      Gps droneGps = (Gps) drone.getAttribute(AttributeType.GPS);
      currentFieldOfView =
          droneGps != null && droneGps.isValid()
              ? CommonApiUtils.getProxyCameraFootPrint(droneCamera.getCurrentFieldOfView())
              : new FootPrint();
    }

    return new CameraProxy(camDetail, currentFieldOfView, proxyPrints, cameraDetails);
  }
  public static void enableFollowMe(
      DroneManager droneMgr,
      Handler droneHandler,
      FollowType followType,
      ICommandListener listener) {
    if (droneMgr == null) return;

    final FollowAlgorithm.FollowModes selectedMode =
        CommonApiUtils.followTypeToMode(droneMgr.getDrone(), followType);

    if (selectedMode != null) {
      final Follow followMe = droneMgr.getFollowMe();
      if (followMe == null) return;

      if (!followMe.isEnabled()) followMe.toggleFollowMeState();

      FollowAlgorithm currentAlg = followMe.getFollowAlgorithm();
      if (currentAlg.getType() != selectedMode) {
        if (selectedMode == FollowAlgorithm.FollowModes.SOLO_SHOT
            && !SoloApiUtils.isSoloLinkFeatureAvailable(droneMgr, listener)) return;

        followMe.setAlgorithm(selectedMode.getAlgorithmType(droneMgr, droneHandler));
        postSuccessEvent(listener);
      }
    }
  }
  public static FollowState getFollowState(Follow followMe) {
    if (followMe == null) return new FollowState();

    final int state;
    switch (followMe.getState()) {
      default:
      case FOLLOW_INVALID_STATE:
        state = FollowState.STATE_INVALID;
        break;

      case FOLLOW_DRONE_NOT_ARMED:
        state = FollowState.STATE_DRONE_NOT_ARMED;
        break;

      case FOLLOW_DRONE_DISCONNECTED:
        state = FollowState.STATE_DRONE_DISCONNECTED;
        break;

      case FOLLOW_START:
        state = FollowState.STATE_START;
        break;

      case FOLLOW_RUNNING:
        state = FollowState.STATE_RUNNING;
        break;

      case FOLLOW_END:
        state = FollowState.STATE_END;
        break;
    }

    final FollowAlgorithm currentAlg = followMe.getFollowAlgorithm();
    Map<String, Object> modeParams = currentAlg.getParams();
    Bundle params = new Bundle();
    for (Map.Entry<String, Object> entry : modeParams.entrySet()) {
      switch (entry.getKey()) {
        case FollowType.EXTRA_FOLLOW_ROI_TARGET:
          LatLongAlt target = (LatLongAlt) entry.getValue();
          if (target != null) {
            params.putParcelable(entry.getKey(), target);
          }
          break;

        case FollowType.EXTRA_FOLLOW_RADIUS:
          Double radius = (Double) entry.getValue();
          if (radius != null) params.putDouble(entry.getKey(), radius);
          break;
      }
    }
    return new FollowState(state, CommonApiUtils.followModeToType(currentAlg.getType()), params);
  }
  public static State getState(MavLinkDrone drone, boolean isConnected, Vibration vibration) {
    if (drone == null) return new State();

    org.droidplanner.services.android.core.drone.variables.State droneState = drone.getState();
    ApmModes droneMode = droneState.getMode();
    AccelCalibration accelCalibration = drone.getCalibrationSetup();
    String calibrationMessage =
        accelCalibration != null && accelCalibration.isCalibrating()
            ? accelCalibration.getMessage()
            : null;

    final msg_ekf_status_report ekfStatus = droneState.getEkfStatus();
    final EkfStatus proxyEkfStatus =
        ekfStatus == null
            ? new EkfStatus()
            : new EkfStatus(
                ekfStatus.flags,
                ekfStatus.compass_variance,
                ekfStatus.pos_horiz_variance,
                ekfStatus.terrain_alt_variance,
                ekfStatus.velocity_variance,
                ekfStatus.pos_vert_variance);

    return new State(
        isConnected,
        CommonApiUtils.getVehicleMode(droneMode),
        droneState.isArmed(),
        droneState.isFlying(),
        droneState.getErrorId(),
        drone.getMavlinkVersion(),
        calibrationMessage,
        droneState.getFlightStartTime(),
        proxyEkfStatus,
        isConnected && drone.isConnectionAlive(),
        vibration);
  }
  public static Type getType(MavLinkDrone drone) {
    if (drone == null) return new Type();

    return new Type(CommonApiUtils.getDroneProxyType(drone.getType()), drone.getFirmwareVersion());
  }