def check_dates_in_range(activity_dates, start_date=None, end_date=None):
    """Check that an activity's dates fall into the allowed range.
    Prefers the planned date over the actual date when available.
    If the activity dates are missing, returns True
    @param activity_dates: the parsed activity dates.
    @param start_date: the start date in ISO 8601 format (YYYY-MM-DD), or None for no start limit.
    @param end_date: the end date in ISO 8601 format (YYYY-MM-DD), or None for no end limit.
    @returns: True if the activity is in range (or can't be determined).
    """
    if start_date:
        if 'end_actual' in activity_dates:
            if start_date is None or activity_dates['end_actual'
                ] <= start_date:
                return False
        elif 'end_planned' in activity_dates:
            if start_date is None or activity_dates['end_planned'
                ] <= start_date:
                return False
    if end_date:
        if 'start_actual' in activity_dates:
            if end_date is None or activity_dates['start_actual'] >= end_date:
                return False
        elif 'start_planned' in activity_dates:
            if end_date is None or activity_dates['start_planned'] >= end_date:
                return False
    return True
