mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-01 01:02:21 +02:00
Compare commits
119 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 52226c8ef4 | |||
| c254a6ec75 | |||
| 0ecf4863a7 | |||
| 325196159d | |||
| 6adbf39e52 | |||
| db1a37f015 | |||
| 7ca9423fbf | |||
| 11c5ec43e2 | |||
| 3f891f7fb4 | |||
| 49260a0517 | |||
| 1392c5d92a | |||
| c641b436ce | |||
| 6948c2db41 | |||
| fb904f4a0b | |||
| 6c006cc9c7 | |||
| 7a73757ab1 | |||
| 9725cca2bf | |||
| 252f71e75f | |||
| fc2341515c | |||
| 77719f5bcd | |||
| 565ef7f12b | |||
| f4208e2f6b | |||
| 4b3ff45609 | |||
| 6dd9630bae | |||
| a4ec68def6 | |||
| d80be8b2a9 | |||
| 7d7ab5778a | |||
| 1749c776ab | |||
| 336b9eaa9f | |||
| 0fc2209ceb | |||
| 477819d730 | |||
| 425ea0f216 | |||
| 779681088c | |||
| f824b31891 | |||
| d316a63fca | |||
| 55cf60ef2f | |||
| 01598d0a55 | |||
| 4bcba07706 | |||
| ed979bdc80 | |||
| 1d81070d9e | |||
| 357a1de07d | |||
| 84380d8373 | |||
| 97c3e5a938 | |||
| 8fbcf5dcc0 | |||
| 8c364ba7e2 | |||
| 0c5c49cd92 | |||
| 62d9e81b23 | |||
| 1a5acc8f2d | |||
| 7e9b99ae1c | |||
| 1f86250e46 | |||
| 7f6e3f7c69 | |||
| e0b84df8f6 | |||
| a431850793 | |||
| 5c17c8ffcf | |||
| 0691524dfa | |||
| 1c825b052e | |||
| eb8d28dfc1 | |||
| 9f1ea4d745 | |||
| dbd64a8075 | |||
| 75a88ca0e1 | |||
| 2af19b00e5 | |||
| 11db0d1a4f | |||
| 6a4adee2f2 | |||
| d04b420c56 | |||
| 0122539d0f | |||
| 0b8c2a0ef6 | |||
| cef363562c | |||
| e681531186 | |||
| 65c4b85bc4 | |||
| d7022a07a2 | |||
| 81b090893b | |||
| 3dca9304c4 | |||
| 7fc6492e13 | |||
| 80d968dd0f | |||
| f336a1da12 | |||
| 1657bf5ec1 | |||
| d046ca1cd8 | |||
| 6c852091ce | |||
| 4906d3f942 | |||
| 0395394e26 | |||
| ebcc7dc46e | |||
| 1e4246e73a | |||
| 3ca8381504 | |||
| b92457cb23 | |||
| 4baec1e672 | |||
| c702c5a4a0 | |||
| 24c2c5fc1b | |||
| 8797b033a3 | |||
| b2c4cdc4aa | |||
| ae37ec9c33 | |||
| ccc18739a4 | |||
| f48c4806b5 | |||
| 3aadf6d5d8 | |||
| 2f2679c775 | |||
| 442e23b106 | |||
| 65249f11b2 | |||
| 34b5c2ab18 | |||
| 93919183be | |||
| 1915641d78 | |||
| c2c7cad3eb | |||
| e4957e45af | |||
| 77bce9a5eb | |||
| 6538f0d587 | |||
| 5b0e7e5065 | |||
| d6cf8ba90e | |||
| 29568d0e3f | |||
| a571c4c93b | |||
| 073fed6c84 | |||
| 6847e1f899 | |||
| 427048ac11 | |||
| 240ea47c43 | |||
| 068d56a850 | |||
| 76d02da973 | |||
| 4664895ae3 | |||
| 5235c8cf83 | |||
| 4f040ac79f | |||
| dcad42bf4d | |||
| 2eea93a4a3 | |||
| 55e419475a |
+965
@@ -0,0 +1,965 @@
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = false
|
||||
max_line_length = 100
|
||||
tab_width = 4
|
||||
ij_continuation_indent_size = 8
|
||||
ij_formatter_off_tag = @formatter:off
|
||||
ij_formatter_on_tag = @formatter:on
|
||||
ij_formatter_tags_enabled = false
|
||||
ij_smart_tabs = false
|
||||
ij_visual_guides = none
|
||||
ij_wrap_on_typing = false
|
||||
|
||||
[*.java]
|
||||
ij_java_align_consecutive_assignments = false
|
||||
ij_java_align_consecutive_variable_declarations = false
|
||||
ij_java_align_group_field_declarations = false
|
||||
ij_java_align_multiline_annotation_parameters = false
|
||||
ij_java_align_multiline_array_initializer_expression = false
|
||||
ij_java_align_multiline_assignment = false
|
||||
ij_java_align_multiline_binary_operation = false
|
||||
ij_java_align_multiline_chained_methods = false
|
||||
ij_java_align_multiline_deconstruction_list_components = true
|
||||
ij_java_align_multiline_extends_list = false
|
||||
ij_java_align_multiline_for = true
|
||||
ij_java_align_multiline_method_parentheses = false
|
||||
ij_java_align_multiline_parameters = true
|
||||
ij_java_align_multiline_parameters_in_calls = false
|
||||
ij_java_align_multiline_parenthesized_expression = false
|
||||
ij_java_align_multiline_records = true
|
||||
ij_java_align_multiline_resources = true
|
||||
ij_java_align_multiline_ternary_operation = false
|
||||
ij_java_align_multiline_text_blocks = false
|
||||
ij_java_align_multiline_throws_list = false
|
||||
ij_java_align_subsequent_simple_methods = false
|
||||
ij_java_align_throws_keyword = false
|
||||
ij_java_align_types_in_multi_catch = true
|
||||
ij_java_annotation_parameter_wrap = off
|
||||
ij_java_array_initializer_new_line_after_left_brace = false
|
||||
ij_java_array_initializer_right_brace_on_new_line = false
|
||||
ij_java_array_initializer_wrap = off
|
||||
ij_java_assert_statement_colon_on_next_line = false
|
||||
ij_java_assert_statement_wrap = off
|
||||
ij_java_assignment_wrap = off
|
||||
ij_java_binary_operation_sign_on_next_line = false
|
||||
ij_java_binary_operation_wrap = off
|
||||
ij_java_blank_lines_after_anonymous_class_header = 0
|
||||
ij_java_blank_lines_after_class_header = 0
|
||||
ij_java_blank_lines_after_imports = 1
|
||||
ij_java_blank_lines_after_package = 1
|
||||
ij_java_blank_lines_around_class = 1
|
||||
ij_java_blank_lines_around_field = 0
|
||||
ij_java_blank_lines_around_field_in_interface = 0
|
||||
ij_java_blank_lines_around_initializer = 1
|
||||
ij_java_blank_lines_around_method = 1
|
||||
ij_java_blank_lines_around_method_in_interface = 1
|
||||
ij_java_blank_lines_before_class_end = 0
|
||||
ij_java_blank_lines_before_imports = 1
|
||||
ij_java_blank_lines_before_method_body = 0
|
||||
ij_java_blank_lines_before_package = 0
|
||||
ij_java_block_brace_style = end_of_line
|
||||
ij_java_block_comment_add_space = false
|
||||
ij_java_block_comment_at_first_column = true
|
||||
ij_java_builder_methods = none
|
||||
ij_java_call_parameters_new_line_after_left_paren = false
|
||||
ij_java_call_parameters_right_paren_on_new_line = false
|
||||
ij_java_call_parameters_wrap = off
|
||||
ij_java_case_statement_on_separate_line = true
|
||||
ij_java_catch_on_new_line = false
|
||||
ij_java_class_annotation_wrap = split_into_lines
|
||||
ij_java_class_brace_style = end_of_line
|
||||
ij_java_class_count_to_use_import_on_demand = 99
|
||||
ij_java_class_names_in_javadoc = 1
|
||||
ij_java_deconstruction_list_wrap = normal
|
||||
ij_java_do_not_indent_top_level_class_members = false
|
||||
ij_java_do_not_wrap_after_single_annotation = false
|
||||
ij_java_do_not_wrap_after_single_annotation_in_parameter = false
|
||||
ij_java_do_while_brace_force = never
|
||||
ij_java_doc_add_blank_line_after_description = true
|
||||
ij_java_doc_add_blank_line_after_param_comments = false
|
||||
ij_java_doc_add_blank_line_after_return = false
|
||||
ij_java_doc_add_p_tag_on_empty_lines = true
|
||||
ij_java_doc_align_exception_comments = true
|
||||
ij_java_doc_align_param_comments = true
|
||||
ij_java_doc_do_not_wrap_if_one_line = false
|
||||
ij_java_doc_enable_formatting = true
|
||||
ij_java_doc_enable_leading_asterisks = true
|
||||
ij_java_doc_indent_on_continuation = false
|
||||
ij_java_doc_keep_empty_lines = true
|
||||
ij_java_doc_keep_empty_parameter_tag = true
|
||||
ij_java_doc_keep_empty_return_tag = true
|
||||
ij_java_doc_keep_empty_throws_tag = true
|
||||
ij_java_doc_keep_invalid_tags = true
|
||||
ij_java_doc_param_description_on_new_line = false
|
||||
ij_java_doc_preserve_line_breaks = false
|
||||
ij_java_doc_use_throws_not_exception_tag = true
|
||||
ij_java_else_on_new_line = false
|
||||
ij_java_enum_constants_wrap = off
|
||||
ij_java_extends_keyword_wrap = off
|
||||
ij_java_extends_list_wrap = off
|
||||
ij_java_field_annotation_wrap = split_into_lines
|
||||
ij_java_finally_on_new_line = false
|
||||
ij_java_for_brace_force = never
|
||||
ij_java_for_statement_new_line_after_left_paren = false
|
||||
ij_java_for_statement_right_paren_on_new_line = false
|
||||
ij_java_for_statement_wrap = off
|
||||
ij_java_generate_final_locals = false
|
||||
ij_java_generate_final_parameters = false
|
||||
ij_java_if_brace_force = never
|
||||
ij_java_imports_layout = $android.**,$androidx.**,$com.**,$junit.**,$net.**,$org.**,$java.**,$javax.**,$*,|,android.**,|,androidx.**,|,com.**,|,junit.**,|,net.**,|,org.**,|,java.**,|,javax.**,|,*,|
|
||||
ij_java_indent_case_from_switch = true
|
||||
ij_java_insert_inner_class_imports = false
|
||||
ij_java_insert_override_annotation = true
|
||||
ij_java_keep_blank_lines_before_right_brace = 2
|
||||
ij_java_keep_blank_lines_between_package_declaration_and_header = 2
|
||||
ij_java_keep_blank_lines_in_code = 2
|
||||
ij_java_keep_blank_lines_in_declarations = 2
|
||||
ij_java_keep_builder_methods_indents = false
|
||||
ij_java_keep_control_statement_in_one_line = true
|
||||
ij_java_keep_first_column_comment = true
|
||||
ij_java_keep_indents_on_empty_lines = false
|
||||
ij_java_keep_line_breaks = true
|
||||
ij_java_keep_multiple_expressions_in_one_line = false
|
||||
ij_java_keep_simple_blocks_in_one_line = false
|
||||
ij_java_keep_simple_classes_in_one_line = false
|
||||
ij_java_keep_simple_lambdas_in_one_line = false
|
||||
ij_java_keep_simple_methods_in_one_line = false
|
||||
ij_java_label_indent_absolute = false
|
||||
ij_java_label_indent_size = 0
|
||||
ij_java_lambda_brace_style = end_of_line
|
||||
ij_java_layout_static_imports_separately = true
|
||||
ij_java_line_comment_add_space = false
|
||||
ij_java_line_comment_add_space_on_reformat = false
|
||||
ij_java_line_comment_at_first_column = true
|
||||
ij_java_method_annotation_wrap = split_into_lines
|
||||
ij_java_method_brace_style = end_of_line
|
||||
ij_java_method_call_chain_wrap = off
|
||||
ij_java_method_parameters_new_line_after_left_paren = false
|
||||
ij_java_method_parameters_right_paren_on_new_line = false
|
||||
ij_java_method_parameters_wrap = off
|
||||
ij_java_modifier_list_wrap = false
|
||||
ij_java_multi_catch_types_wrap = normal
|
||||
ij_java_names_count_to_use_import_on_demand = 99
|
||||
ij_java_new_line_after_lparen_in_annotation = false
|
||||
ij_java_new_line_after_lparen_in_deconstruction_pattern = true
|
||||
ij_java_new_line_after_lparen_in_record_header = false
|
||||
ij_java_parameter_annotation_wrap = off
|
||||
ij_java_parentheses_expression_new_line_after_left_paren = false
|
||||
ij_java_parentheses_expression_right_paren_on_new_line = false
|
||||
ij_java_place_assignment_sign_on_next_line = false
|
||||
ij_java_prefer_longer_names = true
|
||||
ij_java_prefer_parameters_wrap = false
|
||||
ij_java_record_components_wrap = normal
|
||||
ij_java_repeat_synchronized = true
|
||||
ij_java_replace_instanceof_and_cast = false
|
||||
ij_java_replace_null_check = true
|
||||
ij_java_replace_sum_lambda_with_method_ref = true
|
||||
ij_java_resource_list_new_line_after_left_paren = false
|
||||
ij_java_resource_list_right_paren_on_new_line = false
|
||||
ij_java_resource_list_wrap = off
|
||||
ij_java_rparen_on_new_line_in_annotation = false
|
||||
ij_java_rparen_on_new_line_in_deconstruction_pattern = true
|
||||
ij_java_rparen_on_new_line_in_record_header = false
|
||||
ij_java_space_after_closing_angle_bracket_in_type_argument = false
|
||||
ij_java_space_after_colon = true
|
||||
ij_java_space_after_comma = true
|
||||
ij_java_space_after_comma_in_type_arguments = true
|
||||
ij_java_space_after_for_semicolon = true
|
||||
ij_java_space_after_quest = true
|
||||
ij_java_space_after_type_cast = true
|
||||
ij_java_space_before_annotation_array_initializer_left_brace = false
|
||||
ij_java_space_before_annotation_parameter_list = false
|
||||
ij_java_space_before_array_initializer_left_brace = false
|
||||
ij_java_space_before_catch_keyword = true
|
||||
ij_java_space_before_catch_left_brace = true
|
||||
ij_java_space_before_catch_parentheses = true
|
||||
ij_java_space_before_class_left_brace = true
|
||||
ij_java_space_before_colon = true
|
||||
ij_java_space_before_colon_in_foreach = true
|
||||
ij_java_space_before_comma = false
|
||||
ij_java_space_before_deconstruction_list = false
|
||||
ij_java_space_before_do_left_brace = true
|
||||
ij_java_space_before_else_keyword = true
|
||||
ij_java_space_before_else_left_brace = true
|
||||
ij_java_space_before_finally_keyword = true
|
||||
ij_java_space_before_finally_left_brace = true
|
||||
ij_java_space_before_for_left_brace = true
|
||||
ij_java_space_before_for_parentheses = true
|
||||
ij_java_space_before_for_semicolon = false
|
||||
ij_java_space_before_if_left_brace = true
|
||||
ij_java_space_before_if_parentheses = true
|
||||
ij_java_space_before_method_call_parentheses = false
|
||||
ij_java_space_before_method_left_brace = true
|
||||
ij_java_space_before_method_parentheses = false
|
||||
ij_java_space_before_opening_angle_bracket_in_type_parameter = false
|
||||
ij_java_space_before_quest = true
|
||||
ij_java_space_before_switch_left_brace = true
|
||||
ij_java_space_before_switch_parentheses = true
|
||||
ij_java_space_before_synchronized_left_brace = true
|
||||
ij_java_space_before_synchronized_parentheses = true
|
||||
ij_java_space_before_try_left_brace = true
|
||||
ij_java_space_before_try_parentheses = true
|
||||
ij_java_space_before_type_parameter_list = false
|
||||
ij_java_space_before_while_keyword = true
|
||||
ij_java_space_before_while_left_brace = true
|
||||
ij_java_space_before_while_parentheses = true
|
||||
ij_java_space_inside_one_line_enum_braces = false
|
||||
ij_java_space_within_empty_array_initializer_braces = false
|
||||
ij_java_space_within_empty_method_call_parentheses = false
|
||||
ij_java_space_within_empty_method_parentheses = false
|
||||
ij_java_spaces_around_additive_operators = true
|
||||
ij_java_spaces_around_annotation_eq = true
|
||||
ij_java_spaces_around_assignment_operators = true
|
||||
ij_java_spaces_around_bitwise_operators = true
|
||||
ij_java_spaces_around_equality_operators = true
|
||||
ij_java_spaces_around_lambda_arrow = true
|
||||
ij_java_spaces_around_logical_operators = true
|
||||
ij_java_spaces_around_method_ref_dbl_colon = false
|
||||
ij_java_spaces_around_multiplicative_operators = true
|
||||
ij_java_spaces_around_relational_operators = true
|
||||
ij_java_spaces_around_shift_operators = true
|
||||
ij_java_spaces_around_type_bounds_in_type_parameters = true
|
||||
ij_java_spaces_around_unary_operator = false
|
||||
ij_java_spaces_within_angle_brackets = false
|
||||
ij_java_spaces_within_annotation_parentheses = false
|
||||
ij_java_spaces_within_array_initializer_braces = false
|
||||
ij_java_spaces_within_braces = false
|
||||
ij_java_spaces_within_brackets = false
|
||||
ij_java_spaces_within_cast_parentheses = false
|
||||
ij_java_spaces_within_catch_parentheses = false
|
||||
ij_java_spaces_within_deconstruction_list = false
|
||||
ij_java_spaces_within_for_parentheses = false
|
||||
ij_java_spaces_within_if_parentheses = false
|
||||
ij_java_spaces_within_method_call_parentheses = false
|
||||
ij_java_spaces_within_method_parentheses = false
|
||||
ij_java_spaces_within_parentheses = false
|
||||
ij_java_spaces_within_record_header = false
|
||||
ij_java_spaces_within_switch_parentheses = false
|
||||
ij_java_spaces_within_synchronized_parentheses = false
|
||||
ij_java_spaces_within_try_parentheses = false
|
||||
ij_java_spaces_within_while_parentheses = false
|
||||
ij_java_special_else_if_treatment = true
|
||||
ij_java_subclass_name_suffix = Impl
|
||||
ij_java_ternary_operation_signs_on_next_line = false
|
||||
ij_java_ternary_operation_wrap = off
|
||||
ij_java_test_name_suffix = Test
|
||||
ij_java_throws_keyword_wrap = off
|
||||
ij_java_throws_list_wrap = off
|
||||
ij_java_use_external_annotations = false
|
||||
ij_java_use_fq_class_names = false
|
||||
ij_java_use_relative_indents = false
|
||||
ij_java_use_single_class_imports = true
|
||||
ij_java_variable_annotation_wrap = off
|
||||
ij_java_visibility = public
|
||||
ij_java_while_brace_force = never
|
||||
ij_java_while_on_new_line = false
|
||||
ij_java_wrap_comments = false
|
||||
ij_java_wrap_first_method_in_call_chain = false
|
||||
ij_java_wrap_long_lines = false
|
||||
|
||||
[*.properties]
|
||||
ij_properties_align_group_field_declarations = false
|
||||
ij_properties_keep_blank_lines = false
|
||||
ij_properties_key_value_delimiter = equals
|
||||
ij_properties_spaces_around_key_value_delimiter = false
|
||||
|
||||
[.editorconfig]
|
||||
ij_editorconfig_align_group_field_declarations = false
|
||||
ij_editorconfig_space_after_colon = false
|
||||
ij_editorconfig_space_after_comma = true
|
||||
ij_editorconfig_space_before_colon = false
|
||||
ij_editorconfig_space_before_comma = false
|
||||
ij_editorconfig_spaces_around_assignment_operators = true
|
||||
|
||||
[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.rng,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul}]
|
||||
ij_continuation_indent_size = 4
|
||||
ij_xml_align_attributes = false
|
||||
ij_xml_align_text = false
|
||||
ij_xml_attribute_wrap = normal
|
||||
ij_xml_block_comment_add_space = false
|
||||
ij_xml_block_comment_at_first_column = true
|
||||
ij_xml_keep_blank_lines = 2
|
||||
ij_xml_keep_indents_on_empty_lines = false
|
||||
ij_xml_keep_line_breaks = false
|
||||
ij_xml_keep_line_breaks_in_text = true
|
||||
ij_xml_keep_whitespaces = false
|
||||
ij_xml_keep_whitespaces_around_cdata = preserve
|
||||
ij_xml_keep_whitespaces_inside_cdata = false
|
||||
ij_xml_line_comment_at_first_column = true
|
||||
ij_xml_space_after_tag_name = false
|
||||
ij_xml_space_around_equals_in_attribute = false
|
||||
ij_xml_space_inside_empty_tag = true
|
||||
ij_xml_text_wrap = normal
|
||||
ij_xml_use_custom_settings = true
|
||||
|
||||
[{*.apinotes,*.yaml,*.yml}]
|
||||
indent_size = 2
|
||||
ij_yaml_align_values_properties = do_not_align
|
||||
ij_yaml_autoinsert_sequence_marker = true
|
||||
ij_yaml_block_mapping_on_new_line = false
|
||||
ij_yaml_indent_sequence_value = true
|
||||
ij_yaml_keep_indents_on_empty_lines = false
|
||||
ij_yaml_keep_line_breaks = true
|
||||
ij_yaml_sequence_on_new_line = false
|
||||
ij_yaml_space_before_colon = false
|
||||
ij_yaml_spaces_within_braces = true
|
||||
ij_yaml_spaces_within_brackets = true
|
||||
|
||||
[{*.bash,*.sh,*.zsh}]
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
ij_shell_binary_ops_start_line = false
|
||||
ij_shell_keep_column_alignment_padding = false
|
||||
ij_shell_minify_program = false
|
||||
ij_shell_redirect_followed_by_space = false
|
||||
ij_shell_switch_cases_indented = false
|
||||
ij_shell_use_unix_line_separator = true
|
||||
|
||||
[{*.c,*.c++,*.cc,*.cp,*.cpp,*.cppm,*.cu,*.cuh,*.cxx,*.h,*.h++,*.hh,*.hp,*.hpp,*.hxx,*.i,*.icc,*.ii,*.inl,*.ino,*.ipp,*.ixx,*.m,*.mm,*.mxx,*.pch,*.tcc,*.tpp}]
|
||||
ij_c_add_brief_tag = false
|
||||
ij_c_add_getter_prefix = true
|
||||
ij_c_add_setter_prefix = true
|
||||
ij_c_align_dictionary_pair_values = false
|
||||
ij_c_align_group_field_declarations = false
|
||||
ij_c_align_init_list_in_columns = true
|
||||
ij_c_align_multiline_array_initializer_expression = true
|
||||
ij_c_align_multiline_assignment = true
|
||||
ij_c_align_multiline_binary_operation = true
|
||||
ij_c_align_multiline_chained_methods = false
|
||||
ij_c_align_multiline_for = true
|
||||
ij_c_align_multiline_ternary_operation = true
|
||||
ij_c_array_initializer_comma_on_next_line = false
|
||||
ij_c_array_initializer_new_line_after_left_brace = false
|
||||
ij_c_array_initializer_right_brace_on_new_line = false
|
||||
ij_c_array_initializer_wrap = normal
|
||||
ij_c_assignment_wrap = off
|
||||
ij_c_binary_operation_sign_on_next_line = false
|
||||
ij_c_binary_operation_wrap = normal
|
||||
ij_c_blank_lines_after_class_header = 0
|
||||
ij_c_blank_lines_after_imports = 1
|
||||
ij_c_blank_lines_around_class = 1
|
||||
ij_c_blank_lines_around_field = 0
|
||||
ij_c_blank_lines_around_field_in_interface = 0
|
||||
ij_c_blank_lines_around_method = 1
|
||||
ij_c_blank_lines_around_method_in_interface = 1
|
||||
ij_c_blank_lines_around_namespace = 0
|
||||
ij_c_blank_lines_around_properties_in_declaration = 0
|
||||
ij_c_blank_lines_around_properties_in_interface = 0
|
||||
ij_c_blank_lines_before_imports = 1
|
||||
ij_c_blank_lines_before_method_body = 0
|
||||
ij_c_block_brace_placement = end_of_line
|
||||
ij_c_block_brace_style = end_of_line
|
||||
ij_c_block_comment_at_first_column = true
|
||||
ij_c_catch_on_new_line = false
|
||||
ij_c_class_brace_style = end_of_line
|
||||
ij_c_class_constructor_init_list_align_multiline = true
|
||||
ij_c_class_constructor_init_list_comma_on_next_line = false
|
||||
ij_c_class_constructor_init_list_new_line_after_colon = never
|
||||
ij_c_class_constructor_init_list_new_line_before_colon = if_long
|
||||
ij_c_class_constructor_init_list_wrap = normal
|
||||
ij_c_copy_is_deep = false
|
||||
ij_c_create_interface_for_categories = true
|
||||
ij_c_declare_generated_methods = true
|
||||
ij_c_description_include_member_names = true
|
||||
ij_c_discharged_short_ternary_operator = false
|
||||
ij_c_do_not_add_breaks = false
|
||||
ij_c_do_while_brace_force = never
|
||||
ij_c_else_on_new_line = false
|
||||
ij_c_enum_constants_comma_on_next_line = false
|
||||
ij_c_enum_constants_wrap = on_every_item
|
||||
ij_c_for_brace_force = never
|
||||
ij_c_for_statement_new_line_after_left_paren = false
|
||||
ij_c_for_statement_right_paren_on_new_line = false
|
||||
ij_c_for_statement_wrap = off
|
||||
ij_c_function_brace_placement = end_of_line
|
||||
ij_c_function_call_arguments_align_multiline = true
|
||||
ij_c_function_call_arguments_align_multiline_pars = false
|
||||
ij_c_function_call_arguments_comma_on_next_line = false
|
||||
ij_c_function_call_arguments_new_line_after_lpar = false
|
||||
ij_c_function_call_arguments_new_line_before_rpar = false
|
||||
ij_c_function_call_arguments_wrap = normal
|
||||
ij_c_function_non_top_after_return_type_wrap = normal
|
||||
ij_c_function_parameters_align_multiline = true
|
||||
ij_c_function_parameters_align_multiline_pars = false
|
||||
ij_c_function_parameters_comma_on_next_line = false
|
||||
ij_c_function_parameters_new_line_after_lpar = false
|
||||
ij_c_function_parameters_new_line_before_rpar = false
|
||||
ij_c_function_parameters_wrap = normal
|
||||
ij_c_function_top_after_return_type_wrap = normal
|
||||
ij_c_generate_additional_eq_operators = true
|
||||
ij_c_generate_additional_rel_operators = true
|
||||
ij_c_generate_class_constructor = true
|
||||
ij_c_generate_comparison_operators_use_std_tie = false
|
||||
ij_c_generate_instance_variables_for_properties = ask
|
||||
ij_c_generate_operators_as_members = true
|
||||
ij_c_header_guard_style_pattern = ${PROJECT_NAME}_${FILE_NAME}_${EXT}
|
||||
ij_c_if_brace_force = never
|
||||
ij_c_in_line_short_ternary_operator = true
|
||||
ij_c_indent_block_comment = true
|
||||
ij_c_indent_c_struct_members = 4
|
||||
ij_c_indent_case_from_switch = true
|
||||
ij_c_indent_class_members = 4
|
||||
ij_c_indent_directive_as_code = false
|
||||
ij_c_indent_implementation_members = 0
|
||||
ij_c_indent_inside_code_block = 4
|
||||
ij_c_indent_interface_members = 0
|
||||
ij_c_indent_interface_members_except_ivars_block = false
|
||||
ij_c_indent_namespace_members = 4
|
||||
ij_c_indent_preprocessor_directive = 0
|
||||
ij_c_indent_visibility_keywords = 0
|
||||
ij_c_insert_override = true
|
||||
ij_c_insert_virtual_with_override = false
|
||||
ij_c_introduce_auto_vars = false
|
||||
ij_c_introduce_const_params = false
|
||||
ij_c_introduce_const_vars = false
|
||||
ij_c_introduce_generate_property = false
|
||||
ij_c_introduce_generate_synthesize = true
|
||||
ij_c_introduce_globals_to_header = true
|
||||
ij_c_introduce_prop_to_private_category = false
|
||||
ij_c_introduce_static_consts = true
|
||||
ij_c_introduce_use_ns_types = false
|
||||
ij_c_ivars_prefix = _
|
||||
ij_c_keep_blank_lines_before_end = 2
|
||||
ij_c_keep_blank_lines_before_right_brace = 2
|
||||
ij_c_keep_blank_lines_in_code = 2
|
||||
ij_c_keep_blank_lines_in_declarations = 2
|
||||
ij_c_keep_case_expressions_in_one_line = false
|
||||
ij_c_keep_control_statement_in_one_line = true
|
||||
ij_c_keep_directive_at_first_column = true
|
||||
ij_c_keep_first_column_comment = true
|
||||
ij_c_keep_line_breaks = true
|
||||
ij_c_keep_nested_namespaces_in_one_line = false
|
||||
ij_c_keep_simple_blocks_in_one_line = true
|
||||
ij_c_keep_simple_methods_in_one_line = true
|
||||
ij_c_keep_structures_in_one_line = false
|
||||
ij_c_lambda_capture_list_align_multiline = false
|
||||
ij_c_lambda_capture_list_align_multiline_bracket = false
|
||||
ij_c_lambda_capture_list_comma_on_next_line = false
|
||||
ij_c_lambda_capture_list_new_line_after_lbracket = false
|
||||
ij_c_lambda_capture_list_new_line_before_rbracket = false
|
||||
ij_c_lambda_capture_list_wrap = off
|
||||
ij_c_line_comment_add_space = false
|
||||
ij_c_line_comment_at_first_column = true
|
||||
ij_c_method_brace_placement = end_of_line
|
||||
ij_c_method_call_arguments_align_by_colons = true
|
||||
ij_c_method_call_arguments_align_multiline = false
|
||||
ij_c_method_call_arguments_special_dictionary_pairs_treatment = true
|
||||
ij_c_method_call_arguments_wrap = off
|
||||
ij_c_method_call_chain_wrap = off
|
||||
ij_c_method_parameters_align_by_colons = true
|
||||
ij_c_method_parameters_align_multiline = false
|
||||
ij_c_method_parameters_wrap = off
|
||||
ij_c_namespace_brace_placement = end_of_line
|
||||
ij_c_parentheses_expression_new_line_after_left_paren = false
|
||||
ij_c_parentheses_expression_right_paren_on_new_line = false
|
||||
ij_c_place_assignment_sign_on_next_line = false
|
||||
ij_c_property_nonatomic = true
|
||||
ij_c_put_ivars_to_implementation = true
|
||||
ij_c_refactor_compatibility_aliases_and_classes = true
|
||||
ij_c_refactor_properties_and_ivars = true
|
||||
ij_c_release_style = ivar
|
||||
ij_c_retain_object_parameters_in_constructor = true
|
||||
ij_c_semicolon_after_method_signature = false
|
||||
ij_c_shift_operation_align_multiline = true
|
||||
ij_c_shift_operation_wrap = normal
|
||||
ij_c_show_non_virtual_functions = false
|
||||
ij_c_space_after_colon = true
|
||||
ij_c_space_after_colon_in_foreach = true
|
||||
ij_c_space_after_colon_in_selector = false
|
||||
ij_c_space_after_comma = true
|
||||
ij_c_space_after_cup_in_blocks = false
|
||||
ij_c_space_after_dictionary_literal_colon = true
|
||||
ij_c_space_after_for_semicolon = true
|
||||
ij_c_space_after_init_list_colon = true
|
||||
ij_c_space_after_method_parameter_type_parentheses = false
|
||||
ij_c_space_after_method_return_type_parentheses = false
|
||||
ij_c_space_after_pointer_in_declaration = false
|
||||
ij_c_space_after_quest = true
|
||||
ij_c_space_after_reference_in_declaration = false
|
||||
ij_c_space_after_reference_in_rvalue = false
|
||||
ij_c_space_after_structures_rbrace = true
|
||||
ij_c_space_after_superclass_colon = true
|
||||
ij_c_space_after_type_cast = true
|
||||
ij_c_space_after_visibility_sign_in_method_declaration = true
|
||||
ij_c_space_before_autorelease_pool_lbrace = true
|
||||
ij_c_space_before_catch_keyword = true
|
||||
ij_c_space_before_catch_left_brace = true
|
||||
ij_c_space_before_catch_parentheses = true
|
||||
ij_c_space_before_category_parentheses = true
|
||||
ij_c_space_before_chained_send_message = true
|
||||
ij_c_space_before_class_left_brace = true
|
||||
ij_c_space_before_colon = true
|
||||
ij_c_space_before_colon_in_foreach = false
|
||||
ij_c_space_before_comma = false
|
||||
ij_c_space_before_dictionary_literal_colon = false
|
||||
ij_c_space_before_do_left_brace = true
|
||||
ij_c_space_before_else_keyword = true
|
||||
ij_c_space_before_else_left_brace = true
|
||||
ij_c_space_before_export_lbrace = true
|
||||
ij_c_space_before_for_left_brace = true
|
||||
ij_c_space_before_for_parentheses = true
|
||||
ij_c_space_before_for_semicolon = false
|
||||
ij_c_space_before_if_left_brace = true
|
||||
ij_c_space_before_if_parentheses = true
|
||||
ij_c_space_before_init_list = false
|
||||
ij_c_space_before_init_list_colon = true
|
||||
ij_c_space_before_method_call_parentheses = false
|
||||
ij_c_space_before_method_left_brace = true
|
||||
ij_c_space_before_method_parentheses = false
|
||||
ij_c_space_before_namespace_lbrace = true
|
||||
ij_c_space_before_pointer_in_declaration = true
|
||||
ij_c_space_before_property_attributes_parentheses = false
|
||||
ij_c_space_before_protocols_brackets = true
|
||||
ij_c_space_before_quest = true
|
||||
ij_c_space_before_reference_in_declaration = true
|
||||
ij_c_space_before_superclass_colon = true
|
||||
ij_c_space_before_switch_left_brace = true
|
||||
ij_c_space_before_switch_parentheses = true
|
||||
ij_c_space_before_template_call_lt = false
|
||||
ij_c_space_before_template_declaration_lt = false
|
||||
ij_c_space_before_try_left_brace = true
|
||||
ij_c_space_before_while_keyword = true
|
||||
ij_c_space_before_while_left_brace = true
|
||||
ij_c_space_before_while_parentheses = true
|
||||
ij_c_space_between_adjacent_brackets = false
|
||||
ij_c_space_between_operator_and_punctuator = false
|
||||
ij_c_space_within_empty_array_initializer_braces = false
|
||||
ij_c_spaces_around_additive_operators = true
|
||||
ij_c_spaces_around_assignment_operators = true
|
||||
ij_c_spaces_around_bitwise_operators = true
|
||||
ij_c_spaces_around_equality_operators = true
|
||||
ij_c_spaces_around_lambda_arrow = true
|
||||
ij_c_spaces_around_logical_operators = true
|
||||
ij_c_spaces_around_multiplicative_operators = true
|
||||
ij_c_spaces_around_pm_operators = false
|
||||
ij_c_spaces_around_relational_operators = true
|
||||
ij_c_spaces_around_shift_operators = true
|
||||
ij_c_spaces_around_unary_operator = false
|
||||
ij_c_spaces_within_array_initializer_braces = false
|
||||
ij_c_spaces_within_braces = true
|
||||
ij_c_spaces_within_brackets = false
|
||||
ij_c_spaces_within_cast_parentheses = false
|
||||
ij_c_spaces_within_catch_parentheses = false
|
||||
ij_c_spaces_within_category_parentheses = false
|
||||
ij_c_spaces_within_empty_braces = false
|
||||
ij_c_spaces_within_empty_function_call_parentheses = false
|
||||
ij_c_spaces_within_empty_function_declaration_parentheses = false
|
||||
ij_c_spaces_within_empty_lambda_capture_list_bracket = false
|
||||
ij_c_spaces_within_empty_template_call_ltgt = false
|
||||
ij_c_spaces_within_empty_template_declaration_ltgt = false
|
||||
ij_c_spaces_within_for_parentheses = false
|
||||
ij_c_spaces_within_function_call_parentheses = false
|
||||
ij_c_spaces_within_function_declaration_parentheses = false
|
||||
ij_c_spaces_within_if_parentheses = false
|
||||
ij_c_spaces_within_lambda_capture_list_bracket = false
|
||||
ij_c_spaces_within_method_parameter_type_parentheses = false
|
||||
ij_c_spaces_within_method_return_type_parentheses = false
|
||||
ij_c_spaces_within_parentheses = false
|
||||
ij_c_spaces_within_property_attributes_parentheses = false
|
||||
ij_c_spaces_within_protocols_brackets = false
|
||||
ij_c_spaces_within_send_message_brackets = false
|
||||
ij_c_spaces_within_structured_binding_list_bracket = false
|
||||
ij_c_spaces_within_switch_parentheses = false
|
||||
ij_c_spaces_within_template_call_ltgt = false
|
||||
ij_c_spaces_within_template_declaration_ltgt = false
|
||||
ij_c_spaces_within_template_double_gt = true
|
||||
ij_c_spaces_within_while_parentheses = false
|
||||
ij_c_special_else_if_treatment = true
|
||||
ij_c_structured_binding_list_align_multiline = false
|
||||
ij_c_structured_binding_list_align_multiline_bracket = false
|
||||
ij_c_structured_binding_list_comma_on_next_line = false
|
||||
ij_c_structured_binding_list_new_line_after_lbracket = false
|
||||
ij_c_structured_binding_list_new_line_before_rbracket = false
|
||||
ij_c_structured_binding_list_wrap = off
|
||||
ij_c_superclass_list_after_colon = never
|
||||
ij_c_superclass_list_align_multiline = true
|
||||
ij_c_superclass_list_before_colon = if_long
|
||||
ij_c_superclass_list_comma_on_next_line = false
|
||||
ij_c_superclass_list_wrap = on_every_item
|
||||
ij_c_tag_prefix_of_block_comment = at
|
||||
ij_c_tag_prefix_of_line_comment = back_slash
|
||||
ij_c_template_call_arguments_align_multiline = false
|
||||
ij_c_template_call_arguments_align_multiline_pars = false
|
||||
ij_c_template_call_arguments_comma_on_next_line = false
|
||||
ij_c_template_call_arguments_new_line_after_lt = false
|
||||
ij_c_template_call_arguments_new_line_before_gt = false
|
||||
ij_c_template_call_arguments_wrap = off
|
||||
ij_c_template_declaration_function_body_indent = false
|
||||
ij_c_template_declaration_function_wrap = split_into_lines
|
||||
ij_c_template_declaration_struct_body_indent = false
|
||||
ij_c_template_declaration_struct_wrap = split_into_lines
|
||||
ij_c_template_parameters_align_multiline = false
|
||||
ij_c_template_parameters_align_multiline_pars = false
|
||||
ij_c_template_parameters_comma_on_next_line = false
|
||||
ij_c_template_parameters_new_line_after_lt = false
|
||||
ij_c_template_parameters_new_line_before_gt = false
|
||||
ij_c_template_parameters_wrap = off
|
||||
ij_c_ternary_operation_signs_on_next_line = true
|
||||
ij_c_ternary_operation_wrap = normal
|
||||
ij_c_type_qualifiers_placement = before
|
||||
ij_c_use_modern_casts = true
|
||||
ij_c_use_setters_in_constructor = true
|
||||
ij_c_while_brace_force = never
|
||||
ij_c_while_on_new_line = false
|
||||
ij_c_wrap_property_declaration = off
|
||||
|
||||
[{*.cmake,CMakeLists.txt}]
|
||||
ij_cmake_align_multiline_parameters_in_calls = false
|
||||
ij_cmake_force_commands_case = 2
|
||||
ij_cmake_keep_blank_lines_in_code = 2
|
||||
ij_cmake_space_before_for_parentheses = true
|
||||
ij_cmake_space_before_if_parentheses = true
|
||||
ij_cmake_space_before_method_call_parentheses = false
|
||||
ij_cmake_space_before_method_parentheses = false
|
||||
ij_cmake_space_before_while_parentheses = true
|
||||
ij_cmake_spaces_within_for_parentheses = false
|
||||
ij_cmake_spaces_within_if_parentheses = false
|
||||
ij_cmake_spaces_within_method_call_parentheses = false
|
||||
ij_cmake_spaces_within_method_parentheses = false
|
||||
ij_cmake_spaces_within_while_parentheses = false
|
||||
|
||||
[{*.gant,*.groovy,*.gy}]
|
||||
ij_groovy_align_group_field_declarations = false
|
||||
ij_groovy_align_multiline_array_initializer_expression = false
|
||||
ij_groovy_align_multiline_assignment = false
|
||||
ij_groovy_align_multiline_binary_operation = false
|
||||
ij_groovy_align_multiline_chained_methods = false
|
||||
ij_groovy_align_multiline_extends_list = false
|
||||
ij_groovy_align_multiline_for = true
|
||||
ij_groovy_align_multiline_list_or_map = true
|
||||
ij_groovy_align_multiline_method_parentheses = false
|
||||
ij_groovy_align_multiline_parameters = true
|
||||
ij_groovy_align_multiline_parameters_in_calls = false
|
||||
ij_groovy_align_multiline_resources = true
|
||||
ij_groovy_align_multiline_ternary_operation = false
|
||||
ij_groovy_align_multiline_throws_list = false
|
||||
ij_groovy_align_named_args_in_map = true
|
||||
ij_groovy_align_throws_keyword = false
|
||||
ij_groovy_array_initializer_new_line_after_left_brace = false
|
||||
ij_groovy_array_initializer_right_brace_on_new_line = false
|
||||
ij_groovy_array_initializer_wrap = off
|
||||
ij_groovy_assert_statement_wrap = off
|
||||
ij_groovy_assignment_wrap = off
|
||||
ij_groovy_binary_operation_wrap = off
|
||||
ij_groovy_blank_lines_after_class_header = 0
|
||||
ij_groovy_blank_lines_after_imports = 1
|
||||
ij_groovy_blank_lines_after_package = 1
|
||||
ij_groovy_blank_lines_around_class = 1
|
||||
ij_groovy_blank_lines_around_field = 0
|
||||
ij_groovy_blank_lines_around_field_in_interface = 0
|
||||
ij_groovy_blank_lines_around_method = 1
|
||||
ij_groovy_blank_lines_around_method_in_interface = 1
|
||||
ij_groovy_blank_lines_before_imports = 1
|
||||
ij_groovy_blank_lines_before_method_body = 0
|
||||
ij_groovy_blank_lines_before_package = 0
|
||||
ij_groovy_block_brace_style = end_of_line
|
||||
ij_groovy_block_comment_add_space = false
|
||||
ij_groovy_block_comment_at_first_column = true
|
||||
ij_groovy_call_parameters_new_line_after_left_paren = false
|
||||
ij_groovy_call_parameters_right_paren_on_new_line = false
|
||||
ij_groovy_call_parameters_wrap = off
|
||||
ij_groovy_catch_on_new_line = false
|
||||
ij_groovy_class_annotation_wrap = split_into_lines
|
||||
ij_groovy_class_brace_style = end_of_line
|
||||
ij_groovy_class_count_to_use_import_on_demand = 5
|
||||
ij_groovy_do_while_brace_force = never
|
||||
ij_groovy_else_on_new_line = false
|
||||
ij_groovy_enable_groovydoc_formatting = true
|
||||
ij_groovy_enum_constants_wrap = off
|
||||
ij_groovy_extends_keyword_wrap = off
|
||||
ij_groovy_extends_list_wrap = off
|
||||
ij_groovy_field_annotation_wrap = split_into_lines
|
||||
ij_groovy_finally_on_new_line = false
|
||||
ij_groovy_for_brace_force = never
|
||||
ij_groovy_for_statement_new_line_after_left_paren = false
|
||||
ij_groovy_for_statement_right_paren_on_new_line = false
|
||||
ij_groovy_for_statement_wrap = off
|
||||
ij_groovy_ginq_general_clause_wrap_policy = 2
|
||||
ij_groovy_ginq_having_wrap_policy = 1
|
||||
ij_groovy_ginq_indent_having_clause = true
|
||||
ij_groovy_ginq_indent_on_clause = true
|
||||
ij_groovy_ginq_on_wrap_policy = 1
|
||||
ij_groovy_ginq_space_after_keyword = true
|
||||
ij_groovy_if_brace_force = never
|
||||
ij_groovy_import_annotation_wrap = 2
|
||||
ij_groovy_imports_layout = *,|,javax.**,java.**,|,$*
|
||||
ij_groovy_indent_case_from_switch = true
|
||||
ij_groovy_indent_label_blocks = true
|
||||
ij_groovy_insert_inner_class_imports = false
|
||||
ij_groovy_keep_blank_lines_before_right_brace = 2
|
||||
ij_groovy_keep_blank_lines_in_code = 2
|
||||
ij_groovy_keep_blank_lines_in_declarations = 2
|
||||
ij_groovy_keep_control_statement_in_one_line = true
|
||||
ij_groovy_keep_first_column_comment = true
|
||||
ij_groovy_keep_indents_on_empty_lines = false
|
||||
ij_groovy_keep_line_breaks = true
|
||||
ij_groovy_keep_multiple_expressions_in_one_line = false
|
||||
ij_groovy_keep_simple_blocks_in_one_line = false
|
||||
ij_groovy_keep_simple_classes_in_one_line = true
|
||||
ij_groovy_keep_simple_lambdas_in_one_line = true
|
||||
ij_groovy_keep_simple_methods_in_one_line = true
|
||||
ij_groovy_label_indent_absolute = false
|
||||
ij_groovy_label_indent_size = 0
|
||||
ij_groovy_lambda_brace_style = end_of_line
|
||||
ij_groovy_layout_static_imports_separately = true
|
||||
ij_groovy_line_comment_add_space = false
|
||||
ij_groovy_line_comment_add_space_on_reformat = false
|
||||
ij_groovy_line_comment_at_first_column = true
|
||||
ij_groovy_method_annotation_wrap = split_into_lines
|
||||
ij_groovy_method_brace_style = end_of_line
|
||||
ij_groovy_method_call_chain_wrap = off
|
||||
ij_groovy_method_parameters_new_line_after_left_paren = false
|
||||
ij_groovy_method_parameters_right_paren_on_new_line = false
|
||||
ij_groovy_method_parameters_wrap = off
|
||||
ij_groovy_modifier_list_wrap = false
|
||||
ij_groovy_names_count_to_use_import_on_demand = 3
|
||||
ij_groovy_packages_to_use_import_on_demand = java.awt.*,javax.swing.*
|
||||
ij_groovy_parameter_annotation_wrap = off
|
||||
ij_groovy_parentheses_expression_new_line_after_left_paren = false
|
||||
ij_groovy_parentheses_expression_right_paren_on_new_line = false
|
||||
ij_groovy_prefer_parameters_wrap = false
|
||||
ij_groovy_resource_list_new_line_after_left_paren = false
|
||||
ij_groovy_resource_list_right_paren_on_new_line = false
|
||||
ij_groovy_resource_list_wrap = off
|
||||
ij_groovy_space_after_assert_separator = true
|
||||
ij_groovy_space_after_colon = true
|
||||
ij_groovy_space_after_comma = true
|
||||
ij_groovy_space_after_comma_in_type_arguments = true
|
||||
ij_groovy_space_after_for_semicolon = true
|
||||
ij_groovy_space_after_quest = true
|
||||
ij_groovy_space_after_type_cast = true
|
||||
ij_groovy_space_before_annotation_parameter_list = false
|
||||
ij_groovy_space_before_array_initializer_left_brace = false
|
||||
ij_groovy_space_before_assert_separator = false
|
||||
ij_groovy_space_before_catch_keyword = true
|
||||
ij_groovy_space_before_catch_left_brace = true
|
||||
ij_groovy_space_before_catch_parentheses = true
|
||||
ij_groovy_space_before_class_left_brace = true
|
||||
ij_groovy_space_before_closure_left_brace = true
|
||||
ij_groovy_space_before_colon = true
|
||||
ij_groovy_space_before_comma = false
|
||||
ij_groovy_space_before_do_left_brace = true
|
||||
ij_groovy_space_before_else_keyword = true
|
||||
ij_groovy_space_before_else_left_brace = true
|
||||
ij_groovy_space_before_finally_keyword = true
|
||||
ij_groovy_space_before_finally_left_brace = true
|
||||
ij_groovy_space_before_for_left_brace = true
|
||||
ij_groovy_space_before_for_parentheses = true
|
||||
ij_groovy_space_before_for_semicolon = false
|
||||
ij_groovy_space_before_if_left_brace = true
|
||||
ij_groovy_space_before_if_parentheses = true
|
||||
ij_groovy_space_before_method_call_parentheses = false
|
||||
ij_groovy_space_before_method_left_brace = true
|
||||
ij_groovy_space_before_method_parentheses = false
|
||||
ij_groovy_space_before_quest = true
|
||||
ij_groovy_space_before_record_parentheses = false
|
||||
ij_groovy_space_before_switch_left_brace = true
|
||||
ij_groovy_space_before_switch_parentheses = true
|
||||
ij_groovy_space_before_synchronized_left_brace = true
|
||||
ij_groovy_space_before_synchronized_parentheses = true
|
||||
ij_groovy_space_before_try_left_brace = true
|
||||
ij_groovy_space_before_try_parentheses = true
|
||||
ij_groovy_space_before_while_keyword = true
|
||||
ij_groovy_space_before_while_left_brace = true
|
||||
ij_groovy_space_before_while_parentheses = true
|
||||
ij_groovy_space_in_named_argument = true
|
||||
ij_groovy_space_in_named_argument_before_colon = false
|
||||
ij_groovy_space_within_empty_array_initializer_braces = false
|
||||
ij_groovy_space_within_empty_method_call_parentheses = false
|
||||
ij_groovy_spaces_around_additive_operators = true
|
||||
ij_groovy_spaces_around_assignment_operators = true
|
||||
ij_groovy_spaces_around_bitwise_operators = true
|
||||
ij_groovy_spaces_around_equality_operators = true
|
||||
ij_groovy_spaces_around_lambda_arrow = true
|
||||
ij_groovy_spaces_around_logical_operators = true
|
||||
ij_groovy_spaces_around_multiplicative_operators = true
|
||||
ij_groovy_spaces_around_regex_operators = true
|
||||
ij_groovy_spaces_around_relational_operators = true
|
||||
ij_groovy_spaces_around_shift_operators = true
|
||||
ij_groovy_spaces_within_annotation_parentheses = false
|
||||
ij_groovy_spaces_within_array_initializer_braces = false
|
||||
ij_groovy_spaces_within_braces = true
|
||||
ij_groovy_spaces_within_brackets = false
|
||||
ij_groovy_spaces_within_cast_parentheses = false
|
||||
ij_groovy_spaces_within_catch_parentheses = false
|
||||
ij_groovy_spaces_within_for_parentheses = false
|
||||
ij_groovy_spaces_within_gstring_injection_braces = false
|
||||
ij_groovy_spaces_within_if_parentheses = false
|
||||
ij_groovy_spaces_within_list_or_map = false
|
||||
ij_groovy_spaces_within_method_call_parentheses = false
|
||||
ij_groovy_spaces_within_method_parentheses = false
|
||||
ij_groovy_spaces_within_parentheses = false
|
||||
ij_groovy_spaces_within_switch_parentheses = false
|
||||
ij_groovy_spaces_within_synchronized_parentheses = false
|
||||
ij_groovy_spaces_within_try_parentheses = false
|
||||
ij_groovy_spaces_within_tuple_expression = false
|
||||
ij_groovy_spaces_within_while_parentheses = false
|
||||
ij_groovy_special_else_if_treatment = true
|
||||
ij_groovy_ternary_operation_wrap = off
|
||||
ij_groovy_throws_keyword_wrap = off
|
||||
ij_groovy_throws_list_wrap = off
|
||||
ij_groovy_use_flying_geese_braces = false
|
||||
ij_groovy_use_fq_class_names = false
|
||||
ij_groovy_use_fq_class_names_in_javadoc = true
|
||||
ij_groovy_use_relative_indents = false
|
||||
ij_groovy_use_single_class_imports = true
|
||||
ij_groovy_variable_annotation_wrap = off
|
||||
ij_groovy_while_brace_force = never
|
||||
ij_groovy_while_on_new_line = false
|
||||
ij_groovy_wrap_chain_calls_after_dot = false
|
||||
ij_groovy_wrap_long_lines = false
|
||||
|
||||
[{*.har,*.json}]
|
||||
indent_size = 2
|
||||
ij_json_array_wrapping = split_into_lines
|
||||
ij_json_keep_blank_lines_in_code = 0
|
||||
ij_json_keep_indents_on_empty_lines = false
|
||||
ij_json_keep_line_breaks = true
|
||||
ij_json_keep_trailing_comma = false
|
||||
ij_json_object_wrapping = split_into_lines
|
||||
ij_json_property_alignment = do_not_align
|
||||
ij_json_space_after_colon = true
|
||||
ij_json_space_after_comma = true
|
||||
ij_json_space_before_colon = false
|
||||
ij_json_space_before_comma = false
|
||||
ij_json_spaces_within_braces = false
|
||||
ij_json_spaces_within_brackets = false
|
||||
ij_json_wrap_long_lines = false
|
||||
|
||||
[{*.htm,*.html,*.sht,*.shtm,*.shtml}]
|
||||
ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3
|
||||
ij_html_align_attributes = true
|
||||
ij_html_align_text = false
|
||||
ij_html_attribute_wrap = normal
|
||||
ij_html_block_comment_add_space = false
|
||||
ij_html_block_comment_at_first_column = true
|
||||
ij_html_do_not_align_children_of_min_lines = 0
|
||||
ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p
|
||||
ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot
|
||||
ij_html_enforce_quotes = false
|
||||
ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var
|
||||
ij_html_keep_blank_lines = 2
|
||||
ij_html_keep_indents_on_empty_lines = false
|
||||
ij_html_keep_line_breaks = true
|
||||
ij_html_keep_line_breaks_in_text = true
|
||||
ij_html_keep_whitespaces = false
|
||||
ij_html_keep_whitespaces_inside = span,pre,textarea
|
||||
ij_html_line_comment_at_first_column = true
|
||||
ij_html_new_line_after_last_attribute = never
|
||||
ij_html_new_line_before_first_attribute = never
|
||||
ij_html_quote_style = double
|
||||
ij_html_remove_new_line_before_tags = br
|
||||
ij_html_space_after_tag_name = false
|
||||
ij_html_space_around_equality_in_attribute = false
|
||||
ij_html_space_inside_empty_tag = false
|
||||
ij_html_text_wrap = normal
|
||||
|
||||
[{*.kt,*.kts}]
|
||||
ij_kotlin_align_in_columns_case_branch = false
|
||||
ij_kotlin_align_multiline_binary_operation = false
|
||||
ij_kotlin_align_multiline_extends_list = false
|
||||
ij_kotlin_align_multiline_method_parentheses = false
|
||||
ij_kotlin_align_multiline_parameters = true
|
||||
ij_kotlin_align_multiline_parameters_in_calls = false
|
||||
ij_kotlin_allow_trailing_comma = false
|
||||
ij_kotlin_allow_trailing_comma_on_call_site = false
|
||||
ij_kotlin_assignment_wrap = off
|
||||
ij_kotlin_blank_lines_after_class_header = 0
|
||||
ij_kotlin_blank_lines_around_block_when_branches = 0
|
||||
ij_kotlin_blank_lines_before_declaration_with_comment_or_annotation_on_separate_line = 1
|
||||
ij_kotlin_block_comment_add_space = false
|
||||
ij_kotlin_block_comment_at_first_column = true
|
||||
ij_kotlin_call_parameters_new_line_after_left_paren = false
|
||||
ij_kotlin_call_parameters_right_paren_on_new_line = false
|
||||
ij_kotlin_call_parameters_wrap = off
|
||||
ij_kotlin_catch_on_new_line = false
|
||||
ij_kotlin_class_annotation_wrap = split_into_lines
|
||||
ij_kotlin_continuation_indent_for_chained_calls = true
|
||||
ij_kotlin_continuation_indent_for_expression_bodies = true
|
||||
ij_kotlin_continuation_indent_in_argument_lists = true
|
||||
ij_kotlin_continuation_indent_in_elvis = true
|
||||
ij_kotlin_continuation_indent_in_if_conditions = true
|
||||
ij_kotlin_continuation_indent_in_parameter_lists = true
|
||||
ij_kotlin_continuation_indent_in_supertype_lists = true
|
||||
ij_kotlin_else_on_new_line = false
|
||||
ij_kotlin_enum_constants_wrap = off
|
||||
ij_kotlin_extends_list_wrap = off
|
||||
ij_kotlin_field_annotation_wrap = split_into_lines
|
||||
ij_kotlin_finally_on_new_line = false
|
||||
ij_kotlin_if_rparen_on_new_line = false
|
||||
ij_kotlin_import_nested_classes = false
|
||||
ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,^
|
||||
ij_kotlin_insert_whitespaces_in_simple_one_line_method = true
|
||||
ij_kotlin_keep_blank_lines_before_right_brace = 2
|
||||
ij_kotlin_keep_blank_lines_in_code = 2
|
||||
ij_kotlin_keep_blank_lines_in_declarations = 2
|
||||
ij_kotlin_keep_first_column_comment = true
|
||||
ij_kotlin_keep_indents_on_empty_lines = false
|
||||
ij_kotlin_keep_line_breaks = true
|
||||
ij_kotlin_lbrace_on_next_line = false
|
||||
ij_kotlin_line_break_after_multiline_when_entry = true
|
||||
ij_kotlin_line_comment_add_space = false
|
||||
ij_kotlin_line_comment_add_space_on_reformat = false
|
||||
ij_kotlin_line_comment_at_first_column = true
|
||||
ij_kotlin_method_annotation_wrap = split_into_lines
|
||||
ij_kotlin_method_call_chain_wrap = off
|
||||
ij_kotlin_method_parameters_new_line_after_left_paren = false
|
||||
ij_kotlin_method_parameters_right_paren_on_new_line = false
|
||||
ij_kotlin_method_parameters_wrap = off
|
||||
ij_kotlin_name_count_to_use_star_import = 2147483647
|
||||
ij_kotlin_name_count_to_use_star_import_for_members = 2147483647
|
||||
ij_kotlin_packages_to_use_import_on_demand = java.util.*,kotlinx.android.synthetic.**,io.ktor.**
|
||||
ij_kotlin_parameter_annotation_wrap = off
|
||||
ij_kotlin_space_after_comma = true
|
||||
ij_kotlin_space_after_extend_colon = true
|
||||
ij_kotlin_space_after_type_colon = true
|
||||
ij_kotlin_space_before_catch_parentheses = true
|
||||
ij_kotlin_space_before_comma = false
|
||||
ij_kotlin_space_before_extend_colon = true
|
||||
ij_kotlin_space_before_for_parentheses = true
|
||||
ij_kotlin_space_before_if_parentheses = true
|
||||
ij_kotlin_space_before_lambda_arrow = true
|
||||
ij_kotlin_space_before_type_colon = false
|
||||
ij_kotlin_space_before_when_parentheses = true
|
||||
ij_kotlin_space_before_while_parentheses = true
|
||||
ij_kotlin_spaces_around_additive_operators = true
|
||||
ij_kotlin_spaces_around_assignment_operators = true
|
||||
ij_kotlin_spaces_around_equality_operators = true
|
||||
ij_kotlin_spaces_around_function_type_arrow = true
|
||||
ij_kotlin_spaces_around_logical_operators = true
|
||||
ij_kotlin_spaces_around_multiplicative_operators = true
|
||||
ij_kotlin_spaces_around_range = false
|
||||
ij_kotlin_spaces_around_relational_operators = true
|
||||
ij_kotlin_spaces_around_unary_operator = false
|
||||
ij_kotlin_spaces_around_when_arrow = true
|
||||
ij_kotlin_use_custom_formatting_for_modifiers = true
|
||||
ij_kotlin_variable_annotation_wrap = off
|
||||
ij_kotlin_while_on_new_line = false
|
||||
ij_kotlin_wrap_elvis_expressions = 1
|
||||
ij_kotlin_wrap_expression_body_functions = 0
|
||||
ij_kotlin_wrap_first_method_in_call_chain = false
|
||||
|
||||
[{*.markdown,*.md}]
|
||||
ij_markdown_force_one_space_after_blockquote_symbol = true
|
||||
ij_markdown_force_one_space_after_header_symbol = true
|
||||
ij_markdown_force_one_space_after_list_bullet = true
|
||||
ij_markdown_force_one_space_between_words = true
|
||||
ij_markdown_format_tables = true
|
||||
ij_markdown_insert_quote_arrows_on_wrap = true
|
||||
ij_markdown_keep_indents_on_empty_lines = false
|
||||
ij_markdown_keep_line_breaks_inside_text_blocks = true
|
||||
ij_markdown_max_lines_around_block_elements = 1
|
||||
ij_markdown_max_lines_around_header = 1
|
||||
ij_markdown_max_lines_between_paragraphs = 1
|
||||
ij_markdown_min_lines_around_block_elements = 1
|
||||
ij_markdown_min_lines_around_header = 1
|
||||
ij_markdown_min_lines_between_paragraphs = 1
|
||||
ij_markdown_wrap_text_if_long = true
|
||||
ij_markdown_wrap_text_inside_blockquotes = true
|
||||
|
||||
[{*.toml,Cargo.lock,Cargo.toml.orig,Gopkg.lock,Pipfile,poetry.lock}]
|
||||
ij_toml_keep_indents_on_empty_lines = false
|
||||
Generated
+5
@@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
||||
+10
-3
@@ -1,18 +1,25 @@
|
||||
# How to contribute?
|
||||
|
||||
## Testing
|
||||
## Testing
|
||||
|
||||
Just use OpenTracks and tell us what can be improved by opening an issue [here](https://github.com/OpenTracksApp/OpenTracks/issues/new/choose)
|
||||
Just use OpenTracks and tell us what can be improved by opening an
|
||||
issue [here](https://github.com/OpenTracksApp/OpenTracks/issues/new/choose)
|
||||
|
||||
If we broke things (happens now and then), please tell us also.
|
||||
|
||||
## Translations
|
||||
|
||||
Translations are hosted on [hosted.weblate.org](https://hosted.weblate.org/engage/opentracks/).
|
||||
|
||||
## Coding new features
|
||||
|
||||
You have a cool idea for a feature that is missing in OpenTracks?
|
||||
And you would like to help by implementing it?
|
||||
If not, you can just take a look at the [issue tracker](https://github.com/OpenTracksApp/OpenTracks/issues).
|
||||
If not, you can just take a look at
|
||||
the [issue tracker](https://github.com/OpenTracksApp/OpenTracks/issues).
|
||||
|
||||
Advices:
|
||||
|
||||
* creating an issue beforehand might be a good idea
|
||||
Sometimes it is helpful to discuss your idea and also your implementation approach first.
|
||||
We may be able to give you some hints on how to tackle the problem.
|
||||
|
||||
+33
-11
@@ -59,16 +59,38 @@ We do not support type of movement (i.e., walking vs running).
|
||||
|
||||
## Tested Barometric Sensor Smartphones
|
||||
|
||||
There are smartphones that have a barometric sensor that OpenTracks uses to compute altitude gain and loss.
|
||||
OpenTracks derives the altitude gain and altitude loss using the internal barometric sensor of a device (if present).
|
||||
However, barometric sensor seem to be prone to a lot of noise.
|
||||
This may either be a malfunctioning sensor, a case that prevents the device from measuring, or something else.
|
||||
|
||||
In our tests there are smartphones whose barometric sensor works well and others don't. Here is a list of the smartphones tested:
|
||||
To check if the barometric sensor of a device is working with OpenTracks:
|
||||
1. Record a track (ca. 1min) with the device stationary.
|
||||
Expectation: 0m gain and 0m loss should.
|
||||
2. Record a track (ca. 1min) while shaking the device.
|
||||
Expectation: 0m gain and 0m loss should.
|
||||
3. Record a track (ca. 1min) while moving the device up (less than 3m difference between highest and lowest point).
|
||||
Expectation: 0m gain and 0m loss should.
|
||||
4. Record a track walking up some stairs or taking an elevator.
|
||||
Expectation: some gain and some loss is recorded that seems realistic.
|
||||
|
||||
| Brand | Model | Android Version | Tests |
|
||||
|--------|--------------------|-----------------|--------------------------------------------------------------------------------|
|
||||
| Google | Pixel | LineageOS 17.1 | Ok |
|
||||
| Google | Pixel 2 XL | LineageOS 17.1 | Ok on the bike handlebars but it fails when I carry it in a pocket or backpack |
|
||||
| Google | Pixel 3 | Android 11 | Failure |
|
||||
| Google | Pixel 3a | Android 11 | Ok |
|
||||
| Google | Pixel 3a | Lineage 18.1 | Ok |
|
||||
| Google | Pixel 4a | Android 11 | Ok |
|
||||
| Sony | Xperia XZ1 Compact | LineageOS 16.1 | Failure |
|
||||
If any of these tests do **not** show expected values for gain/loss, OpenTracks will not show useful values.
|
||||
|
||||
Please note that OpenTracks:
|
||||
* only records gain/loss if +/- 3m to the initial/previous of are measured to the previous
|
||||
* solely uses the barometric sensor for gain/loss; GPS is not used for this.
|
||||
|
||||
In our tests there are smartphones whose barometric sensor works well and others don't.
|
||||
|
||||
Here is a list of the smartphones tested:
|
||||
|
||||
| Brand | Model | Android Version | Tests |
|
||||
|---------|--------------------|-----------------|--------------------------------------------------------------------------------|
|
||||
| Google | Pixel | LineageOS 17.1 | Ok |
|
||||
| Google | Pixel 2 XL | LineageOS 17.1 | Ok on the bike handlebars but it fails when I carry it in a pocket or backpack |
|
||||
| Google | Pixel 3 | Android 11 | Failure |
|
||||
| Google | Pixel 3a | Android 11 | Ok |
|
||||
| Google | Pixel 3a | Lineage 18.1 | Ok |
|
||||
| Google | Pixel 4a | Android 11 | Ok |
|
||||
| Google | Nexus 4 | LineageOS 18.1 | Ok |
|
||||
| Samsung | S4 | Android 11 | Ok |
|
||||
| Sony | Xperia XZ1 Compact | LineageOS 16.1 | Failure |
|
||||
|
||||
+10
-12
@@ -6,7 +6,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.1.0-beta01'
|
||||
classpath 'com.android.tools.build:gradle:8.1.0'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ android {
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
compileSdk 33
|
||||
compileSdk 34
|
||||
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
@@ -64,18 +64,16 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId "de.dennisguse.opentracks"
|
||||
versionCode 5194
|
||||
versionName "v4.3.3"
|
||||
versionCode 5313
|
||||
versionName "v4.7.0"
|
||||
|
||||
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
||||
|
||||
minSdk 21
|
||||
targetSdk 33
|
||||
minSdk 24
|
||||
targetSdk 34
|
||||
|
||||
testInstrumentationRunner "de.dennisguse.opentracks.TestRunner"
|
||||
testInstrumentationRunnerArguments clearPackageData: 'true'
|
||||
|
||||
resConfigs "ar", "bg", "ca", "cs", "da", "de", "el", "en", "es", "et", "eu", "fa", "fi", "fr", "ga", "gl", "hi", "hr", "hu", "in", "it", "iw", "ja", "ko", "lt", "lv", "mo", "ms", "nb", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sr", "sv", "th", "tl", "tr", "uk", "vi", "zh"
|
||||
}
|
||||
signingConfigs {
|
||||
nightly {
|
||||
@@ -130,20 +128,20 @@ dependencies {
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
|
||||
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'androidx.preference:preference:1.2.0'
|
||||
implementation 'androidx.preference:preference:1.2.1'
|
||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
||||
implementation 'com.google.android.material:material:1.8.0'
|
||||
implementation 'com.google.android.material:material:1.9.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'androidx.core:core-splashscreen:1.0.1'
|
||||
implementation 'androidx.mediarouter:mediarouter:1.3.1'
|
||||
implementation 'androidx.mediarouter:mediarouter:1.4.0'
|
||||
|
||||
androidTestImplementation 'androidx.test:core:1.5.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||
androidTestImplementation 'androidx.test:rules:1.5.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.5.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
||||
androidTestImplementation 'org.mockito:mockito-android:5.3.1'
|
||||
androidTestImplementation 'org.mockito:mockito-android:5.4.0'
|
||||
|
||||
androidTestUtil 'androidx.test:orchestrator:1.4.2'
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
v4.3.4: OpenTracks
|
||||
|
||||
Bugfix:
|
||||
- Android 13: regional locales could not be selected (introduced in v4.3.0)
|
||||
@@ -0,0 +1,6 @@
|
||||
v4.3.5: OpenTracks
|
||||
|
||||
Bugfix:
|
||||
- Sensor parsing had a overflow one off bug (#1559)
|
||||
- Insert marker: don't crash if no camera app is installed (#1561)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
v4.4.0: OpenTracks
|
||||
|
||||
Changes:
|
||||
- Export all tracks as one file
|
||||
@@ -0,0 +1,14 @@
|
||||
v4.5.0: OpenTracks
|
||||
|
||||
Changes:
|
||||
- Material3
|
||||
- App shortcut for aggregated statistics
|
||||
- New Unit: miles with meters
|
||||
|
||||
Bugfix:
|
||||
- GPS disabled warnings shown repeatedly (#1429)
|
||||
|
||||
Developer:
|
||||
- Use Java Records
|
||||
- Target API34
|
||||
- Refactor sensor handling
|
||||
@@ -0,0 +1,12 @@
|
||||
v4.6.0: OpenTracks
|
||||
|
||||
Changes:
|
||||
- Voice announcements use ICU plural format (en, es, pt, zh, dr, de) due to fractional quanitites #1584
|
||||
- Requires Android 7.0 / SDK24+ due to ICU plurals
|
||||
- On Android 14+: use Android's AltitudeConverter instead of internal EGM2008
|
||||
|
||||
Bugfix:
|
||||
- Android 13 couldn't select images from gallery
|
||||
|
||||
Developer:
|
||||
- Split ActivityType and ActivityIcon
|
||||
@@ -0,0 +1,5 @@
|
||||
v4.6.1: OpenTracks
|
||||
|
||||
Bugfix:
|
||||
- Re-added aggregated statistics per selected tracks
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
v4.6.2: OpenTracks
|
||||
|
||||
Bugfix:
|
||||
- Crash on voice annoucement for imperial+meter
|
||||
- Crash on settings for imperial+meter
|
||||
- Fixed clipping of charts (Material3 upgrade)
|
||||
- Bluetooth settings handle missing permission
|
||||
- Aggregated stats didn't show imperial units for avg speed
|
||||
@@ -0,0 +1,11 @@
|
||||
v4.7.0: OpenTracks
|
||||
|
||||
Changes:
|
||||
- Statistics: distance, total time, and moving time are included between automatic segments (created due to distance too previous location too long)
|
||||
- Recorded tracks show sensor statistics again
|
||||
|
||||
Bugfix:
|
||||
- GPX exporter: for automatic segments their might be no location
|
||||
- CSV exporter: distance didn't use decimal grouping
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
v4.4.0: OpenTracks
|
||||
|
||||
Cambios:
|
||||
- Exportar todas as rutas nun único ficheiro
|
||||
@@ -0,0 +1,14 @@
|
||||
v4.5.0: OpenTracks
|
||||
|
||||
Cambios:
|
||||
- Material3
|
||||
- Atallo na app para estatísticas acumuladas
|
||||
- Nova unidade: millas con metros
|
||||
|
||||
Arranxo:
|
||||
- avisos repetidos do GPS desactivado (#1429)
|
||||
|
||||
Desenvolvemento:
|
||||
- Utilizar Java Records
|
||||
- Obxectivo API34
|
||||
- Refactorización da xestión dos sensores
|
||||
@@ -0,0 +1,12 @@
|
||||
v4.6.0: OpenTracks
|
||||
|
||||
Cambios:
|
||||
- Anuncios por voz usando o formato de plurais ICU (en, es, pt, zh, dr, de) debido ás cantidades en fraccións #1584
|
||||
- Require Android 7.0 / SDK24+ debido aos plurais ICU
|
||||
- En Android 14+: usar o conversor AltitudeConverter de Android no lugar do interno EGM2008
|
||||
|
||||
Arrranxo:
|
||||
- Non se podía escoller unha imaxe da galería en Android 13
|
||||
|
||||
Desenvolvemento:
|
||||
- Separamos ActivityType e ActivityIcon
|
||||
@@ -0,0 +1,4 @@
|
||||
v4.6.1: OpenTracks
|
||||
|
||||
Arranxo:
|
||||
- Volvemos a engadir estatísticas conxuntas para as rutas seleccionadas
|
||||
@@ -0,0 +1,10 @@
|
||||
(versionName): OpenTracks
|
||||
|
||||
Cambios:
|
||||
-
|
||||
|
||||
Arranxos:
|
||||
-
|
||||
|
||||
Programadora:
|
||||
-
|
||||
@@ -0,0 +1,22 @@
|
||||
Gravador de actividades deportivas que respecta a túa privacidade.
|
||||
|
||||
As actividades deportivas e ao aire libre proporcionanche felicidade, destreza e confianza.
|
||||
|
||||
Dalle valor á túa saúde facendo un seguimento dos teus adestramentos.
|
||||
Grava mentras saes a correr ou camiñar, e será un ciclocomputador cunha pantalla máis grande e clara.
|
||||
Marca as localizacións interesantes na ruta podendo engadir unha imaxe.
|
||||
Garda un rexistro das túas estatísticas con gran detalle e análise.
|
||||
Comparte só os datos que outras persoas poden ver.
|
||||
|
||||
* Anuncios por voz.
|
||||
* Soporte para sensores Bluetooth LE: de frecuencia cardíaca, velocidade e distancia (ciclismo), cadencia (ciclismo), e de potencia (ciclismo).
|
||||
* Gañancia e perda de altitude: a través do sensor barométrico.
|
||||
* Altitude mostrada en EGM2008 (sobre o nivel do mar); exportada como WGS84.
|
||||
* Exporta os datos como rutas tanto como KMZ (inclúe fotos), KML, ou GPX.
|
||||
* Non precisa conexión a internet ou permisos extra.
|
||||
* Decorado escuro, claro, ou seguindo os axustes do sistema.
|
||||
* Sen publicidade.
|
||||
|
||||
Software Libre / Free Software / Open Source
|
||||
significa que podes usar, estudar, cambiar e compartir o código fonte.
|
||||
Licenza Apache 2.0
|
||||
@@ -0,0 +1 @@
|
||||
Gravador de actividades que respecta a túa privacidade.
|
||||
@@ -0,0 +1 @@
|
||||
OpenTracks
|
||||
@@ -2,13 +2,13 @@ v3.19.0: OpenTracks
|
||||
|
||||
Wijzigingen:
|
||||
- Ondersteuning voor Running Speed en Cadence (RCS) sensoren
|
||||
- Bij het delen van een track wordt een afbeelding gemaakt
|
||||
- Bij delen van een track: maakt een deel-afbeelding
|
||||
- Niet trillen bij starten van opnemen
|
||||
- Bij opnemen: UI toont recentst ontvangen hoogte, snelheid en richting (ook al is deze niet opgeslagen)
|
||||
- Bij opnemen: UI toont meest recente hoogte, snelheid en richting (zelfs als niet opgeslagen)
|
||||
|
||||
Bugfix:
|
||||
- Berekening van totale tijd mag geen pauze-tijd bevatten (vereist opnieuw importeren)
|
||||
- (opnieuw) Gebruik aangepaste overzichten indien aanwezig
|
||||
- Berekening totale tijd mag geen pauze-tijd bevatten (vereist opnieuw importeren)
|
||||
- (opnieuw) Gebruik aanwezige aangepaste overzichten
|
||||
|
||||
Ontwikkelaar:
|
||||
- Upgrade naar SDK31 en AGP7.0.0 (vereist JDK11)
|
||||
|
||||
@@ -5,4 +5,4 @@ Wijzigingen:
|
||||
- Gesproken meldingen van hartslag
|
||||
|
||||
Bugfix:
|
||||
- Crash due to race condition
|
||||
- Vastloper door race condities
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+2
-1
@@ -1,5 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@@ -80,13 +80,10 @@ do
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -143,12 +140,16 @@ fi
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@@ -193,6 +194,10 @@ if "$cygwin" || "$msys" ; then
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
|
||||
Vendored
+1
@@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.anything;
|
||||
import static de.dennisguse.opentracks.util.EspressoUtils.childAtPosition;
|
||||
import static de.dennisguse.opentracks.util.EspressoUtils.waitFor;
|
||||
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||
@@ -30,7 +31,7 @@ public class EspressoDeleteTrackTest {
|
||||
public ActivityScenarioRule<TrackListActivity> mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class);
|
||||
|
||||
@Rule
|
||||
public GrantPermissionRule mGrantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
public GrantPermissionRule mGrantPermissionRule = TestUtil.createGrantPermissionRule();
|
||||
|
||||
@Test
|
||||
public void espressoDeleteTrackTest() {
|
||||
@@ -51,7 +52,15 @@ public class EspressoDeleteTrackTest {
|
||||
onData(anything()).inAdapterView(withId(R.id.track_list)).atPosition(0).perform(longClick());
|
||||
|
||||
// open menu and delete selected track
|
||||
onView(allOf(withContentDescription("More options"), isDisplayed()))
|
||||
//TODO openActionBarOverflowOrOptionsMenu(); doesn't work
|
||||
onView(
|
||||
allOf(withContentDescription("More options"),
|
||||
childAtPosition(
|
||||
childAtPosition(
|
||||
withId(androidx.appcompat.R.id.action_mode_bar),
|
||||
1),
|
||||
2),
|
||||
isDisplayed()))
|
||||
.perform(click());
|
||||
|
||||
onView(withText("Delete")).perform(click());
|
||||
|
||||
@@ -38,7 +38,7 @@ public class EspressoEditTrackRecordingTest {
|
||||
public ActivityScenarioRule<TrackListActivity> mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class);
|
||||
|
||||
@Rule
|
||||
public GrantPermissionRule mGrantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
public GrantPermissionRule mGrantPermissionRule = TestUtil.createGrantPermissionRule();
|
||||
|
||||
@LargeTest
|
||||
@Test
|
||||
|
||||
@@ -31,8 +31,7 @@ public class EspressoUITest {
|
||||
public ActivityScenarioRule<TrackListActivity> mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class);
|
||||
|
||||
@Rule
|
||||
public GrantPermissionRule mGrantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
|
||||
public GrantPermissionRule mGrantPermissionRule = TestUtil.createGrantPermissionRule();
|
||||
@LargeTest
|
||||
@Test
|
||||
public void record_stop_resume_stop_finish() {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.dennisguse.opentracks;
|
||||
|
||||
import android.Manifest;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.test.rule.GrantPermissionRule;
|
||||
|
||||
public class TestUtil {
|
||||
|
||||
public static GrantPermissionRule createGrantPermissionRule() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
return GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.POST_NOTIFICATIONS);
|
||||
}
|
||||
return GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.BLUETOOTH_CONNECT);
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ public class ChartPointTest {
|
||||
statistics.setTotalTime(Duration.ofSeconds(1000));
|
||||
|
||||
// when
|
||||
ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(0), false, UnitSystem.IMPERIAL);
|
||||
ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(0), false, UnitSystem.IMPERIAL_FEET);
|
||||
|
||||
// then
|
||||
assertEquals(1000000, (long) point.getTimeOrDistance());
|
||||
|
||||
@@ -96,16 +96,7 @@ public class TestDataUtil {
|
||||
return new TrackData(track, trackPoints, markers);
|
||||
}
|
||||
|
||||
public static class TrackData {
|
||||
public final Track track;
|
||||
public final List<TrackPoint> trackPoints;
|
||||
public final List<Marker> markers;
|
||||
|
||||
public TrackData(Track track, List<TrackPoint> trackPoints, List<Marker> markers) {
|
||||
this.track = track;
|
||||
this.trackPoints = trackPoints;
|
||||
this.markers = markers;
|
||||
}
|
||||
public record TrackData(Track track, List<TrackPoint> trackPoints, List<Marker> markers) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -424,7 +424,7 @@ public class CustomContentProviderUtilsTest {
|
||||
Marker.Id markerId = new Marker.Id(System.currentTimeMillis());
|
||||
marker.setId(markerId);
|
||||
ContentValues contentValues = contentProviderUtils.createContentValues(marker);
|
||||
assertEquals(markerId.getId(), contentValues.get(MarkerColumns._ID));
|
||||
assertEquals(markerId.id(), contentValues.get(MarkerColumns._ID));
|
||||
assertEquals((int) (TestDataUtil.INITIAL_LONGITUDE * 1000000), contentValues.get(MarkerColumns.LONGITUDE));
|
||||
assertEquals(TEST_DESC, contentValues.get(MarkerColumns.DESCRIPTION));
|
||||
}
|
||||
@@ -458,7 +458,7 @@ public class CustomContentProviderUtilsTest {
|
||||
when(cursorMock.getLong(columnIndex++)).thenReturn(trackId);
|
||||
|
||||
Marker marker = contentProviderUtils.createMarker(cursorMock);
|
||||
assertEquals(id, marker.getId().getId());
|
||||
assertEquals(id, marker.getId().id());
|
||||
assertEquals(name, marker.getName());
|
||||
assertEquals(trackId, marker.getTrackId().getId());
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public class TrackSelectionTest extends TestCase {
|
||||
@Test
|
||||
public void testFilterBuildSelection_onlyOneCategory() {
|
||||
// given
|
||||
TrackSelection filter = new TrackSelection().addCategory("running");
|
||||
TrackSelection filter = new TrackSelection().addActivityType("running");
|
||||
|
||||
// when
|
||||
SelectionData selection = filter.buildSelection();
|
||||
@@ -82,10 +82,10 @@ public class TrackSelectionTest extends TestCase {
|
||||
public void testFilterBuildSelection_severalCategories() {
|
||||
// given
|
||||
TrackSelection filter = new TrackSelection()
|
||||
.addCategory("running")
|
||||
.addCategory("road biking")
|
||||
.addCategory("mountain biking")
|
||||
.addCategory("trail walking");
|
||||
.addActivityType("running")
|
||||
.addActivityType("road biking")
|
||||
.addActivityType("mountain biking")
|
||||
.addActivityType("trail walking");
|
||||
|
||||
// when
|
||||
SelectionData selection = filter.buildSelection();
|
||||
@@ -136,8 +136,8 @@ public class TrackSelectionTest extends TestCase {
|
||||
.addTrackId(trackId1)
|
||||
.addTrackId(trackId2)
|
||||
.addTrackId(trackId3)
|
||||
.addCategory("running")
|
||||
.addCategory("road biking");
|
||||
.addActivityType("running")
|
||||
.addActivityType("road biking");
|
||||
|
||||
// when
|
||||
SelectionData selection = filter.buildSelection();
|
||||
@@ -188,8 +188,8 @@ public class TrackSelectionTest extends TestCase {
|
||||
long oneDay = 24 * 60 * 60 * 1000;
|
||||
|
||||
TrackSelection filter = new TrackSelection()
|
||||
.addCategory("running")
|
||||
.addCategory("road biking")
|
||||
.addActivityType("running")
|
||||
.addActivityType("road biking")
|
||||
.addDateRange(instant, instant.plusMillis(oneDay));
|
||||
|
||||
// when
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ public class DistanceFormatterTest {
|
||||
public void testFormatDistance_imperial() {
|
||||
DistanceFormatter formatter = DistanceFormatter.Builder()
|
||||
.setDecimalCount(2)
|
||||
.setUnit(UnitSystem.IMPERIAL)
|
||||
.setUnit(UnitSystem.IMPERIAL_FEET)
|
||||
.build(context);
|
||||
|
||||
// A large number in imperial
|
||||
|
||||
@@ -36,7 +36,7 @@ public class SpeedFormatterTest {
|
||||
public void testGetSpeedParts_pace_imperial() {
|
||||
SpeedFormatter formatter = SpeedFormatter.Builder()
|
||||
.setDecimalCount(2)
|
||||
.setUnit(UnitSystem.IMPERIAL)
|
||||
.setUnit(UnitSystem.IMPERIAL_FEET)
|
||||
.setReportSpeedOrPace(false)
|
||||
.build(context);
|
||||
|
||||
@@ -72,7 +72,7 @@ public class SpeedFormatterTest {
|
||||
public void testGetSpeedParts_speed_imperial() {
|
||||
SpeedFormatter formatter = SpeedFormatter.Builder()
|
||||
.setDecimalCount(2)
|
||||
.setUnit(UnitSystem.IMPERIAL)
|
||||
.setUnit(UnitSystem.IMPERIAL_FEET)
|
||||
.setReportSpeedOrPace(true)
|
||||
.build(context);
|
||||
|
||||
|
||||
+42
-48
@@ -46,6 +46,7 @@ import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.TimezoneRule;
|
||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.data.models.ActivityType;
|
||||
import de.dennisguse.opentracks.data.models.Cadence;
|
||||
import de.dennisguse.opentracks.data.models.Distance;
|
||||
import de.dennisguse.opentracks.data.models.HeartRate;
|
||||
@@ -57,7 +58,6 @@ import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
||||
import de.dennisguse.opentracks.sensors.AltitudeSumManager;
|
||||
import de.dennisguse.opentracks.sensors.BluetoothRemoteSensorManager;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingCadence;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingDistanceSpeed;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingPower;
|
||||
@@ -96,8 +96,8 @@ public class ExportImportTest {
|
||||
|
||||
private final ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
||||
|
||||
private static final String TRACK_ICON = "the track icon";
|
||||
private static final String TRACK_CATEGORY = "the category";
|
||||
private static final ActivityType TRACK_ACTIVITY_TYPE = ActivityType.MOUNTAIN_BIKING;
|
||||
private static final String TRACK_ACTIVITY_TYPE_LOCALIZED = "the activity type";
|
||||
private static final String TRACK_DESCRIPTION = "the description";
|
||||
|
||||
private File tmpFile;
|
||||
@@ -165,8 +165,7 @@ public class ExportImportTest {
|
||||
service.insertMarker("Marker 2", "Marker 2 category", "Marker 2 desc", null);
|
||||
|
||||
trackPointCreator.setClock("2020-02-02T02:02:18Z");
|
||||
BluetoothRemoteSensorManager mockRemoteSensorManager = Mockito.mock(BluetoothRemoteSensorManager.class);
|
||||
trackPointCreator.getSensorManager().setBluetoothSensorManager(mockRemoteSensorManager);
|
||||
trackPointCreator.getSensorManager().sensorDataSet = new SensorDataSet();
|
||||
service.endCurrentTrack();
|
||||
|
||||
trackPointCreator.setClock("2020-02-02T02:03:20Z");
|
||||
@@ -179,12 +178,11 @@ public class ExportImportTest {
|
||||
sendLocation(trackPointCreator, "2020-02-02T02:03:23Z", 3, 16.001, 10, 27, 15, 10, 0);
|
||||
|
||||
trackPointCreator.setClock("2020-02-02T02:03:24Z");
|
||||
trackPointCreator.getSensorManager().setBluetoothSensorManager(mockRemoteSensorManager);
|
||||
service.endCurrentTrack();
|
||||
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
track.setIcon(TRACK_ICON);
|
||||
track.setCategory(TRACK_CATEGORY);
|
||||
track.setActivityType(TRACK_ACTIVITY_TYPE);
|
||||
track.setActivityTypeLocalized(TRACK_ACTIVITY_TYPE_LOCALIZED);
|
||||
track.setDescription(TRACK_DESCRIPTION);
|
||||
contentProviderUtils.updateTrack(track);
|
||||
|
||||
@@ -195,7 +193,7 @@ public class ExportImportTest {
|
||||
assertEquals(2, markers.size());
|
||||
}
|
||||
|
||||
//TODO Does not test images
|
||||
//TODO Does not test marker images
|
||||
@LargeTest
|
||||
@Test
|
||||
public void kmz_with_trackdetail_and_sensordata() throws TimeoutException, IOException {
|
||||
@@ -204,11 +202,11 @@ public class ExportImportTest {
|
||||
// given
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
|
||||
TrackExporter trackExporter = TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA.createTrackExporter(context, contentProviderUtils);
|
||||
TrackExporter trackExporter = TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA_AND_PICTURES.createTrackExporter(context, contentProviderUtils);
|
||||
|
||||
// when
|
||||
// 1. export
|
||||
trackExporter.writeTrack(track, context.getContentResolver().openOutputStream(tmpFileUri));
|
||||
trackExporter.writeTrack(List.of(track), context.getContentResolver().openOutputStream(tmpFileUri));
|
||||
contentProviderUtils.deleteTrack(context, trackId);
|
||||
|
||||
// 2. import
|
||||
@@ -219,10 +217,10 @@ public class ExportImportTest {
|
||||
// 1. track
|
||||
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||
assertNotNull(importedTrack);
|
||||
assertEquals(track.getCategory(), importedTrack.getCategory());
|
||||
assertEquals(track.getActivityTypeLocalized(), importedTrack.getActivityTypeLocalized());
|
||||
assertEquals(track.getDescription(), importedTrack.getDescription());
|
||||
assertEquals(track.getName(), importedTrack.getName());
|
||||
assertEquals(track.getIcon(), importedTrack.getIcon());
|
||||
assertEquals(track.getActivityType(), importedTrack.getActivityType());
|
||||
|
||||
// 2. trackpoints
|
||||
TrackPointAssert a = new TrackPointAssert();
|
||||
@@ -240,24 +238,24 @@ public class ExportImportTest {
|
||||
TrackStatistics originalTrackStatistics = track.getTrackStatistics();
|
||||
|
||||
assertEquals(originalTrackStatistics.getTotalTime(), importedTrackStatistics.getTotalTime());
|
||||
assertEquals(Duration.ofSeconds(19), importedTrackStatistics.getTotalTime());
|
||||
assertEquals(Duration.ofSeconds(20), importedTrackStatistics.getTotalTime());
|
||||
|
||||
assertEquals(originalTrackStatistics.getMovingTime(), importedTrackStatistics.getMovingTime());
|
||||
assertEquals(Duration.ofSeconds(3), importedTrackStatistics.getMovingTime());
|
||||
assertEquals(Duration.ofSeconds(4), importedTrackStatistics.getMovingTime());
|
||||
|
||||
// Distance
|
||||
assertEquals(originalTrackStatistics.getTotalDistance(), importedTrackStatistics.getTotalDistance());
|
||||
assertEquals(125.16, importedTrackStatistics.getTotalDistance().toM(), 0.01);
|
||||
assertEquals(222238.70, importedTrackStatistics.getTotalDistance().toM(), 0.01);
|
||||
|
||||
// Speed
|
||||
assertEquals(originalTrackStatistics.getMaxSpeed(), importedTrackStatistics.getMaxSpeed());
|
||||
assertEquals(41.72, importedTrackStatistics.getMaxSpeed().toMPS(), 0.01);
|
||||
assertEquals(55559.67, importedTrackStatistics.getMaxSpeed().toMPS(), 0.01);
|
||||
|
||||
assertEquals(originalTrackStatistics.getAverageSpeed(), importedTrackStatistics.getAverageSpeed());
|
||||
assertEquals(6.58, importedTrackStatistics.getAverageSpeed().toMPS(), 0.01);
|
||||
assertEquals(11111.93, importedTrackStatistics.getAverageSpeed().toMPS(), 0.01);
|
||||
|
||||
assertEquals(originalTrackStatistics.getAverageMovingSpeed(), importedTrackStatistics.getAverageMovingSpeed());
|
||||
assertEquals(41.72, importedTrackStatistics.getMaxSpeed().toMPS(), 0.01);
|
||||
assertEquals(55559.67, importedTrackStatistics.getMaxSpeed().toMPS(), 0.01);
|
||||
|
||||
// Altitude
|
||||
assertEquals(originalTrackStatistics.getMinAltitude(), importedTrackStatistics.getMinAltitude(), 0.01);
|
||||
@@ -290,7 +288,7 @@ public class ExportImportTest {
|
||||
TrackExporter trackExporter = TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA.createTrackExporter(context, contentProviderUtils);
|
||||
|
||||
// when
|
||||
trackExporter.writeTrack(track, context.getContentResolver().openOutputStream(tmpFileUri));
|
||||
trackExporter.writeTrack(List.of(track), context.getContentResolver().openOutputStream(tmpFileUri));
|
||||
|
||||
// 2. import
|
||||
InputStream inputStream = context.getContentResolver().openInputStream(tmpFileUri);
|
||||
@@ -314,7 +312,7 @@ public class ExportImportTest {
|
||||
|
||||
// when
|
||||
// 1. export
|
||||
trackExporter.writeTrack(track, context.getContentResolver().openOutputStream(tmpFileUri));
|
||||
trackExporter.writeTrack(List.of(track), context.getContentResolver().openOutputStream(tmpFileUri));
|
||||
contentProviderUtils.deleteTrack(context, trackId);
|
||||
|
||||
// 2. import
|
||||
@@ -326,7 +324,7 @@ public class ExportImportTest {
|
||||
// 1. track
|
||||
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||
assertNotNull(importedTrack);
|
||||
assertEquals(track.getCategory(), importedTrack.getCategory());
|
||||
assertEquals(track.getActivityTypeLocalized(), importedTrack.getActivityTypeLocalized());
|
||||
assertEquals(track.getDescription(), importedTrack.getDescription());
|
||||
assertEquals(track.getName(), importedTrack.getName());
|
||||
|
||||
@@ -396,16 +394,16 @@ public class ExportImportTest {
|
||||
assertEquals(Instant.parse("2020-02-02T02:02:03Z"), importedTrackStatistics.getStartTime());
|
||||
assertEquals(Instant.parse("2020-02-02T02:03:23Z"), importedTrackStatistics.getStopTime());
|
||||
|
||||
assertEquals(Duration.ofSeconds(15), importedTrackStatistics.getTotalTime());
|
||||
assertEquals(Duration.ofSeconds(15), importedTrackStatistics.getMovingTime());
|
||||
assertEquals(Duration.ofSeconds(80), importedTrackStatistics.getTotalTime());
|
||||
assertEquals(Duration.ofSeconds(80), importedTrackStatistics.getMovingTime());
|
||||
|
||||
// Distance
|
||||
assertEquals(125.16, importedTrackStatistics.getTotalDistance().toM(), 0.01);
|
||||
assertEquals(222349.85, importedTrackStatistics.getTotalDistance().toM(), 0.01);
|
||||
|
||||
// Speed
|
||||
assertEquals(8.34, importedTrackStatistics.getMaxSpeed().toMPS(), 0.01);
|
||||
assertEquals(8.34, importedTrackStatistics.getAverageSpeed().toMPS(), 0.01);
|
||||
assertEquals(8.34, importedTrackStatistics.getAverageMovingSpeed().toMPS(), 0.01);
|
||||
assertEquals(2779.37, importedTrackStatistics.getMaxSpeed().toMPS(), 0.01);
|
||||
assertEquals(2779.37, importedTrackStatistics.getAverageSpeed().toMPS(), 0.01);
|
||||
assertEquals(2779.37, importedTrackStatistics.getAverageMovingSpeed().toMPS(), 0.01);
|
||||
|
||||
// Altitude
|
||||
assertEquals(10, importedTrackStatistics.getMinAltitude(), 0.01);
|
||||
@@ -432,7 +430,7 @@ public class ExportImportTest {
|
||||
|
||||
// when
|
||||
// 1. export
|
||||
trackExporter.writeTrack(track, context.getContentResolver().openOutputStream(tmpFileUri));
|
||||
trackExporter.writeTrack(List.of(track), context.getContentResolver().openOutputStream(tmpFileUri));
|
||||
|
||||
// 2. import
|
||||
InputStream inputStream = context.getContentResolver().openInputStream(tmpFileUri);
|
||||
@@ -457,7 +455,7 @@ public class ExportImportTest {
|
||||
|
||||
// when
|
||||
// 1. export
|
||||
trackExporter.writeTrack(track, context.getContentResolver().openOutputStream(tmpFileUri));
|
||||
trackExporter.writeTrack(List.of(track), context.getContentResolver().openOutputStream(tmpFileUri));
|
||||
contentProviderUtils.deleteTrack(context, trackId);
|
||||
|
||||
// then
|
||||
@@ -495,9 +493,6 @@ public class ExportImportTest {
|
||||
}
|
||||
|
||||
private void mockBLESensorData(TrackPointCreator trackPointCreator, Float speed, Distance distance, float heartRate, float cadence, Float power) {
|
||||
BluetoothRemoteSensorManager remoteSensorManager = Mockito.mock(BluetoothRemoteSensorManager.class);
|
||||
Mockito.when(remoteSensorManager.fill(Mockito.any())).thenAnswer(invocation -> {
|
||||
TrackPoint trackPoint = invocation.getArgument(0);
|
||||
|
||||
SensorDataSet sensorDataSet = new SensorDataSet();
|
||||
sensorDataSet.set(new SensorDataCyclingPower("power", "power", Power.of(power)));
|
||||
@@ -508,21 +503,20 @@ public class ExportImportTest {
|
||||
Mockito.when(cyclingCadence.getValue()).thenReturn(Cadence.of(cadence));
|
||||
sensorDataSet.set(cyclingCadence);
|
||||
|
||||
if (distance != null && speed != null) {
|
||||
SensorDataCyclingDistanceSpeed.Data distanceSpeedData = Mockito.mock(SensorDataCyclingDistanceSpeed.Data.class);
|
||||
Mockito.when(distanceSpeedData.getDistanceOverall()).thenReturn(distance);
|
||||
Mockito.when(distanceSpeedData.getSpeed()).thenReturn(Speed.of(speed));
|
||||
SensorDataCyclingDistanceSpeed distanceSpeed = Mockito.mock(SensorDataCyclingDistanceSpeed.class);
|
||||
Mockito.when(distanceSpeed.hasValue()).thenReturn(true);
|
||||
Mockito.when(distanceSpeed.getValue()).thenReturn(distanceSpeedData);
|
||||
sensorDataSet.set(distanceSpeed);
|
||||
}
|
||||
if (distance != null && speed != null) {
|
||||
SensorDataCyclingDistanceSpeed.Data distanceSpeedData = Mockito.mock(SensorDataCyclingDistanceSpeed.Data.class);
|
||||
Mockito.when(distanceSpeedData.getDistanceOverall()).thenReturn(distance);
|
||||
Mockito.when(distanceSpeedData.getSpeed()).thenReturn(Speed.of(speed));
|
||||
SensorDataCyclingDistanceSpeed distanceSpeed = Mockito.mock(SensorDataCyclingDistanceSpeed.class);
|
||||
Mockito.when(distanceSpeed.hasValue()).thenReturn(true);
|
||||
Mockito.when(distanceSpeed.getValue()).thenReturn(distanceSpeedData);
|
||||
sensorDataSet.set(distanceSpeed);
|
||||
}
|
||||
|
||||
sensorDataSet.fillTrackPoint(trackPoint);
|
||||
return sensorDataSet;
|
||||
});
|
||||
trackPointCreator.getSensorManager().setBluetoothSensorManager(remoteSensorManager);
|
||||
trackPointCreator.onChange(new SensorDataSet());
|
||||
trackPointCreator.getSensorManager().sensorDataSet = sensorDataSet;
|
||||
trackPointCreator.onChange(sensorDataSet);
|
||||
|
||||
//TODO Might require: getSensorManager().sensorDataSet = new SensorDataSet()
|
||||
}
|
||||
|
||||
private void mockAltitudeChange(TrackPointCreator trackPointCreator, float altitudeGain) {
|
||||
@@ -545,6 +539,6 @@ public class ExportImportTest {
|
||||
mockAltitudeChange(trackPointCreator, altitudeGain);
|
||||
|
||||
trackPointCreator.setClock(time);
|
||||
trackPointCreator.getGpsHandler().onLocationChanged(location);
|
||||
trackPointCreator.onChange(location);
|
||||
}
|
||||
}
|
||||
+8
-7
@@ -28,6 +28,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.data.models.ActivityType;
|
||||
import de.dennisguse.opentracks.data.models.Distance;
|
||||
import de.dennisguse.opentracks.data.models.Speed;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
@@ -79,10 +80,10 @@ public class GPXTrackImporterTest {
|
||||
// 2. track
|
||||
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||
assertNotNull(importedTrack);
|
||||
assertEquals("the category", importedTrack.getCategory());
|
||||
assertEquals("the category", importedTrack.getActivityTypeLocalized());
|
||||
assertEquals("the description", importedTrack.getDescription());
|
||||
assertEquals("2021-01-07 22:51", importedTrack.getName());
|
||||
assertEquals("UNKNOWN", importedTrack.getIcon());
|
||||
assertEquals(ActivityType.UNKNOWN, importedTrack.getActivityType());
|
||||
|
||||
//TODO Check trackstatistics
|
||||
|
||||
@@ -133,10 +134,10 @@ public class GPXTrackImporterTest {
|
||||
// 2. track
|
||||
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||
assertNotNull(importedTrack);
|
||||
assertEquals("", importedTrack.getCategory());
|
||||
assertEquals("", importedTrack.getActivityTypeLocalized());
|
||||
assertEquals("", importedTrack.getDescription());
|
||||
assertEquals("20210907_213924.gpx", importedTrack.getName());
|
||||
assertEquals("", importedTrack.getIcon());
|
||||
assertEquals(ActivityType.UNKNOWN, importedTrack.getActivityType());
|
||||
|
||||
// 3. trackstatistics
|
||||
TrackStatistics trackStatistics = importedTrack.getTrackStatistics();
|
||||
@@ -181,10 +182,10 @@ public class GPXTrackImporterTest {
|
||||
// 2. track
|
||||
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||
assertNotNull(importedTrack);
|
||||
assertEquals("", importedTrack.getCategory());
|
||||
assertEquals("", importedTrack.getActivityTypeLocalized());
|
||||
assertEquals("", importedTrack.getDescription());
|
||||
assertEquals("20210907_213924.gpx", importedTrack.getName());
|
||||
assertEquals("", importedTrack.getIcon());
|
||||
assertEquals(ActivityType.UNKNOWN, importedTrack.getActivityType());
|
||||
|
||||
// 3. trackstatistics
|
||||
TrackStatistics trackStatistics = importedTrack.getTrackStatistics();
|
||||
@@ -232,7 +233,7 @@ public class GPXTrackImporterTest {
|
||||
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||
|
||||
TrackExporter trackExporter = TrackFileFormat.GPX.createTrackExporter(context, contentProviderUtils);
|
||||
trackExporter.writeTrack(importedTrack, outputStream);
|
||||
trackExporter.writeTrack(List.of(importedTrack), outputStream);
|
||||
|
||||
// then
|
||||
String expected = new BufferedReader(
|
||||
|
||||
+7
-6
@@ -22,6 +22,7 @@ import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.data.models.ActivityType;
|
||||
import de.dennisguse.opentracks.data.models.Distance;
|
||||
import de.dennisguse.opentracks.data.models.Speed;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
@@ -70,10 +71,10 @@ public class KMLTrackImporterTest {
|
||||
// 1. track
|
||||
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||
assertNotNull(importedTrack);
|
||||
assertEquals("", importedTrack.getCategory());
|
||||
assertEquals("", importedTrack.getActivityTypeLocalized());
|
||||
assertEquals("", importedTrack.getDescription());
|
||||
assertEquals("", importedTrack.getName());
|
||||
assertEquals("", importedTrack.getIcon());
|
||||
assertEquals(ActivityType.UNKNOWN, importedTrack.getActivityType());
|
||||
|
||||
// 2. markers
|
||||
assertEquals(0, contentProviderUtils.getMarkers(importTrackId).size());
|
||||
@@ -119,10 +120,10 @@ public class KMLTrackImporterTest {
|
||||
// 1. track
|
||||
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||
assertNotNull(importedTrack);
|
||||
assertEquals("", importedTrack.getCategory());
|
||||
assertEquals("", importedTrack.getActivityTypeLocalized());
|
||||
assertEquals("", importedTrack.getDescription());
|
||||
assertEquals("", importedTrack.getName());
|
||||
assertEquals("", importedTrack.getIcon());
|
||||
assertEquals(ActivityType.UNKNOWN, importedTrack.getActivityType());
|
||||
|
||||
// 2. markers
|
||||
assertEquals(0, contentProviderUtils.getMarkers(importTrackId).size());
|
||||
@@ -159,10 +160,10 @@ public class KMLTrackImporterTest {
|
||||
// 1. track
|
||||
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||
assertNotNull(importedTrack);
|
||||
assertEquals("unknown", importedTrack.getCategory());
|
||||
assertEquals("unknown", importedTrack.getActivityTypeLocalized());
|
||||
assertEquals("Test Track", importedTrack.getDescription());
|
||||
assertEquals("2020-11-28 18:06", importedTrack.getName());
|
||||
assertEquals("UNKNOWN", importedTrack.getIcon());
|
||||
assertEquals(ActivityType.UNKNOWN, importedTrack.getActivityType());
|
||||
|
||||
// 2. markers
|
||||
assertEquals(0, contentProviderUtils.getMarkers(importTrackId).size());
|
||||
|
||||
@@ -1,47 +1,55 @@
|
||||
package de.dennisguse.opentracks.sensors;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.AtmosphericPressure;
|
||||
import de.dennisguse.opentracks.sensors.driver.BarometerInternal;
|
||||
|
||||
/**
|
||||
* NOTE: Test data is completely artificial.
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AltitudeSumManagerTest {
|
||||
|
||||
private final AltitudeSumManager subject = new AltitudeSumManager();
|
||||
|
||||
private static void addSensorValue(AltitudeSumManager altitudeSumManager, float[] values) {
|
||||
for (float f : values) {
|
||||
altitudeSumManager.onSensorValueChanged(f);
|
||||
altitudeSumManager.onSensorValueChanged(AtmosphericPressure.ofHPA(f));
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
subject.reset();
|
||||
}
|
||||
@Mock
|
||||
BarometerInternal driver;
|
||||
|
||||
@Test
|
||||
public void getAltitudeGainLoss_downhill() {
|
||||
// given
|
||||
subject.setConnected(true);
|
||||
AltitudeSumManager subject = new AltitudeSumManager(driver);
|
||||
|
||||
when(driver.isConnected()).thenReturn(true);
|
||||
|
||||
// then
|
||||
addSensorValue(subject, new float[]{1015f, 1015.01f, 1015.02f, 1015.03f, 1015.04f, 1015.05f, 1015.06f, 1015.07f, 1015.08f, 1015.09f, 1015.10f, 1015.11f, 1015.12f, 1015.13f, 1015.14f, 1015.15f});
|
||||
addSensorValue(subject, new float[]{1015f, 1015.01f, 1015.02f, 1015.03f, 1015.04f, 1015.05f, 1015.06f, 1015.07f, 1015.08f, 1015.09f, 1015.10f, 1015.11f, 1015.12f, 1015.13f, 1018f, 1018.1f, 1018.1f, 1018.1f, 1018.1f});
|
||||
|
||||
// then
|
||||
Assert.assertEquals(0f, subject.getAltitudeGain_m(), 0.01);
|
||||
Assert.assertEquals(48.0, subject.getAltitudeLoss_m(), 0.01);
|
||||
Assert.assertEquals(15f, subject.getAltitudeLoss_m(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sensorUnavailable() {
|
||||
// given
|
||||
subject.setConnected(false);
|
||||
AltitudeSumManager subject = new AltitudeSumManager(driver);
|
||||
|
||||
when(driver.isConnected()).thenReturn(true);
|
||||
|
||||
// then
|
||||
subject.onSensorValueChanged(999f);
|
||||
subject.onSensorValueChanged(AtmosphericPressure.ofHPA(999f));
|
||||
|
||||
// then
|
||||
Assert.assertNull(subject.getAltitudeGain_m());
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.bluetooth.BluetoothGattCharacteristic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.AtmosphericPressure;
|
||||
import de.dennisguse.opentracks.data.models.Cadence;
|
||||
import de.dennisguse.opentracks.data.models.Distance;
|
||||
import de.dennisguse.opentracks.data.models.HeartRate;
|
||||
@@ -20,7 +21,7 @@ public class BluetoothUtilsTest {
|
||||
@Test
|
||||
public void parseHeartRate_uint8() {
|
||||
// given
|
||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.HEARTRATE.getServiceUUID(), 0, 0);
|
||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.HEARTRATE.serviceUUID(), 0, 0);
|
||||
characteristic.setValue(new byte[]{0x02, 0x3C});
|
||||
|
||||
// when
|
||||
@@ -33,7 +34,7 @@ public class BluetoothUtilsTest {
|
||||
@Test
|
||||
public void parseHeartRate_uint16() {
|
||||
// given
|
||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.HEARTRATE.getServiceUUID(), 0, 0);
|
||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.HEARTRATE.serviceUUID(), 0, 0);
|
||||
characteristic.setValue(new byte[]{0x01, 0x01, 0x01});
|
||||
|
||||
// when
|
||||
@@ -43,9 +44,22 @@ public class BluetoothUtilsTest {
|
||||
assertEquals(HeartRate.of(257), heartRate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseEnvironmentalSensing_Pa() {
|
||||
// given
|
||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.BAROMETRIC_PRESSURE.serviceUUID(), 0, 0);
|
||||
characteristic.setValue(new byte[]{(byte) 0xB2, (byte) 0x48, (byte) 0x0F, (byte) 0x00});
|
||||
|
||||
// when
|
||||
AtmosphericPressure pressure = BluetoothUtils.parseEnvironmentalSensing(characteristic);
|
||||
|
||||
// then
|
||||
assertEquals(AtmosphericPressure.ofPA(100165), pressure);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseCyclingSpeedCadence_crankOnly() {
|
||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_SPEED_CADENCE.getServiceUUID(), 0, 0);
|
||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_SPEED_CADENCE.serviceUUID(), 0, 0);
|
||||
characteristic.setValue(new byte[]{0x02, (byte) 0xC8, 0x00, 0x00, 0x00, 0x06, (byte) 0x99});
|
||||
|
||||
// when
|
||||
@@ -58,7 +72,7 @@ public class BluetoothUtilsTest {
|
||||
|
||||
@Test
|
||||
public void parseCyclingSpeedCadence_wheelOnly() {
|
||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_SPEED_CADENCE.getServiceUUID(), 0, 0);
|
||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_SPEED_CADENCE.serviceUUID(), 0, 0);
|
||||
characteristic.setValue(new byte[]{0x01, (byte) 0xFF, (byte) 0xFF, 0, 1, 0x45, (byte) 0x99});
|
||||
|
||||
// when
|
||||
@@ -71,7 +85,7 @@ public class BluetoothUtilsTest {
|
||||
|
||||
@Test
|
||||
public void parseCyclingSpeedCadence_crankWheel() {
|
||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_SPEED_CADENCE.getServiceUUID(), 0, 0);
|
||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_SPEED_CADENCE.serviceUUID(), 0, 0);
|
||||
characteristic.setValue(new byte[]{0x03, (byte) 0xC8, 0x00, 0x00, 0x01, 0x06, (byte) 0x99, (byte) 0xE1, 0x00, 0x45, (byte) 0x99});
|
||||
|
||||
// when
|
||||
@@ -84,34 +98,34 @@ public class BluetoothUtilsTest {
|
||||
|
||||
@Test
|
||||
public void parseCyclingPower_power() {
|
||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_POWER.getServiceUUID(), 0, 0);
|
||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_POWER.serviceUUID(), 0, 0);
|
||||
characteristic.setValue(new byte[]{0, 0, 40, 0});
|
||||
|
||||
// when
|
||||
SensorDataCyclingPower.Data powerCadence = BluetoothUtils.parseCyclingPower("", "", characteristic);
|
||||
|
||||
// then
|
||||
assertEquals(40, powerCadence.getPower().getValue().getW(), 0.01);
|
||||
assertEquals(40, powerCadence.power().getValue().getW(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseCyclingPower_power_with_cadence() {
|
||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_POWER.getServiceUUID(), 0, 0);
|
||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_POWER.serviceUUID(), 0, 0);
|
||||
characteristic.setValue(new byte[]{0x2C, 0x00, 0x00, 0x00, (byte) 0x9F, 0x00, 0x0C, 0x00, (byte) 0xE5, 0x42});
|
||||
|
||||
// when
|
||||
SensorDataCyclingPower.Data powerCadence = BluetoothUtils.parseCyclingPower("", "", characteristic);
|
||||
|
||||
// then
|
||||
assertEquals(0, powerCadence.getPower().getValue().getW(), 0.01);
|
||||
assertEquals(0, powerCadence.power().getValue().getW(), 0.01);
|
||||
|
||||
assertEquals(12, powerCadence.getCadence().getCrankRevolutionsCount());
|
||||
assertEquals(17125, powerCadence.getCadence().getCrankRevolutionsTime());
|
||||
assertEquals(12, powerCadence.cadence().getCrankRevolutionsCount());
|
||||
assertEquals(17125, powerCadence.cadence().getCrankRevolutionsTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseRunningSpeedAndCadence_with_distance() {
|
||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.RUNNING_SPEED_CADENCE.getServiceUUID(), 0, 0);
|
||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.RUNNING_SPEED_CADENCE.serviceUUID(), 0, 0);
|
||||
characteristic.setValue(new byte[]{2, 0, 5, 80, (byte) 0xFF, (byte) 0xFF, 0, 1});
|
||||
|
||||
// when
|
||||
|
||||
@@ -5,6 +5,8 @@ import static org.junit.Assert.assertNull;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.AtmosphericPressure;
|
||||
|
||||
public class PressureSensorUtilsTest {
|
||||
|
||||
// real data at 500Hz stationary
|
||||
@@ -12,11 +14,11 @@ public class PressureSensorUtilsTest {
|
||||
public void altitudeChanges_none() {
|
||||
// given
|
||||
float[] sensorValues_hPa = new float[]{1015.6876f, 1015.699f, 1015.70905f, 1015.71075f, 1015.7224f, 1015.72f, 1015.7373f, 1015.7481f, 1015.74133f, 1015.73553f, 1015.7462f, 1015.74896f, 1015.752f, 1015.754f, 1015.7456f, 1015.73303f, 1015.7288f, 1015.7239f, 1015.7298f, 1015.7387f, 1015.72534f, 1015.72577f, 1015.72797f, 1015.71796f, 1015.7113f, 1015.7097f, 1015.7096f, 1015.7013f, 1015.7072f, 1015.71063f, 1015.7088f, 1015.7115f, 1015.713f, 1015.7121f, 1015.7062f, 1015.7062f, 1015.6994f, 1015.69617f, 1015.68945f, 1015.698f, 1015.6913f, 1015.69696f, 1015.69293f, 1015.6955f, 1015.6928f, 1015.6939f, 1015.68787f, 1015.6881f, 1015.68536f, 1015.68726f, 1015.6879f, 1015.6904f, 1015.6937f, 1015.69476f, 1015.7046f, 1015.7019f, 1015.7079f, 1015.71124f, 1015.71216f, 1015.71436f, 1015.7171f, 1015.7186f, 1015.7186f, 1015.7246f, 1015.72046f, 1015.7211f, 1015.72375f, 1015.7194f, 1015.72125f, 1015.7161f, 1015.71185f, 1015.7188f, 1015.721f, 1015.7252f, 1015.72266f, 1015.7236f, 1015.72614f, 1015.7266f, 1015.7344f, 1015.7376f, 1015.7337f, 1015.7253f, 1015.71875f, 1015.7219f, 1015.7219f, 1015.7317f, 1015.7284f, 1015.73444f, 1015.73584f, 1015.7369f, 1015.73254f, 1015.7369f, 1015.7336f, 1015.73254f, 1015.73676f, 1015.74176f, 1015.74506f, 1015.7478f, 1015.755f, 1015.7515f, 1015.7543f, 1015.7459f, 1015.7468f, 1015.7492f, 1015.74585f, 1015.74756f, 1015.74756f, 1015.75085f, 1015.754f, 1015.75336f, 1015.7568f, 1015.75165f, 1015.761f, 1015.7527f, 1015.75684f, 1015.7635f, 1015.7585f, 1015.7552f, 1015.7475f, 1015.74506f, 1015.7542f, 1015.75586f, 1015.74176f, 1015.74414f, 1015.7501f, 1015.751f, 1015.7478f, 1015.755f, 1015.75836f, 1015.7592f, 1015.75256f, 1015.7559f, 1015.76654f, 1015.76154f, 1015.766f, 1015.77014f, 1015.76904f, 1015.76013f, 1015.7674f, 1015.76514f, 1015.7674f, 1015.7635f, 1015.76404f, 1015.7607f, 1015.754f, 1015.7574f, 1015.7607f, 1015.7607f, 1015.7607f, 1015.754f, 1015.7567f, 1015.7616f, 1015.7643f, 1015.7666f, 1015.7609f, 1015.766f, 1015.76764f, 1015.755f, 1015.75757f, 1015.74927f, 1015.74927f, 1015.7426f, 1015.745f, 1015.745f, 1015.7409f, 1015.7376f, 1015.7326f, 1015.74164f, 1015.74664f, 1015.745f, 1015.7459f, 1015.7502f, 1015.7493f, 1015.7476f, 1015.7493f, 1015.751f, 1015.7601f, 1015.76434f, 1015.766f, 1015.756f, 1015.7617f, 1015.7623f, 1015.76404f, 1015.76733f, 1015.7607f, 1015.7623f, 1015.76337f, 1015.7584f, 1015.7573f, 1015.7502f, 1015.7534f, 1015.7534f, 1015.7601f, 1015.75684f, 1015.7518f, 1015.75574f, 1015.7524f, 1015.7507f, 1015.7484f, 1015.7502f, 1015.7534f, 1015.7623f, 1015.75903f, 1015.75574f, 1015.75574f, 1015.7573f, 1015.7524f, 1015.75574f, 1015.75574f, 1015.7607f, 1015.7573f, 1015.754f, 1015.74677f, 1015.754f, 1015.75574f, 1015.75903f, 1015.7573f, 1015.7551f, 1015.7573f, 1015.754f, 1015.7507f, 1015.7374f, 1015.739f, 1015.73566f, 1015.73566f, 1015.7367f, 1015.7417f, 1015.7417f, 1015.739f, 1015.74835f, 1015.74567f, 1015.7517f, 1015.74066f, 1015.7374f, 1015.739f, 1015.7417f, 1015.73065f, 1015.72894f, 1015.73505f, 1015.73334f, 1015.74005f, 1015.74005f, 1015.7367f, 1015.7434f, 1015.744f, 1015.7423f, 1015.7384f, 1015.739f, 1015.7374f, 1015.7374f, 1015.7374f, 1015.7341f, 1015.73505f, 1015.7341f, 1015.7267f, 1015.72833f, 1015.7234f, 1015.7167f, 1015.725f, 1015.7217f, 1015.7234f, 1015.73004f, 1015.7324f, 1015.7423f, 1015.74005f, 1015.73505f, 1015.73004f, 1015.739f, 1015.7417f, 1015.74567f, 1015.74066f, 1015.74146f, 1015.74146f, 1015.73816f, 1015.7274f, 1015.72906f, 1015.7274f, 1015.7341f, 1015.739f, 1015.744f, 1015.7417f, 1015.7374f, 1015.7324f, 1015.73816f, 1015.74146f, 1015.7374f, 1015.7341f, 1015.7365f, 1015.7365f, 1015.74146f, 1015.74414f, 1015.7475f, 1015.7448f, 1015.74146f, 1015.74585f, 1015.7475f, 1015.75146f, 1015.75146f, 1015.7591f, 1015.75476f, 1015.7614f, 1015.75476f, 1015.7492f, 1015.74817f, 1015.7498f, 1015.7515f, 1015.75586f, 1015.7509f, 1015.7448f, 1015.7525f, 1015.7581f, 1015.7592f};
|
||||
float firstSensorValue = sensorValues_hPa[0];
|
||||
AtmosphericPressure firstSensorValue = AtmosphericPressure.ofHPA(sensorValues_hPa[0]);
|
||||
|
||||
// when // then
|
||||
for (float v : sensorValues_hPa) {
|
||||
assertNull(PressureSensorUtils.computeChanges(firstSensorValue, v));
|
||||
assertNull(PressureSensorUtils.computeChanges(firstSensorValue, AtmosphericPressure.ofHPA(v)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,25 +27,25 @@ public class PressureSensorUtilsTest {
|
||||
@Test
|
||||
public void computeChanges_downhill() {
|
||||
float[] sensorValues_hPa = new float[]{1015f, 1015.01f, 1015.02f, 1015.03f, 1015.04f, 1015.05f, 1015.06f, 1015.07f, 1015.08f, 1015.09f, 1015.10f, 1015.11f, 1015.12f, 1015.13f, 1018f, 1018.1f, 1018.1f, 1018.1f, 1018.1f};
|
||||
float firstSensorValue = sensorValues_hPa[0];
|
||||
AtmosphericPressure firstSensorValue = AtmosphericPressure.ofHPA(sensorValues_hPa[0]);
|
||||
|
||||
// when
|
||||
float altitudeGain_m = 0;
|
||||
float altitudeLoss = 0;
|
||||
float lastUsedPressureValue_hPa = firstSensorValue;
|
||||
AtmosphericPressure lastUsedPressureValue = firstSensorValue;
|
||||
|
||||
for (float v : sensorValues_hPa) {
|
||||
PressureSensorUtils.AltitudeChange altitudeChange = PressureSensorUtils.computeChanges(lastUsedPressureValue_hPa, v);
|
||||
PressureSensorUtils.AltitudeChange altitudeChange = PressureSensorUtils.computeChanges(lastUsedPressureValue, AtmosphericPressure.ofHPA(v));
|
||||
if (altitudeChange != null) {
|
||||
altitudeGain_m += altitudeChange.getAltitudeGain_m();
|
||||
altitudeLoss += altitudeChange.getAltitudeLoss_m();
|
||||
lastUsedPressureValue_hPa = altitudeChange.getCurrentSensorValue_hPa();
|
||||
lastUsedPressureValue = altitudeChange.currentSensorValue();
|
||||
}
|
||||
}
|
||||
|
||||
// then
|
||||
assertEquals(0f, altitudeGain_m, 0.01);
|
||||
assertEquals(15.0f, altitudeLoss, 0.01);
|
||||
assertEquals(1016.80f, lastUsedPressureValue_hPa, 0.01); //Expect exponential smoothing
|
||||
assertEquals(1016.80f, lastUsedPressureValue.getHPA(), 0.01); //Expect exponential smoothing
|
||||
}
|
||||
}
|
||||
@@ -11,13 +11,44 @@ public class UintUtilsTest {
|
||||
assertEquals(0, UintUtils.diff(1, 1, UintUtils.UINT16_MAX));
|
||||
assertEquals(1, UintUtils.diff(2, 1, UintUtils.UINT16_MAX));
|
||||
assertEquals(3, UintUtils.diff(5, 2, UintUtils.UINT16_MAX));
|
||||
assertEquals(65534, UintUtils.diff(1, 2, UintUtils.UINT16_MAX));
|
||||
|
||||
assertEquals(65535, UintUtils.diff(1, 2, UintUtils.UINT16_MAX)); /* unsigned 16 arithmetic is modulo UINT16_MAX + 1, not modulo UINT16_MAX */
|
||||
assertEquals(65530, UintUtils.diff(UintUtils.UINT16_MAX, 5, UintUtils.UINT16_MAX));
|
||||
|
||||
/* Test modulo arithmetic for arguments that are out of range */
|
||||
|
||||
if (false) { /* false means UintUtils.diff() throws if arguments out of range */
|
||||
assertEquals(0, UintUtils.diff(65537, 1, UintUtils.UINT16_MAX));
|
||||
assertEquals(0, UintUtils.diff(1, 65537, UintUtils.UINT16_MAX));
|
||||
assertEquals(0, UintUtils.diff(65537, 65537, UintUtils.UINT16_MAX));
|
||||
assertEquals(0, UintUtils.diff(-65535, 1, UintUtils.UINT16_MAX));
|
||||
assertEquals(0, UintUtils.diff(1, -65535, UintUtils.UINT16_MAX));
|
||||
assertEquals(0, UintUtils.diff(-65535, -65535, UintUtils.UINT16_MAX));
|
||||
assertEquals(0, UintUtils.diff(-65535, 65537, UintUtils.UINT16_MAX));
|
||||
assertEquals(0, UintUtils.diff(65537, -65535, UintUtils.UINT16_MAX));
|
||||
}
|
||||
|
||||
/* The following tests are the above, but for 32-bit unsigned. */
|
||||
|
||||
assertEquals(0, UintUtils.diff(1, 1, UintUtils.UINT32_MAX));
|
||||
assertEquals(1, UintUtils.diff(2, 1, UintUtils.UINT32_MAX));
|
||||
assertEquals(3, UintUtils.diff(5, 2, UintUtils.UINT32_MAX));
|
||||
assertEquals(4294967295L, UintUtils.diff(1, 2, UintUtils.UINT32_MAX));
|
||||
assertEquals(4294967290L, UintUtils.diff(UintUtils.UINT32_MAX, 5, UintUtils.UINT32_MAX));
|
||||
|
||||
if (false) { /* false means UintUtils.diff() throws if arguments out of range */
|
||||
assertEquals(0, UintUtils.diff(4294967297L, 1, UintUtils.UINT32_MAX));
|
||||
assertEquals(0, UintUtils.diff(1, 4294967297L, UintUtils.UINT32_MAX));
|
||||
assertEquals(0, UintUtils.diff(4294967297L, 4294967297L, UintUtils.UINT32_MAX));
|
||||
assertEquals(0, UintUtils.diff(-4294967295L, 1, UintUtils.UINT32_MAX));
|
||||
assertEquals(0, UintUtils.diff(1, -4294967295L, UintUtils.UINT32_MAX));
|
||||
assertEquals(0, UintUtils.diff(-4294967295L, -4294967295L, UintUtils.UINT32_MAX));
|
||||
assertEquals(0, UintUtils.diff(-4294967295L, 4294967297L, UintUtils.UINT32_MAX));
|
||||
assertEquals(0, UintUtils.diff(65537, -4294967297L, UintUtils.UINT32_MAX));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void realData() {
|
||||
assertEquals(1, UintUtils.diff(381616, 381615, UintUtils.UINT32_MAX));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -765,7 +765,7 @@ public class TrackRecordingServiceTestRecording {
|
||||
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.1, 35.0, 1, 15);
|
||||
|
||||
// then
|
||||
assertEquals(new TrackStatistics(startTime, gps2, 0, 1, 0, 0, 0f, 0f), contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||
assertEquals(new TrackStatistics(startTime, gps2, 11113.275390625, 4, 3, 3704.4251302083335f, 0f, 0f).toString(), contentProviderUtils.getTrack(trackId).getTrackStatistics().toString());
|
||||
|
||||
|
||||
// when
|
||||
@@ -774,8 +774,7 @@ public class TrackRecordingServiceTestRecording {
|
||||
service.endCurrentTrack();
|
||||
|
||||
// then
|
||||
assertEquals(new TrackStatistics(startTime, stopTime, 0, 7, 0, 0, 0f, 0f)
|
||||
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||
assertEquals(new TrackStatistics(startTime, stopTime, 11113.275390625, 10, 3, 3704.4251302083335f, 0f, 0f).toString(), contentProviderUtils.getTrack(trackId).getTrackStatistics().toString());
|
||||
|
||||
|
||||
// then
|
||||
|
||||
+2
-4
@@ -5,8 +5,6 @@ import android.location.Location;
|
||||
|
||||
import androidx.test.rule.ServiceTestRule;
|
||||
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||
|
||||
@@ -16,7 +14,7 @@ public class TrackRecordingServiceTestUtils {
|
||||
//TODO Workaround as service is not stopped on API23; thus sharedpreferences are not reset between tests.
|
||||
//TODO Anyhow, the service should re-create all it's resources if a recording starts and makes sure that there is no leftovers from previous recordings.
|
||||
@Deprecated
|
||||
public static void resetService(ServiceTestRule mServiceRule, Context context) throws TimeoutException {
|
||||
public static void resetService(ServiceTestRule mServiceRule, Context context) {
|
||||
// Let's use default values.
|
||||
PreferencesUtils.clear();
|
||||
}
|
||||
@@ -30,6 +28,6 @@ public class TrackRecordingServiceTestUtils {
|
||||
location.setSpeed(speed);
|
||||
|
||||
trackPointCreator.setClock(time);
|
||||
trackPointCreator.getGpsHandler().onLocationChanged(location);
|
||||
trackPointCreator.getSensorManager().getGpsManager().onLocationChanged(location);
|
||||
}
|
||||
}
|
||||
|
||||
+63
-4
@@ -3,6 +3,7 @@ package de.dennisguse.opentracks.services.announcement;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.content.Context;
|
||||
import android.icu.text.MessageFormat;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
@@ -15,6 +16,7 @@ import org.junit.runner.RunWith;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import de.dennisguse.opentracks.LocaleRule;
|
||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||
@@ -185,12 +187,54 @@ public class VoiceAnnouncementUtilsTest {
|
||||
stats.setTotalAltitudeGain(6000f);
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.IMPERIAL, true, null, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.IMPERIAL_FEET, true, null, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("Total distance 12.4 miles. 1 hour 5 minutes 10 seconds. Average moving speed 11.4 miles per hour.", announcement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAnnouncement_imperial_speed_1() {
|
||||
TrackStatistics stats = new TrackStatistics();
|
||||
stats.setTotalDistance(Distance.ofMile(1.1));
|
||||
stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10));
|
||||
stats.setMovingTime(Duration.ofHours(1));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.IMPERIAL_FEET, true, null, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("Total distance 1.1 miles. 1 hour. Average moving speed 1.1 miles per hour.", announcement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAnnouncement_imperial_meter_speed_1() {
|
||||
TrackStatistics stats = new TrackStatistics();
|
||||
stats.setTotalDistance(Distance.ofMile(1.1));
|
||||
stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10));
|
||||
stats.setMovingTime(Duration.ofHours(1));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.IMPERIAL_METER, true, null, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("Total distance 1.1 miles. 1 hour. Average moving speed 1.1 miles per hour.", announcement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAnnouncement_metric_speed_1() {
|
||||
TrackStatistics stats = new TrackStatistics();
|
||||
stats.setTotalDistance(Distance.ofKilometer(1.1));
|
||||
stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10));
|
||||
stats.setMovingTime(Duration.ofHours(1));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.METRIC, true, null, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("Total distance 1.1 kilometers. 1 hour. Average moving speed 1.1 kilometers per hour.", announcement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAnnouncement_withInterval_imperial_speed() {
|
||||
// given
|
||||
@@ -207,7 +251,7 @@ public class VoiceAnnouncementUtilsTest {
|
||||
}
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.IMPERIAL, true, lastInterval, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.IMPERIAL_FEET, true, lastInterval, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("Total distance 8.8 miles. 16 minutes 39 seconds. Average moving speed 31.8 miles per hour. Lap speed 31.8 miles per hour.", announcement);
|
||||
@@ -223,7 +267,7 @@ public class VoiceAnnouncementUtilsTest {
|
||||
stats.setTotalAltitudeGain(6000f);
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.IMPERIAL, false, null, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.IMPERIAL_FEET, false, null, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("Total distance 12.4 miles. 1 hour 5 minutes 10 seconds. Pace 5 minutes 15 seconds per mile.", announcement);
|
||||
@@ -245,7 +289,7 @@ public class VoiceAnnouncementUtilsTest {
|
||||
}
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.IMPERIAL, false, lastInterval, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.IMPERIAL_FEET, false, lastInterval, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("Total distance 8.8 miles. 16 minutes 39 seconds. Pace 1 minute 53 seconds per mile. Lap time 1 minute 53 seconds per mile.", announcement);
|
||||
@@ -306,4 +350,19 @@ public class VoiceAnnouncementUtilsTest {
|
||||
// then
|
||||
assertEquals(" Current heart rate 133 bpm.", announcement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ICUMessageDemo() {
|
||||
// Android 7's ICU MessageFormat; working
|
||||
String template = """
|
||||
{n, plural,
|
||||
one {1 mile}
|
||||
other {{n,number,#.#} miles}
|
||||
}""";
|
||||
|
||||
assertEquals("1.1 miles", MessageFormat.format(template, Map.of("n", 1.1)));
|
||||
assertEquals("1 mile", MessageFormat.format(template, Map.of("n", 1)));
|
||||
assertEquals("1.1 miles", MessageFormat.format(template, Map.of("n", 1.11)));
|
||||
assertEquals("1.2 miles", MessageFormat.format(template, Map.of("n", 1.18)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
package de.dennisguse.opentracks.services.handlers;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static de.dennisguse.opentracks.services.handlers.GpsStatusValue.GPS_DISABLED;
|
||||
import static de.dennisguse.opentracks.services.handlers.GpsStatusValue.GPS_ENABLED;
|
||||
import static de.dennisguse.opentracks.services.handlers.GpsStatusValue.GPS_NONE;
|
||||
import static de.dennisguse.opentracks.services.handlers.GpsStatusValue.GPS_SIGNAL_BAD;
|
||||
import static de.dennisguse.opentracks.services.handlers.GpsStatusValue.GPS_SIGNAL_FIX;
|
||||
import static de.dennisguse.opentracks.services.handlers.GpsStatusValue.GPS_SIGNAL_LOST;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.Distance;
|
||||
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class GpsStatusTest {
|
||||
|
||||
private final Context context = ApplicationProvider.getApplicationContext();
|
||||
|
||||
@BeforeClass
|
||||
public static void preSetUp() {
|
||||
// Prepare looper for Android's message queue
|
||||
if (Looper.myLooper() == null) Looper.prepare();
|
||||
}
|
||||
|
||||
private final static Location badFix = new Location("gps");
|
||||
private final static Location ok = new Location("gps");
|
||||
|
||||
static {
|
||||
badFix.setAccuracy(50);
|
||||
|
||||
ok.setAccuracy(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartDisabledEnabledStop() {
|
||||
ArrayList<GpsStatusValue> statusList = new ArrayList<>();
|
||||
|
||||
// given
|
||||
GpsStatusManager subject = new GpsStatusManager(context, statusList::add, new Handler());
|
||||
|
||||
// when / then
|
||||
subject.start();
|
||||
assertEquals(List.of(GPS_ENABLED), statusList);
|
||||
|
||||
subject.onGpsDisabled();
|
||||
assertEquals(List.of(GPS_ENABLED, GPS_DISABLED), statusList);
|
||||
|
||||
subject.onGpsEnabled();
|
||||
assertEquals(List.of(GPS_ENABLED, GPS_DISABLED, GPS_ENABLED), statusList);
|
||||
|
||||
subject.stop();
|
||||
assertEquals(List.of(GPS_ENABLED, GPS_DISABLED, GPS_ENABLED, GPS_NONE), statusList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartBadfixOk() {
|
||||
ArrayList<GpsStatusValue> statusList = new ArrayList<>();
|
||||
|
||||
// given
|
||||
GpsStatusManager subject = new GpsStatusManager(context, statusList::add, new Handler());
|
||||
subject.onRecordingDistanceChanged(Distance.of(10));
|
||||
|
||||
// when / then
|
||||
subject.start();
|
||||
subject.onNewTrackPoint(new TrackPoint(badFix, Instant.now()));
|
||||
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_BAD), statusList);
|
||||
|
||||
subject.onNewTrackPoint(new TrackPoint(ok, Instant.now()));
|
||||
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_BAD, GPS_SIGNAL_FIX), statusList);
|
||||
|
||||
subject.onNewTrackPoint(new TrackPoint(ok, Instant.now()));
|
||||
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_BAD, GPS_SIGNAL_FIX), statusList);
|
||||
|
||||
subject.onNewTrackPoint(new TrackPoint(badFix, Instant.now()));
|
||||
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_BAD, GPS_SIGNAL_FIX, GPS_SIGNAL_BAD), statusList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartSignalLost() {
|
||||
ArrayList<GpsStatusValue> statusList = new ArrayList<>();
|
||||
|
||||
// given
|
||||
GpsStatusManager subject = new GpsStatusManager(context, statusList::add, new Handler());
|
||||
subject.onRecordingDistanceChanged(Distance.of(10));
|
||||
subject.onMinRecordingIntervalChanged(GpsStatusManager.SIGNAL_LOST_THRESHOLD.multipliedBy(-1));
|
||||
|
||||
// when / then
|
||||
subject.start();
|
||||
subject.onNewTrackPoint(new TrackPoint(ok, Instant.now().minusMillis(1000)));
|
||||
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_FIX), statusList);
|
||||
|
||||
subject.determineGpsStatusByTime(Instant.now());
|
||||
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_FIX, GPS_SIGNAL_LOST), statusList);
|
||||
|
||||
subject.onNewTrackPoint(new TrackPoint(ok, Instant.now()));
|
||||
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_FIX, GPS_SIGNAL_LOST, GPS_SIGNAL_FIX), statusList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartSignalLostByTimer() throws InterruptedException {
|
||||
ArrayList<GpsStatusValue> statusList = new ArrayList<>();
|
||||
|
||||
final HandlerThread handlerThread = new HandlerThread("solution!");
|
||||
handlerThread.start();
|
||||
|
||||
// given
|
||||
GpsStatusManager subject = new GpsStatusManager(context, statusList::add, new Handler(handlerThread.getLooper()));
|
||||
subject.onRecordingDistanceChanged(Distance.of(10));
|
||||
subject.onMinRecordingIntervalChanged(GpsStatusManager.SIGNAL_LOST_THRESHOLD.multipliedBy(-1).plus(Duration.ofMillis(10)));
|
||||
|
||||
// when / then
|
||||
subject.start();
|
||||
Thread.sleep(100);
|
||||
assertEquals(List.of(GPS_ENABLED), statusList);
|
||||
|
||||
subject.onNewTrackPoint(new TrackPoint(ok, Instant.now()));
|
||||
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_FIX), statusList);
|
||||
|
||||
Thread.sleep(100);
|
||||
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_FIX, GPS_SIGNAL_LOST), statusList);
|
||||
|
||||
subject.onNewTrackPoint(new TrackPoint(badFix, Instant.now()));
|
||||
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_FIX, GPS_SIGNAL_LOST, GPS_SIGNAL_BAD), statusList);
|
||||
|
||||
Thread.sleep(100);
|
||||
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_FIX, GPS_SIGNAL_LOST, GPS_SIGNAL_BAD, GPS_SIGNAL_LOST), statusList);
|
||||
}
|
||||
}
|
||||
-57
@@ -1,57 +0,0 @@
|
||||
package de.dennisguse.opentracks.services.handlers;
|
||||
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.Distance;
|
||||
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class TrackPointCreatorTest {
|
||||
|
||||
@Mock
|
||||
private Context context;
|
||||
|
||||
@Mock
|
||||
private TrackPointCreator.Callback server;
|
||||
|
||||
@Mock
|
||||
private GPSManager locationHandler;
|
||||
|
||||
private TrackPointCreator subject;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
subject = new TrackPointCreator(locationHandler, server);
|
||||
subject.start(context, null);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
subject.stop();
|
||||
}
|
||||
|
||||
@Ignore("ServiceExecutor disabled for #822")
|
||||
@Test
|
||||
public void sendTrackPoint() throws InterruptedException {
|
||||
// given
|
||||
TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, null);
|
||||
Distance horizontalAccuracyThreshold = Distance.of(50);
|
||||
|
||||
// when
|
||||
subject.onNewTrackPoint(trackPoint);
|
||||
|
||||
// then
|
||||
Thread.sleep(10); // Wait for executor service
|
||||
verify(server).newTrackPoint(trackPoint, horizontalAccuracyThreshold);
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ public class DescriptionGeneratorTest {
|
||||
stats.setTotalAltitudeLoss(6000f);
|
||||
stats.setStartTime(START_TIME);
|
||||
track.setTrackStatistics(stats);
|
||||
track.setCategory("hiking");
|
||||
track.setActivityTypeLocalized("hiking");
|
||||
String expected = //"Created by"
|
||||
"<a href='https://github.com/OpenTracksApp/OpenTracks'>OpenTracks (Debug)</a><p>"
|
||||
+ "Name: -<br>"
|
||||
@@ -118,7 +118,7 @@ public class DescriptionGeneratorTest {
|
||||
stats.setTotalAltitudeLoss(6000f);
|
||||
stats.setStartTime(START_TIME);
|
||||
track.setTrackStatistics(stats);
|
||||
track.setCategory("hiking");
|
||||
track.setActivityTypeLocalized("hiking");
|
||||
String expected = //"Created by"
|
||||
"<a href='https://github.com/OpenTracksApp/OpenTracks'>OpenTracks (Debug)</a><p>"
|
||||
+ "Name: -<br>"
|
||||
|
||||
+6
-26
@@ -5,7 +5,6 @@ import static org.junit.Assert.assertNull;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -78,13 +77,13 @@ public class TrackStatisticsUpdaterTest {
|
||||
|
||||
// when
|
||||
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
|
||||
data.trackPoints.forEach(subject::addTrackPoint);
|
||||
data.trackPoints().forEach(subject::addTrackPoint);
|
||||
|
||||
// then
|
||||
TrackStatistics statistics = subject.getTrackStatistics();
|
||||
assertEquals(128.03, statistics.getTotalDistance().toM(), 0.01);
|
||||
assertEquals(Duration.ofSeconds(13), statistics.getTotalTime());
|
||||
assertEquals(Duration.ofSeconds(9), statistics.getMovingTime());
|
||||
assertEquals(142.26, statistics.getTotalDistance().toM(), 0.01);
|
||||
assertEquals(Duration.ofSeconds(14), statistics.getTotalTime());
|
||||
assertEquals(Duration.ofSeconds(10), statistics.getMovingTime());
|
||||
|
||||
assertEquals(2.5, statistics.getMinAltitude(), 0.01);
|
||||
assertEquals(32.5, statistics.getMaxAltitude(), 0.01);
|
||||
@@ -93,8 +92,8 @@ public class TrackStatisticsUpdaterTest {
|
||||
|
||||
assertEquals(14.226, statistics.getMaxSpeed().toMPS(), 0.01);
|
||||
assertEquals(14.226, statistics.getAverageMovingSpeed().toMPS(), 0.01);
|
||||
assertEquals(9.84, statistics.getAverageSpeed().toMPS(), 0.01);
|
||||
assertEquals(106.85f, statistics.getAverageHeartRate().getBPM(), 0.01);
|
||||
assertEquals(10.16, statistics.getAverageSpeed().toMPS(), 0.01);
|
||||
assertEquals(106.64f, statistics.getAverageHeartRate().getBPM(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -226,25 +225,6 @@ public class TrackStatisticsUpdaterTest {
|
||||
assertEquals(59.18, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
|
||||
}
|
||||
|
||||
@Ignore("TODO: create a concept ont to compute speed from GPS and sensor")
|
||||
@Test
|
||||
public void addTrackPoint_speed_from_GPS_not_moving() {
|
||||
}
|
||||
|
||||
@Ignore("TODO: create a concept ont to compute speed from GPS and sensor")
|
||||
@Test
|
||||
public void addTrackPoint_speed_from_GPS_moving() {
|
||||
}
|
||||
|
||||
@Ignore("TODO: create a concept ont to compute speed from GPS and sensor")
|
||||
@Test
|
||||
public void addTrackPoint_speed_from_GPS_not_moving_and_sensor_speed() {
|
||||
}
|
||||
|
||||
@Ignore("TODO: create a concept ont to compute speed from GPS and sensor")
|
||||
@Test
|
||||
public void addTrackPoint_speed_from_GPS_moving_and_sensor_speed() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addTrackPoint_maxSpeed_ignore_above_acceleration() {
|
||||
|
||||
+6
-6
@@ -16,18 +16,18 @@ import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.data.models.ActivityType;
|
||||
import de.dennisguse.opentracks.data.models.Distance;
|
||||
import de.dennisguse.opentracks.data.models.Speed;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class AggregatedStatisticsTest {
|
||||
|
||||
private final Context context = ApplicationProvider.getApplicationContext();
|
||||
|
||||
private static Track createTrack(Context context, Distance totalDistance, Duration totalTime, String category) {
|
||||
private static Track createTrack(Context context, Distance totalDistance, Duration totalTime, String activityTypeLocalized) {
|
||||
TrackStatistics statistics = new TrackStatistics();
|
||||
statistics.setStartTime(Instant.ofEpochMilli(1000L)); // Resulting start time
|
||||
statistics.setStopTime(statistics.getStartTime().plus(totalTime));
|
||||
@@ -40,8 +40,8 @@ public class AggregatedStatisticsTest {
|
||||
statistics.setMinAltitude(1200.0); // Resulting min altitude
|
||||
|
||||
Track track = new Track();
|
||||
track.setIcon(TrackIconUtils.getIconValue(context, category));
|
||||
track.setCategory(category);
|
||||
track.setActivityType(ActivityType.findByLocalizedString(context, activityTypeLocalized));
|
||||
track.setActivityTypeLocalized(activityTypeLocalized);
|
||||
track.setTrackStatistics(statistics);
|
||||
return track;
|
||||
}
|
||||
@@ -243,8 +243,8 @@ public class AggregatedStatisticsTest {
|
||||
// Check order
|
||||
|
||||
{
|
||||
assertEquals(biking, aggregatedStatistics.getItem(0).getCategory());
|
||||
assertEquals(driving, aggregatedStatistics.getItem(3).getCategory());
|
||||
assertEquals(biking, aggregatedStatistics.getItem(0).getActivityTypeLocalized());
|
||||
assertEquals(driving, aggregatedStatistics.getItem(3).getActivityTypeLocalized());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -51,7 +51,7 @@ public class EspressoAggregatedFilterTest {
|
||||
@Before
|
||||
public void setUp() {
|
||||
Pair<Track, List<TrackPoint>> pair = TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), 20);
|
||||
pair.first.setCategory(CATEGORY);
|
||||
pair.first.setActivityTypeLocalized(CATEGORY);
|
||||
TestDataUtil.insertTrackWithLocations(new ContentProviderUtils(ApplicationProvider.getApplicationContext()), pair.first, pair.second);
|
||||
}
|
||||
|
||||
@@ -59,8 +59,8 @@ public class EspressoAggregatedFilterTest {
|
||||
public void espressoAggregatedFilterTest() {
|
||||
// open AggregatedStatisticsActivity through toolbar's menu item
|
||||
onView(ViewMatchers.withId(R.id.bottom_app_bar)).check(matches(isDisplayed()));
|
||||
onView(withId(R.id.bottom_app_bar)).check(matches(hasDescendant(withId(R.id.track_list_aggregated_stats))));
|
||||
onView(withId(R.id.track_list_aggregated_stats)).perform(click());
|
||||
onView(withId(R.id.bottom_app_bar)).check(matches(hasDescendant(withId(R.id.aggregated_stats_button))));
|
||||
onView(withId(R.id.aggregated_stats_button)).perform(click());
|
||||
|
||||
// open FilterDialogFragment through toolbar's menu item
|
||||
onView(withId(R.id.bottom_app_bar)).check(matches(isDisplayed()));
|
||||
|
||||
@@ -79,7 +79,7 @@ public class EGM2008UtilsTest {
|
||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
||||
|
||||
// then
|
||||
assertEquals(-14.8980, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
|
||||
assertEquals(-14.8980, altitude_egm2008.correctAltitude(trackPoint.getLocation()).toM(), MAX_BILINEAR_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -94,7 +94,7 @@ public class EGM2008UtilsTest {
|
||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
||||
|
||||
// then
|
||||
assertEquals(30.15, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
|
||||
assertEquals(30.15, altitude_egm2008.correctAltitude(trackPoint.getLocation()).toM(), MAX_BILINEAR_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -109,7 +109,7 @@ public class EGM2008UtilsTest {
|
||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
||||
|
||||
// then
|
||||
assertEquals(30.15, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
|
||||
assertEquals(30.15, altitude_egm2008.correctAltitude(trackPoint.getLocation()).toM(), MAX_BILINEAR_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -124,7 +124,7 @@ public class EGM2008UtilsTest {
|
||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
||||
|
||||
// then
|
||||
assertEquals(30.15, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
|
||||
assertEquals(30.15, altitude_egm2008.correctAltitude(trackPoint.getLocation()).toM(), MAX_BILINEAR_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -139,7 +139,7 @@ public class EGM2008UtilsTest {
|
||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
||||
|
||||
// then
|
||||
assertEquals(-17.2260, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
|
||||
assertEquals(-17.2260, altitude_egm2008.correctAltitude(trackPoint.getLocation()).toM(), MAX_BILINEAR_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -154,7 +154,7 @@ public class EGM2008UtilsTest {
|
||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
||||
|
||||
// then
|
||||
assertEquals(-39.4865, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
|
||||
assertEquals(-39.4865, altitude_egm2008.correctAltitude(trackPoint.getLocation()).toM(), MAX_BILINEAR_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -174,7 +174,7 @@ public class EGM2008UtilsTest {
|
||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint1.getLocation());
|
||||
|
||||
// then
|
||||
assertNotEquals(altitude_egm2008.correctAltitude(trackPoint1.getLocation()), altitude_egm2008.correctAltitude(trackPoint2.getLocation()), 0.0001);
|
||||
assertNotEquals(altitude_egm2008.correctAltitude(trackPoint1.getLocation()).toM(), altitude_egm2008.correctAltitude(trackPoint2.getLocation()).toM(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -190,7 +190,7 @@ public class EGM2008UtilsTest {
|
||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
||||
|
||||
// then
|
||||
assertEquals(22.99, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
|
||||
assertEquals(22.99, altitude_egm2008.correctAltitude(trackPoint.getLocation()).toM(), MAX_BILINEAR_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -205,7 +205,7 @@ public class EGM2008UtilsTest {
|
||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
||||
|
||||
// then
|
||||
assertEquals(-85.824, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
|
||||
assertEquals(-85.824, altitude_egm2008.correctAltitude(trackPoint.getLocation()).toM(), MAX_BILINEAR_ERROR);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -17,11 +17,14 @@ package de.dennisguse.opentracks.util;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
@@ -37,7 +40,7 @@ public class FileUtilsTest {
|
||||
*/
|
||||
@Test
|
||||
public void testBuildUniqueFileName_new() {
|
||||
String filename = FileUtils.buildUniqueFileName(new File("/dir"), "Filename", "ext");
|
||||
String filename = FileUtils.buildUniqueFileName(FileUtils.getPhotoDir(ApplicationProvider.getApplicationContext()), "Filename", "ext");
|
||||
assertEquals("Filename.ext", filename);
|
||||
}
|
||||
|
||||
@@ -45,9 +48,14 @@ public class FileUtilsTest {
|
||||
* Tests {@link FileUtils#buildUniqueFileName(File, String, String)} when the file exists already.
|
||||
*/
|
||||
@Test
|
||||
public void testBuildUniqueFileName_exist() {
|
||||
// Expect "/default.prop" to exist on the phone/emulator
|
||||
String filename = FileUtils.buildUniqueFileName(new File("/"), "default", "prop");
|
||||
public void testBuildUniqueFileName_exist() throws IOException {
|
||||
// given
|
||||
new File(FileUtils.getPhotoDir(ApplicationProvider.getApplicationContext()), "default.prop").createNewFile();
|
||||
|
||||
//when
|
||||
String filename = FileUtils.buildUniqueFileName(FileUtils.getPhotoDir(ApplicationProvider.getApplicationContext()), "default", "prop");
|
||||
|
||||
// then
|
||||
assertEquals("default(1).prop", filename);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<shortcut
|
||||
android:enabled="true"
|
||||
android:icon="@drawable/ic_statistics_24dp"
|
||||
android:shortcutId="stats"
|
||||
android:shortcutLongLabel="@string/menu_aggregated_statistics"
|
||||
android:shortcutShortLabel="@string/menu_aggregated_statistics">
|
||||
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:targetClass="de.dennisguse.opentracks.ui.aggregatedStatistics.AggregatedStatisticsActivity"
|
||||
android:targetPackage="de.dennisguse.opentracks.debug" />
|
||||
</shortcut>
|
||||
</shortcuts>
|
||||
@@ -89,6 +89,7 @@ limitations under the License.
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- NOTE: the name of the MAIN/LAUNCHER is used by icon packs; if this is changed, icon packs break.-->
|
||||
<activity
|
||||
android:name=".introduction.IntroductionActivity"
|
||||
android:exported="true"
|
||||
@@ -98,6 +99,11 @@ limitations under the License.
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.app.shortcuts"
|
||||
android:resource="@xml/shortcuts"
|
||||
/>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".AboutActivity" />
|
||||
@@ -348,6 +354,7 @@ limitations under the License.
|
||||
<activity android:name=".ui.aggregatedStatistics.AggregatedStatisticsActivity" />
|
||||
|
||||
<activity android:name=".io.file.importer.DirectoryChooserActivity$ExportDirectoryChooserActivity" />
|
||||
<activity android:name=".io.file.importer.DirectoryChooserActivity$ExportDirectoryChooserOneFileActivity" />
|
||||
<activity android:name=".io.file.importer.DirectoryChooserActivity$DefaultTrackExportDirectoryChooserActivity" />
|
||||
|
||||
<activity android:name=".io.file.exporter.ExportActivity" />
|
||||
|
||||
@@ -24,7 +24,7 @@ public class ShowErrorActivity extends AbstractActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
viewBinding.textViewError.setText(getIntent().getStringExtra(EXTRA_ERROR_TEXT));
|
||||
viewBinding.bottomAppBarLayout.bottomAppBarTitle.setText(createErrorTitle());
|
||||
viewBinding.showErrorToolbar.setTitle(createErrorTitle());
|
||||
setSupportActionBar(viewBinding.bottomAppBarLayout.bottomAppBar);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.databinding.TrackEditBinding;
|
||||
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
|
||||
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
||||
import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||
import de.dennisguse.opentracks.util.TrackUtils;
|
||||
|
||||
/**
|
||||
@@ -48,7 +47,7 @@ public class TrackEditActivity extends AbstractActivity implements ChooseActivit
|
||||
private TrackRecordingServiceConnection trackRecordingServiceConnection;
|
||||
private ContentProviderUtils contentProviderUtils;
|
||||
private Track track;
|
||||
private String iconValue;
|
||||
private ActivityType activityType;
|
||||
|
||||
private TrackEditBinding viewBinding;
|
||||
|
||||
@@ -74,28 +73,31 @@ public class TrackEditActivity extends AbstractActivity implements ChooseActivit
|
||||
|
||||
viewBinding.fields.trackEditName.setText(track.getName());
|
||||
|
||||
viewBinding.fields.trackEditActivityType.setText(track.getCategory());
|
||||
viewBinding.fields.trackEditActivityType.setText(track.getActivityTypeLocalized());
|
||||
|
||||
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, ActivityType.getLocalizedStrings(this));
|
||||
viewBinding.fields.trackEditActivityType.setAdapter(adapter);
|
||||
viewBinding.fields.trackEditActivityType.setOnItemClickListener((parent, view, position, id) -> setActivityTypeIcon(TrackIconUtils.getIconValue(this, (String) viewBinding.fields.trackEditActivityType.getAdapter().getItem(position))));
|
||||
viewBinding.fields.trackEditActivityType.setOnItemClickListener((parent, view, position, id) -> {
|
||||
String localizedActivityType = (String) viewBinding.fields.trackEditActivityType.getAdapter().getItem(position);
|
||||
setActivityTypeIcon(ActivityType.findByLocalizedString(this, localizedActivityType));
|
||||
});
|
||||
viewBinding.fields.trackEditActivityType.setOnFocusChangeListener((v, hasFocus) -> {
|
||||
if (!hasFocus) {
|
||||
setActivityTypeIcon(TrackIconUtils.getIconValue(
|
||||
TrackEditActivity.this, viewBinding.fields.trackEditActivityType.getText().toString()));
|
||||
String localizedActivityType = viewBinding.fields.trackEditActivityType.getText().toString();
|
||||
setActivityTypeIcon(ActivityType.findByLocalizedString(this, localizedActivityType));
|
||||
}
|
||||
});
|
||||
|
||||
iconValue = null;
|
||||
activityType = null;
|
||||
if (bundle != null) {
|
||||
iconValue = bundle.getString(ICON_VALUE_KEY);
|
||||
activityType = (ActivityType) bundle.getSerializable(ICON_VALUE_KEY);
|
||||
}
|
||||
if (iconValue == null) {
|
||||
iconValue = track.getIcon();
|
||||
if (activityType == null) {
|
||||
activityType = track.getActivityType();
|
||||
}
|
||||
|
||||
setActivityTypeIcon(iconValue);
|
||||
viewBinding.fields.trackEditActivityTypeIcon.setOnClickListener(v -> ChooseActivityTypeDialogFragment.showDialog(getSupportFragmentManager(), viewBinding.fields.trackEditActivityType.getText().toString()));
|
||||
setActivityTypeIcon(activityType);
|
||||
viewBinding.fields.trackEditActivityTypeIcon.setOnClickListener(v -> ChooseActivityTypeDialogFragment.showDialog(getSupportFragmentManager(), this, viewBinding.fields.trackEditActivityType.getText().toString()));
|
||||
|
||||
viewBinding.fields.trackEditDescription.setText(track.getDescription());
|
||||
|
||||
@@ -109,7 +111,6 @@ public class TrackEditActivity extends AbstractActivity implements ChooseActivit
|
||||
viewBinding.trackEditCancel.setOnClickListener(v -> finish());
|
||||
viewBinding.trackEditCancel.setVisibility(View.VISIBLE);
|
||||
|
||||
viewBinding.bottomAppBarLayout.bottomAppBarTitle.setText(getString(R.string.menu_edit));
|
||||
setSupportActionBar(viewBinding.bottomAppBarLayout.bottomAppBar);
|
||||
}
|
||||
|
||||
@@ -128,7 +129,7 @@ public class TrackEditActivity extends AbstractActivity implements ChooseActivit
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putString(ICON_VALUE_KEY, iconValue);
|
||||
outState.putSerializable(ICON_VALUE_KEY, activityType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -137,14 +138,14 @@ public class TrackEditActivity extends AbstractActivity implements ChooseActivit
|
||||
return viewBinding.getRoot();
|
||||
}
|
||||
|
||||
private void setActivityTypeIcon(String iconValue) {
|
||||
this.iconValue = iconValue;
|
||||
viewBinding.fields.trackEditActivityTypeIcon.setImageResource(TrackIconUtils.getIconDrawable(iconValue));
|
||||
private void setActivityTypeIcon(ActivityType activityType) {
|
||||
this.activityType = activityType;
|
||||
viewBinding.fields.trackEditActivityTypeIcon.setImageResource(activityType.getIconDrawableId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChooseActivityTypeDone(String value) {
|
||||
setActivityTypeIcon(value);
|
||||
viewBinding.fields.trackEditActivityType.setText(getString(TrackIconUtils.getIconActivityType(value)));
|
||||
public void onChooseActivityTypeDone(ActivityType activityType) {
|
||||
setActivityTypeIcon(activityType);
|
||||
viewBinding.fields.trackEditActivityType.setText(getString(activityType.getLocalizedStringId()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import android.database.Cursor;
|
||||
import android.graphics.drawable.AnimatedVectorDrawable;
|
||||
import android.location.LocationManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Vibrator;
|
||||
import android.provider.Settings;
|
||||
import android.util.Pair;
|
||||
import android.view.KeyEvent;
|
||||
@@ -36,6 +35,7 @@ import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.cursoradapter.widget.ResourceCursorAdapter;
|
||||
@@ -43,6 +43,8 @@ import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.CursorLoader;
|
||||
import androidx.loader.content.Loader;
|
||||
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
@@ -50,6 +52,7 @@ import java.time.ZoneOffset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.ActivityType;
|
||||
import de.dennisguse.opentracks.data.models.Distance;
|
||||
import de.dennisguse.opentracks.data.models.DistanceFormatter;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
@@ -72,7 +75,6 @@ import de.dennisguse.opentracks.util.IntentDashboardUtils;
|
||||
import de.dennisguse.opentracks.util.IntentUtils;
|
||||
import de.dennisguse.opentracks.util.PermissionRequester;
|
||||
import de.dennisguse.opentracks.util.StringUtils;
|
||||
import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||
|
||||
/**
|
||||
* An activity displaying a list of tracks.
|
||||
@@ -83,7 +85,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
||||
|
||||
private static final String TAG = TrackListActivity.class.getSimpleName();
|
||||
|
||||
// The following are setFrequency in onCreate
|
||||
// The following are set in onCreate
|
||||
private TrackRecordingServiceConnection trackRecordingServiceConnection;
|
||||
private ResourceCursorAdapter resourceCursorAdapter;
|
||||
|
||||
@@ -137,7 +139,6 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
||||
|
||||
// Menu items
|
||||
private MenuItem searchMenuItem;
|
||||
private MenuItem startGpsMenuItem;
|
||||
|
||||
private final TrackRecordingServiceConnection.Callback bindChangedCallback = (service, unused) -> {
|
||||
service.getRecordingStatusObservable()
|
||||
@@ -165,6 +166,25 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
||||
|
||||
trackRecordingServiceConnection = new TrackRecordingServiceConnection(bindChangedCallback);
|
||||
|
||||
viewBinding.aggregatedStatsButton.setOnClickListener((view) -> startActivity(IntentUtils.newIntent(this, AggregatedStatisticsActivity.class)));
|
||||
viewBinding.sensorStartButton.setOnClickListener((view) -> {
|
||||
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
|
||||
if (locationManager != null && !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
|
||||
startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
|
||||
} else {
|
||||
// Invoke trackRecordingService
|
||||
if (!gpsStatusValue.isGpsStarted()) {
|
||||
trackRecordingServiceConnection.startAndBindWithCallback(this);
|
||||
} else {
|
||||
TrackRecordingService trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
|
||||
if (trackRecordingService != null) {
|
||||
trackRecordingService.stopSensorsAndShutdown(); //TODO Handle this in TrackRecordingServiceConnection
|
||||
}
|
||||
trackRecordingServiceConnection.unbindAndStop(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
viewBinding.trackList.setEmptyView(viewBinding.trackListEmptyView);
|
||||
viewBinding.trackList.setOnItemClickListener((parent, view, position, trackIdId) -> {
|
||||
Track.Id trackId = new Track.Id(trackIdId);
|
||||
@@ -194,14 +214,15 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
||||
int totalDistanceIndex = cursor.getColumnIndexOrThrow(TracksColumns.TOTALDISTANCE);
|
||||
int startTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.STARTTIME);
|
||||
int startTimeOffsetIndex = cursor.getColumnIndexOrThrow(TracksColumns.STARTTIME_OFFSET);
|
||||
int categoryIndex = cursor.getColumnIndexOrThrow(TracksColumns.CATEGORY);
|
||||
int activityTypeIndex = cursor.getColumnIndexOrThrow(TracksColumns.ACTIVITY_TYPE_LOCALIZED);
|
||||
int descriptionIndex = cursor.getColumnIndexOrThrow(TracksColumns.DESCRIPTION);
|
||||
int markerCountIndex = cursor.getColumnIndexOrThrow(TracksColumns.MARKER_COUNT);
|
||||
|
||||
Track.Id trackId = new Track.Id(cursor.getLong(idIndex));
|
||||
boolean isRecording = trackId.equals(recordingStatus.getTrackId());
|
||||
String icon = cursor.getString(iconIndex);
|
||||
int iconId = TrackIconUtils.getIconDrawable(icon);
|
||||
int iconId = ActivityType.findBy(icon)
|
||||
.getIconDrawableId();
|
||||
String name = cursor.getString(nameIndex);
|
||||
String totalTime = StringUtils.formatElapsedTime(Duration.ofMillis(cursor.getLong(totalTimeIndex)));
|
||||
String totalDistance = DistanceFormatter.Builder()
|
||||
@@ -210,13 +231,13 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
||||
int markerCount = cursor.getInt(markerCountIndex);
|
||||
long startTime = cursor.getLong(startTimeIndex);
|
||||
int startTimeOffset = cursor.getInt(startTimeOffsetIndex);
|
||||
String category = icon != null && !icon.equals("") ? null : cursor.getString(categoryIndex);
|
||||
String activityType = icon != null && !icon.equals("") ? null : cursor.getString(activityTypeIndex);
|
||||
String description = cursor.getString(descriptionIndex);
|
||||
|
||||
ListItemUtils.setListItem(TrackListActivity.this, view, isRecording,
|
||||
iconId, R.string.image_track, name, totalTime, totalDistance, markerCount,
|
||||
OffsetDateTime.ofInstant(Instant.ofEpochMilli(startTime), ZoneOffset.ofTotalSeconds(startTimeOffset)),
|
||||
category, description, false);
|
||||
activityType, description, false);
|
||||
}
|
||||
};
|
||||
viewBinding.trackList.setAdapter(resourceCursorAdapter);
|
||||
@@ -246,7 +267,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
||||
}
|
||||
|
||||
// Recording -> Stop
|
||||
((Vibrator) getSystemService(Context.VIBRATOR_SERVICE)).vibrate(1000);
|
||||
ActivityUtils.vibrate(this, 1000);
|
||||
updateGpsMenuItem(false, false);
|
||||
trackRecordingServiceConnection.stopRecording(TrackListActivity.this);
|
||||
viewBinding.trackListFabAction.setImageResource(R.drawable.ic_baseline_record_24);
|
||||
@@ -254,7 +275,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
||||
return true;
|
||||
});
|
||||
|
||||
setSupportActionBar(viewBinding.bottomAppBar);
|
||||
setSupportActionBar(viewBinding.trackListToolbar);
|
||||
|
||||
loadData(getIntent());
|
||||
}
|
||||
@@ -309,21 +330,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
||||
getMenuInflater().inflate(R.menu.track_list, menu);
|
||||
|
||||
searchMenuItem = menu.findItem(R.id.track_list_search);
|
||||
SearchView searchView = ActivityUtils.configureSearchWidget(this, searchMenuItem);
|
||||
|
||||
searchView.findViewById(androidx.appcompat.R.id.search_edit_frame).setPadding(0, 0, 48, 0);
|
||||
|
||||
SearchView.SearchAutoComplete searchAutoComplete = searchView.findViewById(androidx.appcompat.R.id.search_src_text);
|
||||
searchAutoComplete.setHintTextColor(ContextCompat.getColor(this, android.R.color.white));
|
||||
searchAutoComplete.setTextColor(ContextCompat.getColor(this, android.R.color.white));
|
||||
|
||||
searchView.setOnCloseListener(() -> {
|
||||
searchView.clearFocus();
|
||||
searchMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||
return true;
|
||||
});
|
||||
|
||||
startGpsMenuItem = menu.findItem(R.id.track_list_start_gps);
|
||||
ActivityUtils.configureSearchWidget(this, searchMenuItem);
|
||||
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
@@ -340,34 +347,6 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == R.id.track_list_start_gps) {
|
||||
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
|
||||
if (locationManager != null && !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
|
||||
startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
|
||||
} else {
|
||||
// Invoke trackRecordingService
|
||||
if (!gpsStatusValue.isGpsStarted()) {
|
||||
trackRecordingServiceConnection.startAndBindWithCallback(this);
|
||||
} else {
|
||||
TrackRecordingService trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
|
||||
if (trackRecordingService != null) {
|
||||
trackRecordingService.stopSensorsAndShutdown(); //TODO Handle this in TrackRecordingServiceConnection
|
||||
}
|
||||
trackRecordingServiceConnection.unbindAndStop(this);
|
||||
}
|
||||
|
||||
// Update menu after starting or stopping gps
|
||||
this.invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item.getItemId() == R.id.track_list_aggregated_stats) {
|
||||
startActivity(IntentUtils.newIntent(this, AggregatedStatisticsActivity.class));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item.getItemId() == R.id.track_list_markers) {
|
||||
startActivity(IntentUtils.newIntent(this, MarkerListActivity.class));
|
||||
return true;
|
||||
@@ -382,6 +361,12 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
||||
SearchView searchView = (SearchView) searchMenuItem.getActionView();
|
||||
searchView.setIconified(false);
|
||||
searchMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item.getItemId() == R.id.track_list_help) {
|
||||
startActivity(IntentUtils.newIntent(this, HelpActivity.class));
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
@@ -455,14 +440,12 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
||||
*/
|
||||
//TODO Check if if can be avoided to call this outside of onGpsStatusChanged()
|
||||
private void updateGpsMenuItem(boolean isGpsStarted, boolean isRecording) {
|
||||
if (startGpsMenuItem != null) {
|
||||
startGpsMenuItem.setVisible(!isRecording);
|
||||
if (!isRecording) {
|
||||
startGpsMenuItem.setTitle(isGpsStarted ? R.string.menu_stop_gps : R.string.menu_start_gps);
|
||||
startGpsMenuItem.setIcon(isGpsStarted ? gpsStatusValue.icon : R.drawable.ic_gps_off_24dp);
|
||||
if (startGpsMenuItem.getIcon() instanceof AnimatedVectorDrawable) {
|
||||
((AnimatedVectorDrawable) startGpsMenuItem.getIcon()).start();
|
||||
}
|
||||
MaterialButton startGpsMenuItem = viewBinding.sensorStartButton;
|
||||
startGpsMenuItem.setVisibility(!isRecording ? View.VISIBLE : View.INVISIBLE);
|
||||
if (!isRecording) {
|
||||
startGpsMenuItem.setIcon(AppCompatResources.getDrawable(this, isGpsStarted ? gpsStatusValue.icon : R.drawable.ic_gps_off_24dp));
|
||||
if (startGpsMenuItem.getIcon() instanceof AnimatedVectorDrawable) {
|
||||
((AnimatedVectorDrawable) startGpsMenuItem.getIcon()).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -532,11 +515,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
||||
public void setSearch(String searchQuery) {
|
||||
this.searchQuery = searchQuery;
|
||||
restart();
|
||||
if (searchQuery != null) {
|
||||
setTitle(searchQuery);
|
||||
} else {
|
||||
setTitle(R.string.app_name);
|
||||
}
|
||||
viewBinding.trackListToolbar.setTitle(searchQuery == null ? getString(R.string.app_name) : searchQuery);
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
@@ -547,7 +526,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
|
||||
final String[] PROJECTION = new String[]{TracksColumns._ID, TracksColumns.NAME,
|
||||
TracksColumns.DESCRIPTION, TracksColumns.CATEGORY, TracksColumns.STARTTIME, TracksColumns.STARTTIME_OFFSET,
|
||||
TracksColumns.DESCRIPTION, TracksColumns.ACTIVITY_TYPE_LOCALIZED, TracksColumns.STARTTIME, TracksColumns.STARTTIME_OFFSET,
|
||||
TracksColumns.TOTALDISTANCE, TracksColumns.TOTALTIME, TracksColumns.ICON, TracksColumns.MARKER_COUNT};
|
||||
|
||||
final String sortOrder = TracksColumns.STARTTIME + " DESC";
|
||||
@@ -557,7 +536,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
||||
} else {
|
||||
final String SEARCH_QUERY = TracksColumns.NAME + " LIKE ? OR " +
|
||||
TracksColumns.DESCRIPTION + " LIKE ? OR " +
|
||||
TracksColumns.CATEGORY + " LIKE ?";
|
||||
TracksColumns.ACTIVITY_TYPE_LOCALIZED + " LIKE ?";
|
||||
final String[] selectionArgs = new String[]{"%" + searchQuery + "%", "%" + searchQuery + "%", "%" + searchQuery + "%"};
|
||||
return new CursorLoader(TrackListActivity.this, TracksColumns.CONTENT_URI, PROJECTION, SEARCH_QUERY, selectionArgs, sortOrder);
|
||||
}
|
||||
@@ -581,7 +560,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
||||
|
||||
private void setFloatButton() {
|
||||
viewBinding.trackListFabAction.setImageResource(recordingStatus.isRecording() ? R.drawable.ic_baseline_stop_24 : R.drawable.ic_baseline_record_24);
|
||||
viewBinding.trackListFabAction.setBackgroundTintList(ContextCompat.getColorStateList(this, recordingStatus.isRecording() ? R.color.opentracks_secondary_color : R.color.red_dark));
|
||||
viewBinding.trackListFabAction.setBackgroundTintList(ContextCompat.getColorStateList(this, recordingStatus.isRecording() ? R.color.opentracks : R.color.red_dark));
|
||||
}
|
||||
|
||||
private void onRecordingStatusChanged(RecordingStatus status) {
|
||||
|
||||
@@ -103,7 +103,6 @@ public class TrackRecordedActivity extends AbstractTrackDeleteActivity implement
|
||||
trackRecordingServiceConnection = new TrackRecordingServiceConnection(bindCallback);
|
||||
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
viewBinding.bottomAppBarLayout.bottomAppBarTitle.setText(track != null ? track.getName() : "");
|
||||
viewBinding.bottomAppBarLayout.bottomAppBar.replaceMenu(R.menu.track_detail);
|
||||
setSupportActionBar(viewBinding.bottomAppBarLayout.bottomAppBar);
|
||||
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package de.dennisguse.opentracks;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Vibrator;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
@@ -32,6 +30,7 @@ import de.dennisguse.opentracks.chart.ChartFragment;
|
||||
import de.dennisguse.opentracks.chart.TrackDataHubInterface;
|
||||
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.data.TrackDataHub;
|
||||
import de.dennisguse.opentracks.data.models.ActivityType;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.databinding.TrackRecordingBinding;
|
||||
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
|
||||
@@ -45,9 +44,9 @@ import de.dennisguse.opentracks.settings.SettingsActivity;
|
||||
import de.dennisguse.opentracks.ui.intervals.IntervalsFragment;
|
||||
import de.dennisguse.opentracks.ui.markers.MarkerEditActivity;
|
||||
import de.dennisguse.opentracks.ui.markers.MarkerListActivity;
|
||||
import de.dennisguse.opentracks.ui.util.ActivityUtils;
|
||||
import de.dennisguse.opentracks.util.IntentDashboardUtils;
|
||||
import de.dennisguse.opentracks.util.IntentUtils;
|
||||
import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||
import de.dennisguse.opentracks.util.TrackUtils;
|
||||
|
||||
/**
|
||||
@@ -134,10 +133,10 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
||||
}
|
||||
|
||||
viewBinding.trackRecordingFabAction.setImageResource(R.drawable.ic_baseline_stop_24);
|
||||
viewBinding.trackRecordingFabAction.setBackgroundTintList(ContextCompat.getColorStateList(this, R.color.opentracks_secondary_color));
|
||||
viewBinding.trackRecordingFabAction.setBackgroundColor(ContextCompat.getColor(this, R.color.opentracks_secondary_color));
|
||||
viewBinding.trackRecordingFabAction.setBackgroundTintList(ContextCompat.getColorStateList(this, R.color.opentracks));
|
||||
viewBinding.trackRecordingFabAction.setBackgroundColor(ContextCompat.getColor(this, R.color.opentracks));
|
||||
viewBinding.trackRecordingFabAction.setOnLongClickListener((view) -> {
|
||||
((Vibrator) getSystemService(Context.VIBRATOR_SERVICE)).vibrate(1000);
|
||||
ActivityUtils.vibrate(this, 1000);
|
||||
trackRecordingServiceConnection.stopRecording(TrackRecordingActivity.this);
|
||||
Intent newIntent = IntentUtils.newIntent(TrackRecordingActivity.this, TrackStoppedActivity.class)
|
||||
.putExtra(TrackStoppedActivity.EXTRA_TRACK_ID, trackId);
|
||||
@@ -318,10 +317,10 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChooseActivityTypeDone(String iconValue) {
|
||||
public void onChooseActivityTypeDone(ActivityType activityType) {
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
String category = getString(TrackIconUtils.getIconActivityType(iconValue));
|
||||
TrackUtils.updateTrack(this, track, null, category, null, contentProviderUtils);
|
||||
String activityTypeLocalized = getString(activityType.getLocalizedStringId());
|
||||
TrackUtils.updateTrack(this, track, null, activityTypeLocalized, null, contentProviderUtils);
|
||||
}
|
||||
|
||||
private class CustomFragmentPagerAdapter extends FragmentStateAdapter {
|
||||
|
||||
@@ -20,7 +20,6 @@ import de.dennisguse.opentracks.ui.aggregatedStatistics.ConfirmDeleteDialogFragm
|
||||
import de.dennisguse.opentracks.util.ExportUtils;
|
||||
import de.dennisguse.opentracks.util.IntentUtils;
|
||||
import de.dennisguse.opentracks.util.StringUtils;
|
||||
import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||
import de.dennisguse.opentracks.util.TrackUtils;
|
||||
|
||||
public class TrackStoppedActivity extends AbstractTrackDeleteActivity implements ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller {
|
||||
@@ -50,22 +49,23 @@ public class TrackStoppedActivity extends AbstractTrackDeleteActivity implements
|
||||
|
||||
viewBinding.trackEditName.setText(track.getName());
|
||||
|
||||
viewBinding.trackEditActivityType.setText(track.getCategory());
|
||||
viewBinding.trackEditActivityType.setText(track.getActivityTypeLocalized());
|
||||
|
||||
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, ActivityType.getLocalizedStrings(this));
|
||||
viewBinding.trackEditActivityType.setAdapter(adapter);
|
||||
viewBinding.trackEditActivityType.setOnItemClickListener((parent, view, position, id) -> setActivityTypeIcon(TrackIconUtils.getIconValue(this, (String) viewBinding.trackEditActivityType.getAdapter().getItem(position))));
|
||||
viewBinding.trackEditActivityType.setOnItemClickListener((parent, view, position, id) -> {
|
||||
String localizedActivityType = (String) viewBinding.trackEditActivityType.getAdapter().getItem(position);
|
||||
setActivityTypeIcon(ActivityType.findByLocalizedString(this, localizedActivityType));
|
||||
});
|
||||
viewBinding.trackEditActivityType.setOnFocusChangeListener((v, hasFocus) -> {
|
||||
if (!hasFocus) {
|
||||
setActivityTypeIcon(TrackIconUtils.getIconValue(
|
||||
TrackStoppedActivity.this, viewBinding.trackEditActivityType.getText().toString()));
|
||||
String localizedActivityType = viewBinding.trackEditActivityType.getText().toString();
|
||||
setActivityTypeIcon(ActivityType.findByLocalizedString(this, localizedActivityType));
|
||||
}
|
||||
});
|
||||
|
||||
String iconValue = track.getIcon();
|
||||
|
||||
setActivityTypeIcon(iconValue);
|
||||
viewBinding.trackEditActivityTypeIcon.setOnClickListener(v -> ChooseActivityTypeDialogFragment.showDialog(getSupportFragmentManager(), viewBinding.trackEditActivityType.getText().toString()));
|
||||
setActivityTypeIcon(track.getActivityType());
|
||||
viewBinding.trackEditActivityTypeIcon.setOnClickListener(v -> ChooseActivityTypeDialogFragment.showDialog(getSupportFragmentManager(), this, viewBinding.trackEditActivityType.getText().toString()));
|
||||
|
||||
viewBinding.trackEditDescription.setText(track.getDescription());
|
||||
|
||||
@@ -74,7 +74,7 @@ public class TrackStoppedActivity extends AbstractTrackDeleteActivity implements
|
||||
{
|
||||
Pair<String, String> parts = SpeedFormatter.Builder()
|
||||
.setUnit(PreferencesUtils.getUnitSystem())
|
||||
.setReportSpeedOrPace(PreferencesUtils.isReportSpeed(track.getCategory()))
|
||||
.setReportSpeedOrPace(PreferencesUtils.isReportSpeed(track))
|
||||
.build(this)
|
||||
.getSpeedParts(track.getTrackStatistics().getAverageMovingSpeed());
|
||||
viewBinding.speed.setText(parts.first);
|
||||
@@ -125,14 +125,14 @@ public class TrackStoppedActivity extends AbstractTrackDeleteActivity implements
|
||||
return viewBinding.getRoot();
|
||||
}
|
||||
|
||||
private void setActivityTypeIcon(String iconValue) {
|
||||
viewBinding.trackEditActivityTypeIcon.setImageResource(TrackIconUtils.getIconDrawable(iconValue));
|
||||
private void setActivityTypeIcon(ActivityType activityType) {
|
||||
viewBinding.trackEditActivityTypeIcon.setImageResource(activityType.getIconDrawableId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChooseActivityTypeDone(String iconValue) {
|
||||
setActivityTypeIcon(iconValue);
|
||||
viewBinding.trackEditActivityType.setText(getString(TrackIconUtils.getIconActivityType(iconValue)));
|
||||
public void onChooseActivityTypeDone(ActivityType activityType) {
|
||||
setActivityTypeIcon(activityType);
|
||||
viewBinding.trackEditActivityType.setText(getString(activityType.getLocalizedStringId()));
|
||||
}
|
||||
|
||||
private void resumeTrackAndFinish() {
|
||||
|
||||
@@ -65,7 +65,7 @@ public class ChartFragment extends Fragment implements TrackDataHub.Listener {
|
||||
|
||||
// Stats gathered from the received data
|
||||
private final List<ChartPoint> pendingPoints = new ArrayList<>();
|
||||
private String category = "";
|
||||
private String activityTypeLocalized = "";
|
||||
|
||||
// Modes of operation
|
||||
private boolean chartByDistance;
|
||||
@@ -87,7 +87,7 @@ public class ChartFragment extends Fragment implements TrackDataHub.Listener {
|
||||
}
|
||||
}
|
||||
if (PreferencesUtils.isKey(R.string.stats_rate_key, key)) {
|
||||
boolean reportSpeed = PreferencesUtils.isReportSpeed(category);
|
||||
boolean reportSpeed = PreferencesUtils.isReportSpeed(activityTypeLocalized);
|
||||
if (reportSpeed != viewBinding.chartView.getReportSpeed()) {
|
||||
viewBinding.chartView.setReportSpeed(reportSpeed);
|
||||
viewBinding.chartView.applyReportSpeed();
|
||||
@@ -160,12 +160,12 @@ public class ChartFragment extends Fragment implements TrackDataHub.Listener {
|
||||
public void onTrackUpdated(Track track) {
|
||||
if (isResumed()) {
|
||||
if (track == null) {
|
||||
category = "";
|
||||
activityTypeLocalized = "";
|
||||
return;
|
||||
}
|
||||
|
||||
category = track.getCategory();
|
||||
boolean reportSpeed = PreferencesUtils.isReportSpeed(category);
|
||||
activityTypeLocalized = track.getActivityTypeLocalized();
|
||||
boolean reportSpeed = PreferencesUtils.isReportSpeed(activityTypeLocalized);
|
||||
if (reportSpeed != viewBinding.chartView.getReportSpeed()) {
|
||||
viewBinding.chartView.setReportSpeed(reportSpeed);
|
||||
viewBinding.chartView.applyReportSpeed();
|
||||
|
||||
@@ -212,7 +212,7 @@ abstract class ChartValueSeries {
|
||||
int getTitleId(UnitSystem unitSystem) {
|
||||
return switch (unitSystem) {
|
||||
case METRIC -> metricTitleId;
|
||||
case IMPERIAL -> imperialTitleId;
|
||||
case IMPERIAL_FEET, IMPERIAL_METER -> imperialTitleId;
|
||||
case NAUTICAL_IMPERIAL -> nauticalTitleId;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -735,7 +735,7 @@ public class ChartView extends View {
|
||||
if (chartByDistance) {
|
||||
return switch (unitSystem) {
|
||||
case METRIC -> context.getString(R.string.unit_kilometer);
|
||||
case IMPERIAL -> context.getString(R.string.unit_mile);
|
||||
case IMPERIAL_FEET, IMPERIAL_METER -> context.getString(R.string.unit_mile);
|
||||
case NAUTICAL_IMPERIAL -> context.getString(R.string.unit_nautical_mile);
|
||||
};
|
||||
} else {
|
||||
@@ -946,7 +946,7 @@ public class ChartView extends View {
|
||||
*/
|
||||
private void updateEffectiveDimensions() {
|
||||
effectiveWidth = Math.max(0, width - leftBorder - rightBorder);
|
||||
effectiveHeight = Math.max(0, height - topBorder - bottomBorder);
|
||||
effectiveHeight = Math.max(0, height - topBorder - bottomBorder - spacer);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,6 +40,7 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import de.dennisguse.opentracks.BuildConfig;
|
||||
import de.dennisguse.opentracks.data.models.ActivityType;
|
||||
import de.dennisguse.opentracks.data.models.Altitude;
|
||||
import de.dennisguse.opentracks.data.models.Cadence;
|
||||
import de.dennisguse.opentracks.data.models.Distance;
|
||||
@@ -100,7 +101,7 @@ public class ContentProviderUtils {
|
||||
int uuidIndex = cursor.getColumnIndexOrThrow(TracksColumns.UUID);
|
||||
int nameIndex = cursor.getColumnIndexOrThrow(TracksColumns.NAME);
|
||||
int descriptionIndex = cursor.getColumnIndexOrThrow(TracksColumns.DESCRIPTION);
|
||||
int categoryIndex = cursor.getColumnIndexOrThrow(TracksColumns.CATEGORY);
|
||||
int activityTypeLocalizedIndex = cursor.getColumnIndexOrThrow(TracksColumns.ACTIVITY_TYPE_LOCALIZED);
|
||||
int startTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.STARTTIME);
|
||||
int startTimeOffsetIndex = cursor.getColumnIndexOrThrow(TracksColumns.STARTTIME_OFFSET);
|
||||
int stopTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.STOPTIME);
|
||||
@@ -128,8 +129,8 @@ public class ContentProviderUtils {
|
||||
if (!cursor.isNull(descriptionIndex)) {
|
||||
track.setDescription(cursor.getString(descriptionIndex));
|
||||
}
|
||||
if (!cursor.isNull(categoryIndex)) {
|
||||
track.setCategory(cursor.getString(categoryIndex));
|
||||
if (!cursor.isNull(activityTypeLocalizedIndex)) {
|
||||
track.setActivityTypeLocalized(cursor.getString(activityTypeLocalizedIndex));
|
||||
}
|
||||
|
||||
if (!cursor.isNull(startTimeIndex)) {
|
||||
@@ -163,7 +164,7 @@ public class ContentProviderUtils {
|
||||
trackStatistics.setTotalAltitudeLoss(cursor.getFloat(altitudeLossIndex));
|
||||
}
|
||||
if (!cursor.isNull(iconIndex)) {
|
||||
track.setIcon(cursor.getString(iconIndex));
|
||||
track.setActivityType(ActivityType.findBy(cursor.getString(iconIndex)));
|
||||
}
|
||||
return track;
|
||||
}
|
||||
@@ -290,7 +291,7 @@ public class ContentProviderUtils {
|
||||
values.put(TracksColumns.UUID, UUIDUtils.toBytes(track.getUuid()));
|
||||
values.put(TracksColumns.NAME, track.getName());
|
||||
values.put(TracksColumns.DESCRIPTION, track.getDescription());
|
||||
values.put(TracksColumns.CATEGORY, track.getCategory());
|
||||
values.put(TracksColumns.ACTIVITY_TYPE_LOCALIZED, track.getActivityTypeLocalized());
|
||||
values.put(TracksColumns.STARTTIME_OFFSET, track.getZoneOffset().getTotalSeconds());
|
||||
if (trackStatistics.getStartTime() != null) {
|
||||
values.put(TracksColumns.STARTTIME, trackStatistics.getStartTime().toEpochMilli());
|
||||
@@ -308,7 +309,7 @@ public class ContentProviderUtils {
|
||||
values.put(TracksColumns.MAX_ALTITUDE, trackStatistics.getMaxAltitude());
|
||||
values.put(TracksColumns.ALTITUDE_GAIN, trackStatistics.getTotalAltitudeGain());
|
||||
values.put(TracksColumns.ALTITUDE_LOSS, trackStatistics.getTotalAltitudeLoss());
|
||||
values.put(TracksColumns.ICON, track.getIcon());
|
||||
values.put(TracksColumns.ICON, track.getActivityType() != null ? track.getActivityType().getIconId() : "");
|
||||
|
||||
return values;
|
||||
}
|
||||
@@ -403,7 +404,7 @@ public class ContentProviderUtils {
|
||||
public void deleteMarker(Context context, Marker.Id markerId) {
|
||||
final Marker marker = getMarker(markerId);
|
||||
deleteMarkerPhoto(context, marker);
|
||||
contentResolver.delete(MarkerColumns.CONTENT_URI, MarkerColumns._ID + "=?", new String[]{Long.toString(markerId.getId())});
|
||||
contentResolver.delete(MarkerColumns.CONTENT_URI, MarkerColumns._ID + "=?", new String[]{Long.toString(markerId.id())});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -422,7 +423,7 @@ public class ContentProviderUtils {
|
||||
}
|
||||
|
||||
public Marker getMarker(@NonNull Marker.Id markerId) {
|
||||
try (Cursor cursor = getMarkerCursor(null, MarkerColumns._ID + "=?", new String[]{Long.toString(markerId.getId())}, MarkerColumns._ID, 1)) {
|
||||
try (Cursor cursor = getMarkerCursor(null, MarkerColumns._ID + "=?", new String[]{Long.toString(markerId.id())}, MarkerColumns._ID, 1)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return createMarker(cursor);
|
||||
}
|
||||
@@ -442,7 +443,7 @@ public class ContentProviderUtils {
|
||||
String[] selectionArgs;
|
||||
if (minMarkerId != null) {
|
||||
selection = MarkerColumns.TRACKID + "=? AND " + MarkerColumns._ID + ">=?";
|
||||
selectionArgs = new String[]{Long.toString(trackId.getId()), Long.toString(minMarkerId.getId())};
|
||||
selectionArgs = new String[]{Long.toString(trackId.getId()), Long.toString(minMarkerId.id())};
|
||||
} else {
|
||||
selection = MarkerColumns.TRACKID + "=?";
|
||||
selectionArgs = new String[]{Long.toString(trackId.getId())};
|
||||
@@ -495,7 +496,7 @@ public class ContentProviderUtils {
|
||||
if (!updateMarker.hasPhoto()) {
|
||||
deleteMarkerPhoto(context, savedMarker);
|
||||
}
|
||||
int rows = contentResolver.update(MarkerColumns.CONTENT_URI, createContentValues(updateMarker), MarkerColumns._ID + "=?", new String[]{Long.toString(updateMarker.getId().getId())});
|
||||
int rows = contentResolver.update(MarkerColumns.CONTENT_URI, createContentValues(updateMarker), MarkerColumns._ID + "=?", new String[]{Long.toString(updateMarker.getId().id())});
|
||||
return rows == 1;
|
||||
}
|
||||
|
||||
@@ -503,7 +504,7 @@ public class ContentProviderUtils {
|
||||
ContentValues values = new ContentValues();
|
||||
|
||||
if (marker.getId() != null) {
|
||||
values.put(MarkerColumns._ID, marker.getId().getId());
|
||||
values.put(MarkerColumns._ID, marker.getId().id());
|
||||
}
|
||||
values.put(MarkerColumns.NAME, marker.getName());
|
||||
values.put(MarkerColumns.DESCRIPTION, marker.getDescription());
|
||||
|
||||
@@ -213,7 +213,7 @@ public class ShareContentProvider extends CustomContentProvider {
|
||||
PipeDataWriter<String> pipeDataWriter = (output, uri1, mimeType, opts, args) -> {
|
||||
try (FileOutputStream fileOutputStream = new FileOutputStream(output.getFileDescriptor())) {
|
||||
// TODO handle failure (i.e., do not export an empty file)
|
||||
trackExporter.writeTrack(tracks.toArray(new Track[0]), fileOutputStream);
|
||||
trackExporter.writeTrack(tracks, fileOutputStream);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "there occurred an error while sharing a file: " + e);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ import de.dennisguse.opentracks.data.tables.TrackPointsColumns;
|
||||
import de.dennisguse.opentracks.data.tables.TracksColumns;
|
||||
import de.dennisguse.opentracks.services.RecordingStatus;
|
||||
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||
import de.dennisguse.opentracks.services.handlers.EGM2008CorrectionManager;
|
||||
import de.dennisguse.opentracks.services.handlers.AltitudeCorrectionManager;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
||||
|
||||
@@ -73,7 +73,7 @@ public class TrackDataHub {
|
||||
private final ContentProviderUtils contentProviderUtils;
|
||||
private final int targetNumPoints;
|
||||
|
||||
private final EGM2008CorrectionManager egm2008Correction = new EGM2008CorrectionManager();
|
||||
private final AltitudeCorrectionManager egm2008Correction = new AltitudeCorrectionManager();
|
||||
|
||||
//TODO Check if this is needed.
|
||||
private HandlerThread handlerThread;
|
||||
|
||||
@@ -30,9 +30,9 @@ public class TrackSelection implements ContentProviderUtils.ContentProviderSelec
|
||||
return this;
|
||||
}
|
||||
|
||||
public TrackSelection addCategory(String category) {
|
||||
if (!this.categories.contains(category)) {
|
||||
this.categories.add(category);
|
||||
public TrackSelection addActivityType(String activityType) {
|
||||
if (!this.categories.contains(activityType)) {
|
||||
this.categories.add(activityType);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -53,7 +53,7 @@ public class TrackSelection implements ContentProviderUtils.ContentProviderSelec
|
||||
}
|
||||
if (!categories.isEmpty()) {
|
||||
selection += selection.isEmpty() ? "" : " AND ";
|
||||
selection += String.format(TracksColumns.CATEGORY + " IN (%s)", TextUtils.join(",", Collections.nCopies(categories.size(), "?")));
|
||||
selection += String.format(TracksColumns.ACTIVITY_TYPE_LOCALIZED + " IN (%s)", TextUtils.join(",", Collections.nCopies(categories.size(), "?")));
|
||||
}
|
||||
if (from != null && to != null) {
|
||||
selection += selection.isEmpty() ? "" : " AND ";
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package de.dennisguse.opentracks.data.models;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
|
||||
public enum ActivityIcon {
|
||||
AIRPLANE("AIRPLANE", R.drawable.ic_activity_flight_24dp),
|
||||
BIKE("BIKE", R.drawable.ic_activity_bike_24dp),
|
||||
MOUNTAIN_BIKE("MOUNTAIN_BIKE", R.drawable.ic_activity_mtb_24dp),
|
||||
MOTOR_BIKE("MOTOR_BIKE", R.drawable.ic_activity_motorbike_24dp),
|
||||
KAYAK("KAYAK", R.drawable.ic_activity_kayaking_24dp),
|
||||
BOAT("BOAT", R.drawable.ic_activity_boat_24dp),
|
||||
SAILING("SAILING", R.drawable.ic_activity_sailing_24dp),
|
||||
DRIVE("DRIVE", R.drawable.ic_activity_drive_24dp),
|
||||
RUN("RUN", R.drawable.ic_activity_run_24dp),
|
||||
SKI("SKI", R.drawable.ic_activity_skiing_24dp),
|
||||
SNOW_BOARDING("SNOW_BOARDING", R.drawable.ic_activity_snowboarding_24dp),
|
||||
UNKNOWN("UNKNOWN", R.drawable.ic_logo_24dp),
|
||||
WALK("WALK", R.drawable.ic_activity_walk_24dp),
|
||||
ESCOOTER("ESCOOTER", R.drawable.ic_activity_escooter_24dp),
|
||||
INLINE_SKATING("INLINES_SKATING", R.drawable.ic_activity_inline_skating_24dp),
|
||||
SKATE_BOARDING("SKATE_BOARDING", R.drawable.ic_activity_skateboarding_24dp),
|
||||
CLIMBING("CLIMBING", R.drawable.ic_activity_climbing_24dp),
|
||||
SWIMMING("SWIMMING", R.drawable.ic_activity_swimming_24dp),
|
||||
SWIMMING_OPEN("SWIMMING_OPEN", R.drawable.ic_activity_swimming_open_24dp),
|
||||
WORKOUT("WORKOUT", R.drawable.ic_activity_workout_24dp);
|
||||
|
||||
@Deprecated //TODO should be removed.
|
||||
final String iconId;
|
||||
final int iconDrawableId;
|
||||
|
||||
ActivityIcon(String iconId, int iconDrawableId) {
|
||||
this.iconId = iconId;
|
||||
this.iconDrawableId = iconDrawableId;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
package de.dennisguse.opentracks.data.models;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -10,70 +12,138 @@ import java.util.stream.Collectors;
|
||||
import de.dennisguse.opentracks.R;
|
||||
|
||||
public enum ActivityType {
|
||||
AIRPLANE("AIRPLANE", R.drawable.ic_activity_flight_24dp, true, R.string.activity_type_airplane, R.string.activity_type_commercial_airplane, R.string.activity_type_rc_airplane),
|
||||
BIKE("BIKE", R.drawable.ic_activity_bike_24dp, true, R.string.activity_type_biking, R.string.activity_type_cycling, R.string.activity_type_dirt_bike, R.string.activity_type_road_biking, R.string.activity_type_track_cycling),
|
||||
MOUNTAIN_BIKE("MOUNTAIN_BIKE", R.drawable.ic_activity_mtb_24dp, true, R.string.activity_type_mountain_biking),
|
||||
MOTOR_BIKE("MOTOR_BIKE", R.drawable.ic_activity_motorbike_24dp, true, R.string.activity_type_motor_bike),
|
||||
KAYAK("KAYAK", R.drawable.ic_activity_kayaking_24dp, true, R.string.activity_type_kayaking),
|
||||
BOAT("BOAT", R.drawable.ic_activity_boat_24dp, true, R.string.activity_type_boat, R.string.activity_type_ferry, R.string.activity_type_motor_boating, R.string.activity_type_rc_boat),
|
||||
SAILING("SAILING", R.drawable.ic_activity_sailing_24dp, true, R.string.activity_type_sailing),
|
||||
DRIVE("DRIVE", R.drawable.ic_activity_drive_24dp, true, R.string.activity_type_atv, R.string.activity_type_driving, R.string.activity_type_driving_bus, R.string.activity_type_driving_car),
|
||||
RUN("RUN", R.drawable.ic_activity_run_24dp, false, R.string.activity_type_running, R.string.activity_type_street_running, R.string.activity_type_track_running, R.string.activity_type_trail_running),
|
||||
SKI("SKI", R.drawable.ic_activity_skiing_24dp, true, R.string.activity_type_cross_country_skiing, R.string.activity_type_skiing),
|
||||
SNOW_BOARDING("SNOW_BOARDING", R.drawable.ic_activity_snowboarding_24dp, true, R.string.activity_type_snow_boarding),
|
||||
UNKNOWN("UNKNOWN", R.drawable.ic_logo_24dp, true, R.string.activity_type_unknown),
|
||||
WALK("WALK", R.drawable.ic_activity_walk_24dp, false, R.string.activity_type_hiking, R.string.activity_type_off_trail_hiking, R.string.activity_type_speed_walking, R.string.activity_type_trail_hiking, R.string.activity_type_walking),
|
||||
ESCOOTER("ESCOOTER", R.drawable.ic_activity_escooter_24dp, true, R.string.activity_type_escooter),
|
||||
INLINE_SKATING("INLINES_SKATING", R.drawable.ic_activity_inline_skating_24dp, true, R.string.activity_type_inline_skating),
|
||||
SKATE_BOARDING("SKATE_BOARDING", R.drawable.ic_activity_skateboarding_24dp, true, R.string.activity_type_skate_boarding),
|
||||
CLIMBING("CLIMBING", R.drawable.ic_activity_climbing_24dp, false, R.string.activity_type_climbing),
|
||||
SWIMMING("SWIMMING", R.drawable.ic_activity_swimming_24dp, false, R.string.activity_type_swimming),
|
||||
SWIMMING_OPEN("SWIMMING_OPEN", R.drawable.ic_activity_swimming_open_24dp, false, R.string.activity_type_swimming_open),
|
||||
WORKOUT("WORKOUT", R.drawable.ic_activity_workout_24dp, false, R.string.activity_type_workout);
|
||||
|
||||
AIRPLANE("airplane", R.string.activity_type_airplane, ActivityIcon.AIRPLANE, true),
|
||||
ATV("ATV", R.string.activity_type_atv, ActivityIcon.DRIVE, true),
|
||||
BIKING("biking", R.string.activity_type_biking, ActivityIcon.BIKE, true),
|
||||
BLIMP("blimp", R.string.activity_type_blimp, ActivityIcon.UNKNOWN, true),
|
||||
BOAT("boat", R.string.activity_type_boat, ActivityIcon.BOAT, true),
|
||||
CLIMBING("climbing", R.string.activity_type_climbing, ActivityIcon.CLIMBING, false),
|
||||
COMMERCIAL_AIRPLANE("commercial airplane", R.string.activity_type_commercial_airplane, ActivityIcon.AIRPLANE, true),
|
||||
CROSS_COUNTRY_SKIING("cross-country skiing", R.string.activity_type_cross_country_skiing, ActivityIcon.SKI, true),
|
||||
CYCLING("cycling", R.string.activity_type_cycling, ActivityIcon.BIKE, true),
|
||||
DIRT_BIKE("dirt bike", R.string.activity_type_dirt_bike, ActivityIcon.MOTOR_BIKE, true),
|
||||
DONKEY_BACK_RIDING("donkey back riding", R.string.activity_type_donkey_back_riding, ActivityIcon.UNKNOWN, true),
|
||||
DRIVING("driving", R.string.activity_type_driving, ActivityIcon.DRIVE, true),
|
||||
DRIVING_BUS("driving bus", R.string.activity_type_driving_bus, ActivityIcon.DRIVE, true),
|
||||
DRIVING_CAR("driving car", R.string.activity_type_driving_car, ActivityIcon.DRIVE, true),
|
||||
ESCOOTER("escooter", R.string.activity_type_escooter, ActivityIcon.ESCOOTER, true),
|
||||
FERRY("ferry", R.string.activity_type_ferry, ActivityIcon.BOAT, true),
|
||||
FRISBEE("frisbee", R.string.activity_type_frisbee, ActivityIcon.UNKNOWN, true),
|
||||
GLIDING("gliding", R.string.activity_type_gliding, ActivityIcon.UNKNOWN, true),
|
||||
HANG_GLIDING("hang gliding", R.string.activity_type_hang_gliding, ActivityIcon.UNKNOWN, true),
|
||||
HELICOPTER("helicopter", R.string.activity_type_helicopter, ActivityIcon.UNKNOWN, true),
|
||||
HIKING("hiking", R.string.activity_type_hiking, ActivityIcon.WALK, false),
|
||||
HORSE_BACK_RIDING("horse back riding", R.string.activity_type_horse_back_riding, ActivityIcon.UNKNOWN, true),
|
||||
HOT_AIR_BALLOON("hot air balloon", R.string.activity_type_hot_air_balloon, ActivityIcon.UNKNOWN, true),
|
||||
ICE_SAILING("ice sailing", R.string.activity_type_ice_sailing, ActivityIcon.UNKNOWN, true),
|
||||
INLINE_SKATING("inline skating", R.string.activity_type_inline_skating, ActivityIcon.INLINE_SKATING, true),
|
||||
KAYAKING("kayaking", R.string.activity_type_kayaking, ActivityIcon.KAYAK, true),
|
||||
KITE_SURFING("kite surfing", R.string.activity_type_kite_surfing, ActivityIcon.UNKNOWN, true),
|
||||
LAND_SAILING("land sailing", R.string.activity_type_land_sailing, ActivityIcon.UNKNOWN, true),
|
||||
MIXED_TYPE("mixed type", R.string.activity_type_mixed_type, ActivityIcon.UNKNOWN, true),
|
||||
MOTOR_BIKE("motor bike", R.string.activity_type_motor_bike, ActivityIcon.MOTOR_BIKE, true),
|
||||
MOTOR_BOATING("motor boating", R.string.activity_type_motor_boating, ActivityIcon.BOAT, true),
|
||||
MOUNTAIN_BIKING("mountain biking", R.string.activity_type_mountain_biking, ActivityIcon.MOUNTAIN_BIKE, true),
|
||||
OFF_TRAIL_HIKING("off trail hiking", R.string.activity_type_hiking, ActivityIcon.WALK, false),
|
||||
OTHER("other", R.string.activity_type_other, ActivityIcon.UNKNOWN, true),
|
||||
PADDLING("paddling", R.string.activity_type_paddling, ActivityIcon.UNKNOWN, true),
|
||||
PARA_GLIDING("para gliding", R.string.activity_type_para_gliding, ActivityIcon.UNKNOWN, true),
|
||||
RC_AIRPLANE("RC airplane", R.string.activity_type_rc_airplane, ActivityIcon.AIRPLANE, true),
|
||||
RC_BOAT("RC boat", R.string.activity_type_rc_boat, ActivityIcon.BOAT, true),
|
||||
RC_HELICOPTER("RC helicopter", R.string.activity_type_rc_helicopter, ActivityIcon.UNKNOWN, true),
|
||||
RIDING("riding", R.string.activity_type_horse_back_riding, ActivityIcon.UNKNOWN, true),
|
||||
ROAD_BIKING("road biking", R.string.activity_type_road_biking, ActivityIcon.BIKE, true),
|
||||
ROLLER_SKIING("roller skiing", R.string.activity_type_roller_skiing, ActivityIcon.UNKNOWN, true),
|
||||
ROWING("rowing", R.string.activity_type_rowing, ActivityIcon.UNKNOWN, true),
|
||||
RUNNING("running", R.string.activity_type_running, ActivityIcon.RUN, false),
|
||||
SAILING("sailing", R.string.activity_type_sailing, ActivityIcon.SAILING, true),
|
||||
SEAPLANE("seaplane", R.string.activity_type_seaplane, ActivityIcon.AIRPLANE, true),
|
||||
SKATE_BOARDING("skate boarding", R.string.activity_type_skate_boarding, ActivityIcon.SKATE_BOARDING, true),
|
||||
SKATING("skating", R.string.activity_type_skating, ActivityIcon.UNKNOWN, true),
|
||||
SKIING("skiing", R.string.activity_type_skiing, ActivityIcon.SKI, true),
|
||||
SKY_JUMPING("sky jumping", R.string.activity_type_sky_jumping, ActivityIcon.UNKNOWN, true),
|
||||
SLED("sled", R.string.activity_type_sled, ActivityIcon.UNKNOWN, true),
|
||||
SNOW_BOARDING("snow boarding", R.string.activity_type_snow_boarding, ActivityIcon.SNOW_BOARDING, true),
|
||||
SNOW_SHOEING("snow shoeing", R.string.activity_type_snow_shoeing, ActivityIcon.UNKNOWN, true),
|
||||
SPEED_WALKING("speed walking", R.string.activity_type_speed_walking, ActivityIcon.WALK, false),
|
||||
STREET_RUNNING("street running", R.string.activity_type_street_running, ActivityIcon.RUN, false),
|
||||
SURFING("surfing", R.string.activity_type_surfing, ActivityIcon.UNKNOWN, true),
|
||||
TRACK_CYCLING("track cycling", R.string.activity_type_track_cycling, ActivityIcon.BIKE, true),
|
||||
TRACK_RUNNING("track running", R.string.activity_type_trail_running, ActivityIcon.RUN, false),
|
||||
TRAIL_HIKING("trail hiking", R.string.activity_type_trail_hiking, ActivityIcon.WALK, false),
|
||||
TRAIL_RUNNING("trail running", R.string.activity_type_trail_running, ActivityIcon.RUN, false),
|
||||
TRAIN("train", R.string.activity_type_train, ActivityIcon.UNKNOWN, true),
|
||||
ULTIMATE_FRISBEE("ultimate frisbee", R.string.activity_type_ultimate_frisbee, ActivityIcon.UNKNOWN, true),
|
||||
WAKEBOARDING("wakeboarding", R.string.activity_type_wakeboarding, ActivityIcon.UNKNOWN, true),
|
||||
WALKING("walking", R.string.activity_type_walking, ActivityIcon.WALK, false),
|
||||
WATER_SKIING("water skiing", R.string.activity_type_water_skiing, ActivityIcon.UNKNOWN, true),
|
||||
WIND_SURFING("wind surfing", R.string.activity_type_wind_surfing, ActivityIcon.UNKNOWN, true),
|
||||
SWIMMING("swimming", R.string.activity_type_swimming, ActivityIcon.SWIMMING, false),
|
||||
SWIMMING_OPEN("swimming in open water", R.string.activity_type_swimming_open, ActivityIcon.SWIMMING_OPEN, false),
|
||||
WORKOUT("workout", R.string.activity_type_workout, ActivityIcon.WORKOUT, false),
|
||||
UNKNOWN("unknown", R.string.activity_type_unknown, ActivityIcon.UNKNOWN, true);
|
||||
|
||||
final String id;
|
||||
final int iconId;
|
||||
|
||||
final ActivityIcon icon;
|
||||
final boolean showSpeedPreferred;
|
||||
final int[] localizedStringIds;
|
||||
final int localizedStringId;
|
||||
|
||||
//isSpeed?
|
||||
|
||||
ActivityType(String id, int iconId, boolean showSpeedPreferred, int... localizedStringIds) {
|
||||
ActivityType(String id, int localizedStringId, ActivityIcon icon, boolean showSpeedPreferred) {
|
||||
this.id = id;
|
||||
this.iconId = iconId;
|
||||
this.localizedStringId = localizedStringId;
|
||||
this.icon = icon;
|
||||
this.showSpeedPreferred = showSpeedPreferred;
|
||||
this.localizedStringIds = localizedStringIds;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getIconId() {
|
||||
return iconId;
|
||||
@Deprecated
|
||||
public String getIconId() {
|
||||
return icon.iconId;
|
||||
}
|
||||
|
||||
public int getIconDrawableId() {
|
||||
return icon.iconDrawableId;
|
||||
}
|
||||
|
||||
public int getLocalizedStringId() {
|
||||
return localizedStringId;
|
||||
}
|
||||
|
||||
public boolean isShowSpeedPreferred() {
|
||||
return showSpeedPreferred;
|
||||
}
|
||||
|
||||
public int[] getLocalizedStringIds() {
|
||||
return localizedStringIds;
|
||||
}
|
||||
|
||||
public int getFirstLocalizedStringId() {
|
||||
return localizedStringIds[0];
|
||||
}
|
||||
|
||||
public static List<String> getLocalizedStrings(Context context) {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (ActivityType activityType : values()) {
|
||||
List<String> strings = Arrays.stream(activityType.localizedStringIds)
|
||||
.mapToObj(context::getString)
|
||||
.collect(Collectors.toList());
|
||||
result.addAll(strings);
|
||||
}
|
||||
return Arrays.stream(values())
|
||||
.map(ActivityType::getLocalizedStringId)
|
||||
.map(context::getString)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
return result;
|
||||
@NonNull
|
||||
public static ActivityType findBy(String iconId) {
|
||||
if (ActivityIcon.UNKNOWN.iconId.equals(iconId)) {
|
||||
return ActivityType.UNKNOWN;
|
||||
}
|
||||
return Arrays.stream(ActivityType.values()).filter(
|
||||
it -> it.icon.iconId.equals(iconId)
|
||||
).findFirst()
|
||||
.orElse(ActivityType.UNKNOWN);
|
||||
}
|
||||
|
||||
public static ActivityType findByLocalizedString(Context context, String localizedActivityType) {
|
||||
return findByLocalizedString(context.getResources(), localizedActivityType);
|
||||
}
|
||||
|
||||
public static ActivityType findByLocalizedString(Resources resources, String localizedActivityType) {
|
||||
return Arrays.stream(ActivityType.values())
|
||||
.filter(it -> resources.getString(it.getLocalizedStringId()).equals(localizedActivityType))
|
||||
.findFirst()
|
||||
.orElse(ActivityType.UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,7 @@ public abstract class Altitude {
|
||||
public double toM() {
|
||||
return altitude_m;
|
||||
}
|
||||
|
||||
public abstract Altitude replace(double altitude_m);
|
||||
|
||||
|
||||
public abstract int getLabelId();
|
||||
|
||||
public static class WGS84 extends Altitude {
|
||||
@@ -31,12 +29,7 @@ public abstract class Altitude {
|
||||
return R.string.wgs84;
|
||||
}
|
||||
|
||||
public static Altitude of(double altitude_m) {
|
||||
return new WGS84(altitude_m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Altitude replace(double altitude_m) {
|
||||
public static WGS84 of(double altitude_m) {
|
||||
return new WGS84(altitude_m);
|
||||
}
|
||||
}
|
||||
@@ -52,12 +45,7 @@ public abstract class Altitude {
|
||||
return R.string.egm2008;
|
||||
}
|
||||
|
||||
public static Altitude of(double altitude_m) {
|
||||
return new EGM2008(altitude_m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Altitude replace(double altitude_m) {
|
||||
public static EGM2008 of(double altitude_m) {
|
||||
return new EGM2008(altitude_m);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package de.dennisguse.opentracks.data.models;
|
||||
|
||||
public record AtmosphericPressure(float value) {
|
||||
|
||||
public static AtmosphericPressure ofPA(float value_Pa) {
|
||||
return new AtmosphericPressure(value_Pa * 100);
|
||||
}
|
||||
|
||||
public static AtmosphericPressure ofHPA(float value_hPa) {
|
||||
return new AtmosphericPressure(value_hPa);
|
||||
}
|
||||
|
||||
public float getPA() {
|
||||
return value * 100;
|
||||
}
|
||||
|
||||
public float getHPA() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.dennisguse.opentracks.data.models;
|
||||
|
||||
public record BatteryLevel(int percentage) {
|
||||
|
||||
public static BatteryLevel of(int percentage) {
|
||||
return new BatteryLevel(percentage);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,8 @@
|
||||
package de.dennisguse.opentracks.data.models;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Cadence {
|
||||
public record Cadence(float value_rpm) {
|
||||
|
||||
public static Cadence of(float value, Duration duration) {
|
||||
if (duration.isZero()) {
|
||||
@@ -23,34 +20,7 @@ public class Cadence {
|
||||
return of(0.0f);
|
||||
}
|
||||
|
||||
private final float value_rpm;
|
||||
|
||||
private Cadence(float value) {
|
||||
this.value_rpm = value;
|
||||
}
|
||||
|
||||
public float getRPM() {
|
||||
return value_rpm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Cadence cadence = (Cadence) o;
|
||||
return Float.compare(cadence.value_rpm, value_rpm) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(value_rpm);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Cadence{" +
|
||||
"value=" + value_rpm + " rpm" +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,13 @@ package de.dennisguse.opentracks.data.models;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import de.dennisguse.opentracks.settings.UnitSystem;
|
||||
|
||||
public class Distance {
|
||||
public record Distance(double distance_m) {
|
||||
|
||||
public static Distance of(double distance_m) {
|
||||
return new Distance(distance_m);
|
||||
}
|
||||
|
||||
public static Distance of(Double distance_m) {
|
||||
if (distance_m == null) {
|
||||
return Distance.of(Double.NaN);
|
||||
@@ -20,11 +17,9 @@ public class Distance {
|
||||
return Distance.of((double) distance_m);
|
||||
}
|
||||
}
|
||||
|
||||
public static Distance of(String distance_m) {
|
||||
return of(Float.parseFloat(distance_m));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Distance ofOrNull(Double distance_m) {
|
||||
if (distance_m == null) {
|
||||
@@ -60,17 +55,11 @@ public class Distance {
|
||||
public static Distance one(UnitSystem unitSystem) {
|
||||
return switch (unitSystem) {
|
||||
case METRIC -> Distance.ofKilometer(1);
|
||||
case IMPERIAL -> Distance.ofMile(1);
|
||||
case IMPERIAL_FEET, IMPERIAL_METER -> Distance.ofMile(1);
|
||||
case NAUTICAL_IMPERIAL -> Distance.ofNauticalMile(1);
|
||||
};
|
||||
}
|
||||
|
||||
private final double distance_m;
|
||||
|
||||
private Distance(double distance_m) {
|
||||
this.distance_m = distance_m;
|
||||
}
|
||||
|
||||
public Distance plus(@NonNull Distance distance) {
|
||||
return new Distance(distance_m + distance.distance_m);
|
||||
}
|
||||
@@ -130,39 +119,18 @@ public class Distance {
|
||||
public double toKM_Miles(UnitSystem unitSystem) {
|
||||
return switch (unitSystem) {
|
||||
case METRIC -> toKM();
|
||||
case IMPERIAL -> toMI();
|
||||
case IMPERIAL_FEET, IMPERIAL_METER -> toMI();
|
||||
case NAUTICAL_IMPERIAL -> toNauticalMiles();
|
||||
};
|
||||
}
|
||||
|
||||
public double toM_FT(UnitSystem unitSystem) {
|
||||
return switch (unitSystem) {
|
||||
case METRIC -> toM();
|
||||
case NAUTICAL_IMPERIAL, IMPERIAL -> toFT();
|
||||
case METRIC, IMPERIAL_METER -> toM();
|
||||
case NAUTICAL_IMPERIAL, IMPERIAL_FEET -> toFT();
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Distance distance = (Distance) o;
|
||||
return Double.compare(distance.distance_m, distance_m) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(distance_m);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Distance{" +
|
||||
"distance_m=" + distance_m +
|
||||
'}';
|
||||
}
|
||||
|
||||
// multiplication factors for conversion
|
||||
private static final double KM_TO_M = 1000.0;
|
||||
private static final double M_TO_KM = 1 / KM_TO_M;
|
||||
|
||||
@@ -47,8 +47,9 @@ public class DistanceFormatter {
|
||||
if (distance.isInvalid()) {
|
||||
String valueUnknown = resources.getString(R.string.value_unknown);
|
||||
return switch (unitSystem) {
|
||||
case METRIC -> new Pair<>(valueUnknown, resources.getString(R.string.unit_meter));
|
||||
case IMPERIAL, NAUTICAL_IMPERIAL ->
|
||||
case METRIC, IMPERIAL_METER ->
|
||||
new Pair<>(valueUnknown, resources.getString(R.string.unit_meter));
|
||||
case IMPERIAL_FEET, NAUTICAL_IMPERIAL ->
|
||||
new Pair<>(valueUnknown, resources.getString(R.string.unit_feet));
|
||||
};
|
||||
}
|
||||
@@ -61,13 +62,20 @@ public class DistanceFormatter {
|
||||
return new Pair<>(StringUtils.formatDecimal(distance.toM(), decimalCount), resources.getString(R.string.unit_meter));
|
||||
}
|
||||
}
|
||||
case IMPERIAL -> {
|
||||
case IMPERIAL_FEET -> {
|
||||
if (distance.greaterThan(Distance.ofMile(threshold))) {
|
||||
return new Pair<>(StringUtils.formatDecimal(distance.toMI(), decimalCount), resources.getString(R.string.unit_mile));
|
||||
} else {
|
||||
return new Pair<>(StringUtils.formatDecimal(distance.toFT(), decimalCount), resources.getString(R.string.unit_feet));
|
||||
}
|
||||
}
|
||||
case IMPERIAL_METER -> {
|
||||
if (distance.greaterThan(Distance.ofMile(threshold))) {
|
||||
return new Pair<>(StringUtils.formatDecimal(distance.toMI(), decimalCount), resources.getString(R.string.unit_mile));
|
||||
} else {
|
||||
return new Pair<>(StringUtils.formatDecimal(distance.toM(), decimalCount), resources.getString(R.string.unit_meter));
|
||||
}
|
||||
}
|
||||
case NAUTICAL_IMPERIAL -> {
|
||||
if (distance.greaterThan(Distance.ofNauticalMile(threshold))) {
|
||||
return new Pair<>(StringUtils.formatDecimal(distance.toNauticalMiles(), decimalCount), resources.getString(R.string.unit_nautical_mile));
|
||||
|
||||
@@ -1,43 +1,12 @@
|
||||
package de.dennisguse.opentracks.data.models;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class HeartRate {
|
||||
public record HeartRate(float value) {
|
||||
|
||||
public static HeartRate of(float value) {
|
||||
return new HeartRate(value);
|
||||
}
|
||||
|
||||
private final float value;
|
||||
|
||||
private HeartRate(float value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public float getBPM() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
HeartRate heartRate = (HeartRate) o;
|
||||
return Float.compare(heartRate.value, value) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(value);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HeartRate{" +
|
||||
"value=" + value + " bpm" +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Objects;
|
||||
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
|
||||
@@ -267,31 +266,7 @@ public final class Marker {
|
||||
return photoUrl != null && !"".equals(photoUrl);
|
||||
}
|
||||
|
||||
public static class Id implements Parcelable {
|
||||
|
||||
private final long id;
|
||||
|
||||
public Id(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
//TOOD Limit visibility to TrackRecordingService / ContentProvider
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Id id1 = (Id) o;
|
||||
return id == id1.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
public record Id(long id) implements Parcelable {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
@@ -309,7 +284,7 @@ public final class Marker {
|
||||
parcel.writeLong(id);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<Id> CREATOR = new Parcelable.Creator<>() {
|
||||
public static final Creator<Id> CREATOR = new Creator<>() {
|
||||
public Id createFromParcel(Parcel in) {
|
||||
return new Id(in.readLong());
|
||||
}
|
||||
|
||||
@@ -1,43 +1,12 @@
|
||||
package de.dennisguse.opentracks.data.models;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Power {
|
||||
public record Power(float value) {
|
||||
|
||||
public static Power of(float value) {
|
||||
return new Power(value);
|
||||
}
|
||||
|
||||
private final float value;
|
||||
|
||||
private Power(float value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public float getW() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Power power = (Power) o;
|
||||
return Float.compare(power.value, value) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(value);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Power{" +
|
||||
"value=" + value + " W" +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
package de.dennisguse.opentracks.data.models;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
|
||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||
import de.dennisguse.opentracks.settings.UnitSystem;
|
||||
|
||||
public class Speed {
|
||||
public record Speed(double speed_mps) {
|
||||
|
||||
public static Speed of(Distance distance, Duration duration) {
|
||||
if (duration.isZero()) {
|
||||
@@ -47,12 +44,6 @@ public class Speed {
|
||||
return Speed.of(Math.abs(speed1.speed_mps - speed2.speed_mps));
|
||||
}
|
||||
|
||||
private final double speed_mps;
|
||||
|
||||
private Speed(double speed_mps) {
|
||||
this.speed_mps = speed_mps;
|
||||
}
|
||||
|
||||
public Speed mul(double factor) {
|
||||
return new Speed(factor * speed_mps);
|
||||
}
|
||||
@@ -117,29 +108,8 @@ public class Speed {
|
||||
public double to(UnitSystem unitSystem) {
|
||||
return switch (unitSystem) {
|
||||
case METRIC -> toKMH();
|
||||
case IMPERIAL -> toMPH();
|
||||
case IMPERIAL_FEET, IMPERIAL_METER -> toMPH();
|
||||
case NAUTICAL_IMPERIAL -> toKnots();
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Speed speed = (Speed) o;
|
||||
return Double.compare(speed.speed_mps, speed_mps) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(speed_mps);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Speed{" +
|
||||
"speed_mps=" + speed_mps +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class SpeedFormatter {
|
||||
int unitId = switch (unitSystem) {
|
||||
case METRIC ->
|
||||
reportSpeedOrPace ? R.string.unit_kilometer_per_hour : R.string.unit_minute_per_kilometer;
|
||||
case IMPERIAL ->
|
||||
case IMPERIAL_FEET, IMPERIAL_METER ->
|
||||
reportSpeedOrPace ? R.string.unit_mile_per_hour : R.string.unit_minute_per_mile;
|
||||
case NAUTICAL_IMPERIAL ->
|
||||
reportSpeedOrPace ? R.string.unit_knots : R.string.unit_minute_per_nautical_mile;
|
||||
|
||||
@@ -44,9 +44,9 @@ public class Track {
|
||||
|
||||
private String name = "";
|
||||
private String description = "";
|
||||
private String category = "";
|
||||
private String activityTypeLocalized = "";
|
||||
|
||||
private String icon = "";
|
||||
private ActivityType activityType;
|
||||
|
||||
private final ZoneOffset zoneOffset;
|
||||
|
||||
@@ -54,7 +54,7 @@ public class Track {
|
||||
|
||||
@VisibleForTesting
|
||||
public Track() {
|
||||
this.zoneOffset = ZoneOffset.UTC;
|
||||
this(ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
public Track(@NonNull ZoneOffset zoneOffset) {
|
||||
@@ -97,20 +97,20 @@ public class Track {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getCategory() {
|
||||
return category;
|
||||
public String getActivityTypeLocalized() {
|
||||
return activityTypeLocalized;
|
||||
}
|
||||
|
||||
public void setCategory(String category) {
|
||||
this.category = category;
|
||||
public void setActivityTypeLocalized(String activityType) {
|
||||
this.activityTypeLocalized = activityType;
|
||||
}
|
||||
|
||||
public String getIcon() {
|
||||
return icon;
|
||||
public ActivityType getActivityType() {
|
||||
return activityType;
|
||||
}
|
||||
|
||||
public void setIcon(String icon) {
|
||||
this.icon = icon;
|
||||
public void setActivityType(ActivityType activityType) {
|
||||
this.activityType = activityType;
|
||||
}
|
||||
|
||||
public ZoneOffset getZoneOffset() {
|
||||
|
||||
@@ -130,11 +130,11 @@ public class TrackPoint {
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isSegmentStart() {
|
||||
return type == Type.SEGMENT_START_AUTOMATIC || type == Type.SEGMENT_START_MANUAL;
|
||||
public boolean isSegmentManualStart() {
|
||||
return type == Type.SEGMENT_START_MANUAL;
|
||||
}
|
||||
|
||||
public boolean isSegmentEnd() {
|
||||
public boolean isSegmentManualEnd() {
|
||||
return type == Type.SEGMENT_END_MANUAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public interface TracksColumns extends BaseColumns {
|
||||
String UUID = "uuid"; // identifier to make tracks globally unique (prevent re-import)
|
||||
String NAME = "name"; // track name
|
||||
String DESCRIPTION = "description"; // track description
|
||||
String CATEGORY = "category"; // track activity type
|
||||
String ACTIVITY_TYPE_LOCALIZED = "category"; // track activity type
|
||||
String STARTTIME = "starttime"; // track start time
|
||||
String STARTTIME_OFFSET = "starttime_offset"; // in plus/minus in seconds
|
||||
String STOPTIME = "stoptime"; // track stop time
|
||||
@@ -57,13 +57,13 @@ public interface TracksColumns extends BaseColumns {
|
||||
String MAX_ALTITUDE = "maxelevation"; // maximum altitude //TODO RENAME column
|
||||
String ALTITUDE_GAIN = "elevationgain"; // altitude gain //TODO RENAME column
|
||||
String ALTITUDE_LOSS = "elevationloss"; // altitude loss //TODO RENAME column
|
||||
String ICON = "icon"; // track activity type icon
|
||||
String ICON = "icon"; // track activity type icon //TODO DEPRECATED
|
||||
|
||||
String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " ("
|
||||
+ _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
+ NAME + " TEXT, "
|
||||
+ DESCRIPTION + " TEXT, "
|
||||
+ CATEGORY + " TEXT, "
|
||||
+ ACTIVITY_TYPE_LOCALIZED + " TEXT, "
|
||||
+ STARTTIME + " INTEGER, "
|
||||
+ STOPTIME + " INTEGER, "
|
||||
+ NUMPOINTS + " INTEGER, "
|
||||
|
||||
+45
-20
@@ -16,37 +16,62 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.data.models.ActivityType;
|
||||
import de.dennisguse.opentracks.databinding.ChooseActivityTypeBinding;
|
||||
import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||
|
||||
/**
|
||||
* A DialogFragment to choose an activity type.
|
||||
*/
|
||||
public class ChooseActivityTypeDialogFragment extends DialogFragment implements AdapterView.OnItemClickListener {
|
||||
|
||||
private static final String CHOOSE_ACTIVITY_TYPE_DIALOG_TAG = "chooseActivityType";
|
||||
|
||||
public static void showDialog(FragmentManager fragmentManager, String preselectedCategory) {
|
||||
new ChooseActivityTypeDialogFragment(preselectedCategory).show(fragmentManager, ChooseActivityTypeDialogFragment.CHOOSE_ACTIVITY_TYPE_DIALOG_TAG);
|
||||
@Deprecated
|
||||
public static void showDialog(FragmentManager fragmentManager, Context context, String activityTypeLocalized) {
|
||||
ActivityType activityType = ActivityType.findByLocalizedString(context, activityTypeLocalized);
|
||||
showDialog(fragmentManager, activityType);
|
||||
}
|
||||
|
||||
private static int getPosition(Context context, String category) {
|
||||
if (category == null) {
|
||||
public static void showDialog(FragmentManager fragmentManager, ActivityType activityType) {
|
||||
new ChooseActivityTypeDialogFragment(activityType).show(fragmentManager, ChooseActivityTypeDialogFragment.CHOOSE_ACTIVITY_TYPE_DIALOG_TAG);
|
||||
}
|
||||
|
||||
private static final List<ActivityType> activityTypes = List.of(
|
||||
ActivityType.UNKNOWN,
|
||||
ActivityType.AIRPLANE,
|
||||
ActivityType.BIKING,
|
||||
ActivityType.MOUNTAIN_BIKING,
|
||||
ActivityType.MOTOR_BIKE,
|
||||
ActivityType.KAYAKING,
|
||||
ActivityType.BOAT,
|
||||
ActivityType.SAILING,
|
||||
ActivityType.DRIVING,
|
||||
ActivityType.RUNNING,
|
||||
ActivityType.SNOW_BOARDING,
|
||||
ActivityType.SKIING,
|
||||
ActivityType.WALKING,
|
||||
ActivityType.ESCOOTER,
|
||||
ActivityType.INLINE_SKATING,
|
||||
ActivityType.SKATE_BOARDING,
|
||||
ActivityType.CLIMBING,
|
||||
ActivityType.SWIMMING,
|
||||
ActivityType.SWIMMING_OPEN,
|
||||
ActivityType.WORKOUT
|
||||
);
|
||||
|
||||
private static int getPosition(Context context, ActivityType activityType) {
|
||||
if (activityType == null) {
|
||||
return -1;
|
||||
}
|
||||
String iconValue = TrackIconUtils.getIconValue(context, category);
|
||||
|
||||
return TrackIconUtils.getAllIconValues().indexOf(iconValue);
|
||||
return activityTypes.indexOf(activityType);
|
||||
}
|
||||
|
||||
private ChooseActivityTypeBinding viewBinding;
|
||||
|
||||
private final String preselectedCategory;
|
||||
private final ActivityType preselectedActivityType;
|
||||
|
||||
private ChooseActivityTypeCaller chooseActivityTypeCaller;
|
||||
|
||||
private ChooseActivityTypeDialogFragment(String preselectedCategory) {
|
||||
this.preselectedCategory = preselectedCategory;
|
||||
private ChooseActivityTypeDialogFragment(ActivityType activityType) {
|
||||
this.preselectedActivityType = activityType;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -61,13 +86,13 @@ public class ChooseActivityTypeDialogFragment extends DialogFragment implements
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
viewBinding = ChooseActivityTypeBinding.inflate(inflater, container, false);
|
||||
|
||||
List<Integer> imageIds = new ArrayList<>();
|
||||
for (String iconValue : TrackIconUtils.getAllIconValues()) {
|
||||
imageIds.add(TrackIconUtils.getIconDrawable(iconValue));
|
||||
List<Integer> iconDrawableIds = new ArrayList<>();
|
||||
for (ActivityType activityType : activityTypes) {
|
||||
iconDrawableIds.add(activityType.getIconDrawableId());
|
||||
}
|
||||
|
||||
final ChooseActivityTypeImageAdapter imageAdapter = new ChooseActivityTypeImageAdapter(imageIds);
|
||||
int position = getPosition(getContext(), preselectedCategory);
|
||||
final ChooseActivityTypeImageAdapter imageAdapter = new ChooseActivityTypeImageAdapter(iconDrawableIds);
|
||||
int position = getPosition(getContext(), preselectedActivityType);
|
||||
if (position != -1) {
|
||||
imageAdapter.setSelected(position);
|
||||
}
|
||||
@@ -94,7 +119,7 @@ public class ChooseActivityTypeDialogFragment extends DialogFragment implements
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
|
||||
chooseActivityTypeCaller.onChooseActivityTypeDone(TrackIconUtils.getAllIconValues().get(position));
|
||||
chooseActivityTypeCaller.onChooseActivityTypeDone(activityTypes.get(position));
|
||||
dismiss();
|
||||
}
|
||||
|
||||
@@ -103,6 +128,6 @@ public class ChooseActivityTypeDialogFragment extends DialogFragment implements
|
||||
*/
|
||||
public interface ChooseActivityTypeCaller {
|
||||
|
||||
void onChooseActivityTypeDone(String iconValue);
|
||||
void onChooseActivityTypeDone(ActivityType activityType);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ class ChooseActivityTypeImageAdapter extends BaseAdapter {
|
||||
}
|
||||
|
||||
if (position == selected) {
|
||||
imageView.setBackgroundColor(ContextCompat.getColor(parent.getContext(), R.color.opentracks_secondary_color));
|
||||
imageView.setBackgroundColor(ContextCompat.getColor(parent.getContext(), R.color.opentracks));
|
||||
} else {
|
||||
imageView.setBackgroundColor(Color.TRANSPARENT);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package de.dennisguse.opentracks.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
@@ -28,12 +29,11 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.TrackRecordedActivity;
|
||||
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.data.models.ActivityType;
|
||||
import de.dennisguse.opentracks.data.models.DistanceFormatter;
|
||||
import de.dennisguse.opentracks.data.models.SpeedFormatter;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
@@ -43,7 +43,6 @@ import de.dennisguse.opentracks.settings.UnitSystem;
|
||||
import de.dennisguse.opentracks.stats.SensorStatistics;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.util.StringUtils;
|
||||
import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||
|
||||
/**
|
||||
* A fragment to display track statistics to the user for a recorded {@link Track}.
|
||||
@@ -89,7 +88,7 @@ public class StatisticsRecordedFragment extends Fragment {
|
||||
|
||||
if (PreferencesUtils.isKey(R.string.stats_rate_key, key) && track != null) {
|
||||
updateUInecessary = true;
|
||||
preferenceReportSpeed = PreferencesUtils.isReportSpeed(track.getCategory());
|
||||
preferenceReportSpeed = PreferencesUtils.isReportSpeed(track);
|
||||
}
|
||||
|
||||
if (key != null && updateUInecessary && isResumed()) {
|
||||
@@ -113,10 +112,6 @@ public class StatisticsRecordedFragment extends Fragment {
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
viewBinding = StatisticsRecordedBinding.inflate(inflater, container, false);
|
||||
|
||||
RecyclerView sensorsRecyclerView = viewBinding.statsSensorsRecyclerView;
|
||||
sensorsRecyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2));
|
||||
// sensorsRecyclerView.setAdapter(sensorsAdapter);
|
||||
|
||||
return viewBinding.getRoot();
|
||||
}
|
||||
|
||||
@@ -155,7 +150,7 @@ public class StatisticsRecordedFragment extends Fragment {
|
||||
|
||||
sensorStatistics = contentProviderUtils.getSensorStats(trackId);
|
||||
|
||||
boolean prefsChanged = this.track == null || (!this.track.getCategory().equals(track.getCategory()));
|
||||
boolean prefsChanged = this.track == null || (!this.track.getActivityTypeLocalized().equals(track.getActivityTypeLocalized()));
|
||||
this.track = track;
|
||||
if (prefsChanged) {
|
||||
sharedPreferenceChangeListener.onSharedPreferenceChanged(null, getString(R.string.stats_rate_key));
|
||||
@@ -191,8 +186,12 @@ public class StatisticsRecordedFragment extends Fragment {
|
||||
|
||||
// Set activity type
|
||||
{
|
||||
String trackIconValue = TrackIconUtils.getIconValue(getContext(), track.getCategory());
|
||||
viewBinding.statsActivityTypeIcon.setImageDrawable(ContextCompat.getDrawable(getContext(), TrackIconUtils.getIconDrawable(trackIconValue)));
|
||||
Context context = getContext();
|
||||
String localizedActivityType = track.getActivityTypeLocalized();
|
||||
String trackIconValue = ActivityType.findByLocalizedString(context, localizedActivityType)
|
||||
.getIconId();
|
||||
viewBinding.statsActivityTypeIcon.setImageDrawable(ContextCompat.getDrawable(getContext(), ActivityType.findBy(trackIconValue)
|
||||
.getIconDrawableId()));
|
||||
}
|
||||
|
||||
// Set time and start datetime
|
||||
@@ -253,6 +252,28 @@ public class StatisticsRecordedFragment extends Fragment {
|
||||
if (sensorStatistics == null) {
|
||||
return;
|
||||
}
|
||||
//TODO
|
||||
|
||||
if (sensorStatistics.hasHeartRate()) {
|
||||
String maxBPM = String.valueOf(Math.round(sensorStatistics.getMaxHeartRate().getBPM()));
|
||||
String avgBPM = String.valueOf(Math.round(sensorStatistics.getAvgHeartRate().getBPM()));
|
||||
|
||||
viewBinding.statsHeartRateGroup.setVisibility(View.VISIBLE);
|
||||
viewBinding.statsMaxHeartRateValue.setText(maxBPM);
|
||||
viewBinding.statsAvgHeartRateValue.setText(avgBPM);
|
||||
}
|
||||
if (sensorStatistics.hasCadence()) {
|
||||
String maxRPM = String.valueOf(Math.round(sensorStatistics.getMaxCadence().getRPM()));
|
||||
String avgRPM = String.valueOf(Math.round(sensorStatistics.getAvgCadence().getRPM()));
|
||||
|
||||
viewBinding.statsCadenceGroup.setVisibility(View.VISIBLE);
|
||||
viewBinding.statsMaxCadenceValue.setText(maxRPM);
|
||||
viewBinding.statsAvgCadenceValue.setText(avgRPM);
|
||||
}
|
||||
if (sensorStatistics.hasPower()) {
|
||||
String W = String.valueOf(Math.round(sensorStatistics.getAvgPower().getW()));
|
||||
|
||||
viewBinding.statsPowerGroup.setVisibility(View.VISIBLE);
|
||||
viewBinding.statsPowerValue.setText(W);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,9 +122,8 @@ public class StatisticsRecordingFragment extends Fragment {
|
||||
}
|
||||
recordingLayout = newRecordingLayout;
|
||||
|
||||
viewBinding.statsLayout.setColumnCount(recordingLayout.getColumnsPerRow());
|
||||
|
||||
viewBinding.statsLayout.removeAllViews(); //Let's start from scratch
|
||||
viewBinding.statsLayout.setColumnCount(recordingLayout.getColumnsPerRow());
|
||||
viewHolders.clear();
|
||||
|
||||
Map<String, Callable<StatisticViewHolder<?>>> m = Mapping.create(getContext());
|
||||
|
||||
@@ -20,15 +20,19 @@ public class TrackFilenameGenerator {
|
||||
|
||||
public static final String UUID_KEY = "{uuid}";
|
||||
public static final String TRACKNAME_KEY = "{name}";
|
||||
public static final String CATEGORY_KEY = "{category}";
|
||||
public static final String ACTIVITY_TYPE_KEY = "{category}";
|
||||
public static final String STARTTIME_TIME_KEY = "{time}";
|
||||
public static final String STARTTIME_DATE_KEY = "{date}";
|
||||
|
||||
public static String getAllOptions() {
|
||||
return Stream.of(UUID_KEY, TRACKNAME_KEY, CATEGORY_KEY, STARTTIME_TIME_KEY, STARTTIME_DATE_KEY)
|
||||
return Stream.of(UUID_KEY, TRACKNAME_KEY, ACTIVITY_TYPE_KEY, STARTTIME_TIME_KEY, STARTTIME_DATE_KEY)
|
||||
.collect(Collectors.joining(", "));
|
||||
}
|
||||
|
||||
public static String format(@NonNull String name, @NonNull TrackFileFormat trackFileFormat) {
|
||||
return FileUtils.sanitizeFileName(name + "." + trackFileFormat.getExtension());
|
||||
}
|
||||
|
||||
private final String template;
|
||||
|
||||
public TrackFilenameGenerator(@NonNull String template) {
|
||||
@@ -40,11 +44,11 @@ public class TrackFilenameGenerator {
|
||||
|
||||
values.put(UUID_KEY, track.getUuid().toString().substring(0, 8));
|
||||
values.put(TRACKNAME_KEY, track.getName());
|
||||
values.put(CATEGORY_KEY, track.getCategory());
|
||||
values.put(ACTIVITY_TYPE_KEY, track.getActivityTypeLocalized());
|
||||
values.put(STARTTIME_TIME_KEY, track.getStartTime().toLocalTime().toString());
|
||||
values.put(STARTTIME_DATE_KEY, track.getStartTime().toLocalDate().toString());
|
||||
|
||||
return FileUtils.sanitizeFileName(format(template, values)) + "." + trackFileFormat.getExtension();
|
||||
return format(format(template, values), trackFileFormat);
|
||||
}
|
||||
|
||||
private static String format(String template, Map<String, String> values) {
|
||||
@@ -77,10 +81,6 @@ public class TrackFilenameGenerator {
|
||||
return String.format(templateCompiled, valueList.toArray());
|
||||
}
|
||||
|
||||
public String getTemplate() {
|
||||
return template;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
try {
|
||||
getExample();
|
||||
|
||||
@@ -23,8 +23,6 @@ import androidx.annotation.NonNull;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Function;
|
||||
@@ -68,6 +66,9 @@ public class CSVTrackExporter implements TrackExporter {
|
||||
SPEED_FORMAT.setMaximumFractionDigits(2);
|
||||
SPEED_FORMAT.setGroupingUsed(false);
|
||||
|
||||
DISTANCE_FORMAT.setMaximumFractionDigits(0);
|
||||
DISTANCE_FORMAT.setGroupingUsed(false);
|
||||
|
||||
HEARTRATE_FORMAT.setMaximumFractionDigits(0);
|
||||
HEARTRATE_FORMAT.setGroupingUsed(false);
|
||||
|
||||
@@ -87,15 +88,23 @@ public class CSVTrackExporter implements TrackExporter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writeTrack(Track track, @NonNull OutputStream outputStream) {
|
||||
return writeTrack(new Track[]{track}, outputStream);
|
||||
}
|
||||
public boolean writeTrack(@NonNull List<Track> tracks, @NonNull OutputStream outputStream) {
|
||||
List<Column> columns = List.of(
|
||||
new Column("time", null),
|
||||
new Column("trackpoint_type", t -> quote(t.getType().name())),
|
||||
new Column("latitude", t -> t.hasLocation() ? COORDINATE_FORMAT.format(t.getLatitude()) : ""),
|
||||
new Column("longitude", t -> t.hasLocation() ? COORDINATE_FORMAT.format(t.getLongitude()) : ""),
|
||||
new Column("altitude", t -> t.hasAltitude() ? COORDINATE_FORMAT.format(t.getAltitude().toM()) : ""),
|
||||
new Column("accuracy_horizontal", t -> t.hasHorizontalAccuracy() ? DISTANCE_FORMAT.format(t.getHorizontalAccuracy().toM()) : ""),
|
||||
new Column("accuracy_vertical", t -> t.hasVerticalAccuracy() ? DISTANCE_FORMAT.format(t.getVerticalAccuracy().toM()) : ""),
|
||||
|
||||
@Override
|
||||
public boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream) {
|
||||
List<Column> columns = Collections.unmodifiableList(Arrays.asList(new Column("time", null), new Column("trackpoint_type", t -> quote(t.getType().name())), new Column("latitude", t -> t.hasLocation() ? COORDINATE_FORMAT.format(t.getLatitude()) : ""), new Column("longitude", t -> t.hasLocation() ? COORDINATE_FORMAT.format(t.getLongitude()) : ""), new Column("altitude", t -> t.hasAltitude() ? COORDINATE_FORMAT.format(t.getAltitude().toM()) : ""), new Column("accuracy_horizontal", t -> t.hasHorizontalAccuracy() ? DISTANCE_FORMAT.format(t.getHorizontalAccuracy().toM()) : ""), new Column("accuracy_vertical", t -> t.hasVerticalAccuracy() ? DISTANCE_FORMAT.format(t.getVerticalAccuracy().toM()) : ""),
|
||||
|
||||
new Column("speed", t -> t.hasSpeed() ? SPEED_FORMAT.format(t.getSpeed().toKMH()) : ""), new Column("altitude_gain", t -> t.hasAltitudeGain() ? DISTANCE_FORMAT.format(t.getAltitudeGain()) : ""), new Column("altitude_loss", t -> t.hasAltitudeLoss() ? DISTANCE_FORMAT.format(t.getAltitudeLoss()) : ""), new Column("sensor_distance", t -> t.hasSensorDistance() ? DISTANCE_FORMAT.format(t.getSensorDistance().toM()) : ""), new Column("heartrate", t -> t.hasHeartRate() ? HEARTRATE_FORMAT.format(t.getHeartRate().getBPM()) : ""), new Column("cadence", t -> t.hasCadence() ? CADENCE_FORMAT.format(t.getCadence().getRPM()) : ""), new Column("power", t -> t.hasPower() ? ALTITUDE_FORMAT.format(t.getPower().getW()) : "")));
|
||||
new Column("speed", t -> t.hasSpeed() ? SPEED_FORMAT.format(t.getSpeed().toKMH()) : ""),
|
||||
new Column("altitude_gain", t -> t.hasAltitudeGain() ? DISTANCE_FORMAT.format(t.getAltitudeGain()) : ""),
|
||||
new Column("altitude_loss", t -> t.hasAltitudeLoss() ? DISTANCE_FORMAT.format(t.getAltitudeLoss()) : ""),
|
||||
new Column("sensor_distance", t -> t.hasSensorDistance() ? DISTANCE_FORMAT.format(t.getSensorDistance().toM()) : ""),
|
||||
new Column("heartrate", t -> t.hasHeartRate() ? HEARTRATE_FORMAT.format(t.getHeartRate().getBPM()) : ""),
|
||||
new Column("cadence", t -> t.hasCadence() ? CADENCE_FORMAT.format(t.getCadence().getRPM()) : ""),
|
||||
new Column("power", t -> t.hasPower() ? ALTITUDE_FORMAT.format(t.getPower().getW()) : ""));
|
||||
|
||||
try {
|
||||
prepare(outputStream);
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package de.dennisguse.opentracks.io.file.exporter;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@@ -24,6 +23,7 @@ import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
@@ -31,14 +31,15 @@ import androidx.fragment.app.FragmentActivity;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.data.tables.TracksColumns;
|
||||
import de.dennisguse.opentracks.databinding.ExportActivityBinding;
|
||||
import de.dennisguse.opentracks.io.file.ErrorListDialog;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
import de.dennisguse.opentracks.io.file.TrackFilenameGenerator;
|
||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||
import de.dennisguse.opentracks.util.ExportUtils;
|
||||
import de.dennisguse.opentracks.util.FileUtils;
|
||||
@@ -47,12 +48,20 @@ import de.dennisguse.opentracks.util.FileUtils;
|
||||
* An activity for saving tracks to the external storage.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
* TODO: This class needs some refactoring.
|
||||
* * It pushes each export job (usually one Track) for export; although export could be run in parallel.
|
||||
* Also this requires that the ExportActivity stays in foreground, so the user has to activily wait.
|
||||
* It would be better to let the ExportService handle this and let it report progress / conflicts to ExportActivity
|
||||
* * File name conflicts are checked in this class instead of the ExportService.
|
||||
* So, for this check actually a different file name might be used than in the ExportService.
|
||||
* * Saved state as an object instead of individual values.
|
||||
*/
|
||||
public class ExportActivity extends FragmentActivity implements ExportServiceResultReceiver.Receiver {
|
||||
|
||||
private static final String TAG = ExportActivity.class.getSimpleName();
|
||||
|
||||
public static final String EXTRA_DIRECTORY_URI_KEY = "directory_uri";
|
||||
public static final String EXTRA_ONE_FILE_KEY = "one_file";
|
||||
public static final String EXTRA_TRACKFILEFORMAT_KEY = "trackfileformat";
|
||||
|
||||
private static final String BUNDLE_AUTO_CONFLICT = "auto_conflict";
|
||||
@@ -64,9 +73,13 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
||||
private static final String BUNDLE_DIRECTORY_FILES = "track_directory_files";
|
||||
private static final String BUNDLE_TRACK_ERRORS = "track_errors";
|
||||
|
||||
private static final int CONFLICT_NONE = 0;
|
||||
private static final int CONFLICT_OVERWRITE = 1;
|
||||
private static final int CONFLICT_SKIP = 2;
|
||||
private static final String BUNDLE_EXPORT_TASKS = "export_tasks";
|
||||
|
||||
private enum ConflictResolutionStrategy {
|
||||
CONFLICT_NONE,
|
||||
CONFLICT_OVERWRITE,
|
||||
CONFLICT_SKIP
|
||||
}
|
||||
|
||||
private TrackFileFormat trackFileFormat;
|
||||
private Uri directoryUri;
|
||||
@@ -87,12 +100,12 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
||||
|
||||
private ArrayList<String> trackErrors = new ArrayList<>();
|
||||
|
||||
private int autoConflict;
|
||||
private ConflictResolutionStrategy autoConflict;
|
||||
|
||||
private ContentProviderUtils contentProviderUtils;
|
||||
|
||||
// List of tracks to be exported.
|
||||
private final ArrayList<Track> tracks = new ArrayList<>();
|
||||
private ArrayList<ExportTask> exportTasks;
|
||||
|
||||
private final LinkedBlockingQueue<PendingConflict> conflictsQueue = new LinkedBlockingQueue<>();
|
||||
private final Handler conflictsHandler = new Handler();
|
||||
@@ -100,34 +113,36 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
||||
private final Runnable conflictsRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (conflictsQueue.size() > 0) {
|
||||
PendingConflict conflict = conflictsQueue.peek();
|
||||
if (conflict.resolve()) {
|
||||
conflictsQueue.remove(conflict);
|
||||
if (!conflictsQueue.isEmpty()) {
|
||||
conflictsHandler.post(conflictsRunnable);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
viewBinding.exportProgressLeftButton.setOnClickListener((view) -> {
|
||||
setConflictVisibility(View.GONE);
|
||||
conflict.skip();
|
||||
conflictsQueue.remove(conflict);
|
||||
if (!conflictsQueue.isEmpty()) {
|
||||
conflictsHandler.post(conflictsRunnable);
|
||||
}
|
||||
});
|
||||
|
||||
viewBinding.exportProgressRightButton.setOnClickListener((view) -> {
|
||||
setConflictVisibility(View.GONE);
|
||||
conflict.overwrite();
|
||||
conflictsQueue.remove(conflict);
|
||||
if (!conflictsQueue.isEmpty()) {
|
||||
conflictsHandler.post(conflictsRunnable);
|
||||
}
|
||||
});
|
||||
if (conflictsQueue.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PendingConflict conflict = conflictsQueue.peek();
|
||||
if (conflict.resolve()) {
|
||||
conflictsQueue.remove(conflict);
|
||||
if (!conflictsQueue.isEmpty()) {
|
||||
conflictsHandler.post(conflictsRunnable);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
viewBinding.exportProgressLeftButton.setOnClickListener((view) -> {
|
||||
setConflictVisibility(View.GONE);
|
||||
conflict.skip();
|
||||
conflictsQueue.remove(conflict);
|
||||
if (!conflictsQueue.isEmpty()) {
|
||||
conflictsHandler.post(conflictsRunnable);
|
||||
}
|
||||
});
|
||||
|
||||
viewBinding.exportProgressRightButton.setOnClickListener((view) -> {
|
||||
setConflictVisibility(View.GONE);
|
||||
conflict.overwrite();
|
||||
conflictsQueue.remove(conflict);
|
||||
if (!conflictsQueue.isEmpty()) {
|
||||
conflictsHandler.post(conflictsRunnable);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -139,6 +154,7 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
||||
|
||||
directoryUri = getIntent().getParcelableExtra(EXTRA_DIRECTORY_URI_KEY);
|
||||
trackFileFormat = (TrackFileFormat) getIntent().getSerializableExtra(EXTRA_TRACKFILEFORMAT_KEY);
|
||||
boolean allInOneFile = getIntent().getBooleanExtra(EXTRA_ONE_FILE_KEY, false);
|
||||
|
||||
contentProviderUtils = new ContentProviderUtils(this);
|
||||
|
||||
@@ -148,14 +164,17 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
||||
resultReceiver = new ExportServiceResultReceiver(new Handler(), this);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
autoConflict = CONFLICT_NONE;
|
||||
autoConflict = ConflictResolutionStrategy.CONFLICT_NONE;
|
||||
setProgress();
|
||||
new Thread(() -> {
|
||||
directoryFiles = ExportUtils.getAllFiles(ExportActivity.this, documentFile.getUri());
|
||||
runOnUiThread(() -> initExport(0));
|
||||
runOnUiThread(() -> {
|
||||
createExportTasks(allInOneFile);
|
||||
nextExport(null);
|
||||
});
|
||||
}).start();
|
||||
} else {
|
||||
autoConflict = savedInstanceState.getInt(BUNDLE_AUTO_CONFLICT);
|
||||
autoConflict = ConflictResolutionStrategy.valueOf(savedInstanceState.getString(BUNDLE_AUTO_CONFLICT));
|
||||
trackExportSuccessCount = savedInstanceState.getInt(BUNDLE_SUCCESS_COUNT);
|
||||
trackExportErrorCount = savedInstanceState.getInt(BUNDLE_ERROR_COUNT);
|
||||
trackExportOverwrittenCount = savedInstanceState.getInt(BUNDLE_OVERWRITTEN_COUNT);
|
||||
@@ -163,19 +182,19 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
||||
trackExportTotalCount = savedInstanceState.getInt(BUNDLE_TOTAL_COUNT);
|
||||
directoryFiles = savedInstanceState.getStringArrayList(BUNDLE_DIRECTORY_FILES);
|
||||
trackErrors = savedInstanceState.getStringArrayList(BUNDLE_TRACK_ERRORS);
|
||||
|
||||
exportTasks = new ArrayList<>(savedInstanceState.getParcelableArrayList(BUNDLE_EXPORT_TASKS));
|
||||
setProgress();
|
||||
initExport(getTotalDone());
|
||||
nextExport(null);
|
||||
}
|
||||
|
||||
viewBinding.bottomAppBarLayout.bottomAppBarTitle.setText(getString(R.string.export_progress_message, directoryDisplayName));
|
||||
viewBinding.exportActivityToolbar.setTitle(getString(R.string.export_progress_message, directoryDisplayName));
|
||||
viewBinding.bottomAppBarLayout.bottomAppBar.setNavigationIcon(R.drawable.ic_logo_color_24dp);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putInt(BUNDLE_AUTO_CONFLICT, autoConflict);
|
||||
outState.putString(BUNDLE_AUTO_CONFLICT, autoConflict.name());
|
||||
outState.putInt(BUNDLE_SUCCESS_COUNT, trackExportSuccessCount);
|
||||
outState.putInt(BUNDLE_ERROR_COUNT, trackExportErrorCount);
|
||||
outState.putInt(BUNDLE_OVERWRITTEN_COUNT, trackExportOverwrittenCount);
|
||||
@@ -183,13 +202,14 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
||||
outState.putInt(BUNDLE_TOTAL_COUNT, trackExportTotalCount);
|
||||
outState.putStringArrayList(BUNDLE_DIRECTORY_FILES, (ArrayList<String>) directoryFiles);
|
||||
outState.putStringArrayList(BUNDLE_TRACK_ERRORS, trackErrors);
|
||||
outState.putParcelableArrayList(BUNDLE_EXPORT_TASKS, exportTasks);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
conflictsQueue.clear();
|
||||
tracks.clear();
|
||||
exportTasks.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -202,57 +222,50 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
||||
this.doubleBackToCancel = true;
|
||||
Toast.makeText(this, getString(R.string.generic_click_twice_cancel), Toast.LENGTH_SHORT).show();
|
||||
|
||||
new Handler().postDelayed(() -> doubleBackToCancel=false, 2000);
|
||||
new Handler().postDelayed(() -> doubleBackToCancel = false, 2000);
|
||||
}
|
||||
|
||||
private void initExport(int from) {
|
||||
try (Cursor cursor = contentProviderUtils.getTrackCursor(null, null, TracksColumns._ID)) {
|
||||
if (cursor == null) {
|
||||
onExportEnded();
|
||||
return;
|
||||
}
|
||||
|
||||
trackExportTotalCount = cursor.getCount();
|
||||
viewBinding.exportProgressTotal.setText("" + trackExportTotalCount);
|
||||
for (int i = from; i < trackExportTotalCount; i++) {
|
||||
cursor.moveToPosition(i);
|
||||
Track track = ContentProviderUtils.createTrack(cursor);
|
||||
tracks.add(track);
|
||||
}
|
||||
|
||||
if (!tracks.isEmpty()) {
|
||||
export(tracks.get(0));
|
||||
} else {
|
||||
onExportEnded();
|
||||
}
|
||||
private void createExportTasks(boolean allInOneFile) {
|
||||
List<Track> tracks = contentProviderUtils.getTracks();
|
||||
exportTasks = new ArrayList<>();
|
||||
if (allInOneFile) {
|
||||
String filename = "OpenTracks-Backup";
|
||||
exportTasks.add(new ExportTask(filename, trackFileFormat, tracks.stream().map(Track::getId).collect(Collectors.toList())));
|
||||
} else {
|
||||
exportTasks.addAll(tracks.stream().map(it -> new ExportTask(null, trackFileFormat, List.of(it.getId()))).collect(Collectors.toList()));
|
||||
}
|
||||
trackExportTotalCount = exportTasks.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue track identified by UUID to be exported if not exported already or there is a conflict resolution.
|
||||
*
|
||||
* @param track Track object.
|
||||
* @param conflictResolution conflict resolution to be applied if needed.
|
||||
*/
|
||||
private void export(Track track, int conflictResolution) {
|
||||
boolean fileExists = exportFileExists(track);
|
||||
private void export(ExportTask exportTask, ConflictResolutionStrategy conflictResolution) {
|
||||
boolean fileExists = exportFileExists(exportTask);
|
||||
|
||||
if (fileExists && conflictResolution == CONFLICT_NONE) {
|
||||
conflict(track);
|
||||
} else if (fileExists && conflictResolution == CONFLICT_SKIP) {
|
||||
if (fileExists && conflictResolution == ConflictResolutionStrategy.CONFLICT_NONE) {
|
||||
conflict(exportTask);
|
||||
} else if (fileExists && conflictResolution == ConflictResolutionStrategy.CONFLICT_SKIP) {
|
||||
trackExportSkippedCount++;
|
||||
onExportCompleted(track);
|
||||
nextExport(exportTask);
|
||||
} else {
|
||||
ExportService.enqueue(this, resultReceiver, track.getId(), trackFileFormat, directoryUri);
|
||||
ExportService.enqueue(this, resultReceiver, exportTask, directoryUri);
|
||||
}
|
||||
}
|
||||
|
||||
private void export(Track track) {
|
||||
export(track, autoConflict);
|
||||
private void export(ExportTask exportTask) {
|
||||
export(exportTask, autoConflict);
|
||||
}
|
||||
|
||||
private boolean exportFileExists(Track track) {
|
||||
String filename = PreferencesUtils.getTrackFileformatGenerator().format(track, trackFileFormat);
|
||||
@Deprecated //TODO Check should be done in ExportService
|
||||
private boolean exportFileExists(ExportTask exportTask) {
|
||||
String filename;
|
||||
if (exportTask.isMultiExport()) {
|
||||
filename = TrackFilenameGenerator.format(exportTask.getFilename(), exportTask.getTrackFileFormat());
|
||||
} else {
|
||||
Track track = contentProviderUtils.getTrack(exportTask.getTrackIds().get(0));
|
||||
filename = PreferencesUtils.getTrackFileformatGenerator().format(track, trackFileFormat);
|
||||
}
|
||||
return directoryFiles.stream().anyMatch(filename::equals);
|
||||
}
|
||||
|
||||
@@ -269,31 +282,29 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
||||
}
|
||||
|
||||
private void setProgress() {
|
||||
int done = getTotalDone();
|
||||
|
||||
viewBinding.exportProgressDone.setText("" + done);
|
||||
viewBinding.exportProgressDone.setText("" + getTotalDone());
|
||||
viewBinding.exportProgressTotal.setText("" + trackExportTotalCount);
|
||||
|
||||
viewBinding.exportProgressBar.setProgress((int) ((float) done / (float) trackExportTotalCount * 100f));
|
||||
viewBinding.exportProgressSummaryNew.setText(String.valueOf(trackExportSuccessCount));
|
||||
viewBinding.exportProgressSummaryOverwrite.setText(String.valueOf(trackExportOverwrittenCount));
|
||||
viewBinding.exportProgressSummarySkip.setText(String.valueOf(trackExportSkippedCount));
|
||||
viewBinding.exportProgressSummaryErrors.setText(String.valueOf(trackExportErrorCount));
|
||||
viewBinding.exportProgressBar.setProgress((int) ((float) getTotalDone() / (float) trackExportTotalCount * 100f));
|
||||
viewBinding.exportProgressSummaryNew.setText("" + trackExportSuccessCount);
|
||||
viewBinding.exportProgressSummaryOverwrite.setText("" + trackExportOverwrittenCount);
|
||||
viewBinding.exportProgressSummarySkip.setText("" + trackExportSkippedCount);
|
||||
viewBinding.exportProgressSummaryErrors.setText("" + trackExportErrorCount);
|
||||
viewBinding.exportProgressSummaryNewGroup.setVisibility(trackExportSuccessCount > 0 ? View.VISIBLE : View.GONE);
|
||||
viewBinding.exportProgressSummaryOverwriteGroup.setVisibility(trackExportOverwrittenCount > 0 ? View.VISIBLE : View.GONE);
|
||||
viewBinding.exportProgressSummarySkipGroup.setVisibility(trackExportSkippedCount > 0 ? View.VISIBLE : View.GONE);
|
||||
viewBinding.exportProgressSummaryErrorsGroup.setVisibility(trackExportErrorCount > 0 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
private void onExportCompleted(Track track) {
|
||||
tracks.remove(track);
|
||||
private void nextExport(@Nullable ExportTask exportTask) {
|
||||
exportTasks.remove(exportTask);
|
||||
|
||||
setProgress();
|
||||
if (tracks.isEmpty()) {
|
||||
if (exportTasks.isEmpty()) {
|
||||
onExportEnded();
|
||||
return;
|
||||
}
|
||||
export(tracks.get(0));
|
||||
export(exportTasks.get(0));
|
||||
}
|
||||
|
||||
private void onExportEnded() {
|
||||
@@ -318,30 +329,32 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExportSuccess(Track.Id trackId) {
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
|
||||
if (exportFileExists(track)) {
|
||||
public void onExportSuccess(ExportTask exportTask) {
|
||||
if (exportFileExists(exportTask)) {
|
||||
trackExportOverwrittenCount++;
|
||||
} else {
|
||||
trackExportSuccessCount++;
|
||||
}
|
||||
|
||||
onExportCompleted(track);
|
||||
nextExport(exportTask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExportError(Track.Id trackId) {
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
|
||||
public void onExportError(ExportTask exportTask) {
|
||||
trackExportErrorCount++;
|
||||
trackErrors.add(track.getName());
|
||||
String name;
|
||||
if (exportTask.isMultiExport()) {
|
||||
name = exportTask.getFilename();
|
||||
} else {
|
||||
name = contentProviderUtils.getTrack(exportTask.getTrackIds().get(0)).getName();
|
||||
}
|
||||
trackErrors.add(name);
|
||||
|
||||
onExportCompleted(track);
|
||||
nextExport(exportTask);
|
||||
}
|
||||
|
||||
private void conflict(Track track) {
|
||||
PendingConflict newConflict = new PendingConflict(track);
|
||||
private void conflict(ExportTask exportTask) {
|
||||
PendingConflict newConflict = new PendingConflict(exportTask);
|
||||
conflictsQueue.add(newConflict);
|
||||
|
||||
if (conflictsQueue.size() == 1) {
|
||||
@@ -353,10 +366,10 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
||||
* Handle conflicts (exporting file already exists).
|
||||
*/
|
||||
private class PendingConflict {
|
||||
private final Track track;
|
||||
private final ExportTask exportTask;
|
||||
|
||||
public PendingConflict(Track track) {
|
||||
this.track = track;
|
||||
public PendingConflict(ExportTask exportTask) {
|
||||
this.exportTask = exportTask;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -366,14 +379,20 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
||||
* @return true if it could resolve the conflict or false otherwise.
|
||||
*/
|
||||
public boolean resolve() {
|
||||
if (autoConflict == CONFLICT_NONE) {
|
||||
if (autoConflict == ConflictResolutionStrategy.CONFLICT_NONE) {
|
||||
viewBinding.exportProgressAlertIcon.setImageDrawable(ContextCompat.getDrawable(ExportActivity.this, R.drawable.ic_report_problem_24));
|
||||
viewBinding.exportProgressAlertMsg.setText(getString(R.string.export_track_already_exists_msg, track.getName()));
|
||||
String name;
|
||||
if (exportTask.isMultiExport()) {
|
||||
name = exportTask.getFilename();
|
||||
} else {
|
||||
name = contentProviderUtils.getTrack(exportTask.getTrackIds().get(0)).getName();
|
||||
}
|
||||
viewBinding.exportProgressAlertMsg.setText(getString(R.string.export_track_already_exists_msg, name));
|
||||
setConflictVisibility(View.VISIBLE);
|
||||
return false;
|
||||
}
|
||||
|
||||
export(track);
|
||||
export(exportTask);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -381,10 +400,10 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
||||
* Overwrite the export file and set the autoConflict if user set the "do it for all" switch button.
|
||||
*/
|
||||
public void overwrite() {
|
||||
export(track, CONFLICT_OVERWRITE);
|
||||
export(exportTask, ConflictResolutionStrategy.CONFLICT_OVERWRITE);
|
||||
|
||||
if (viewBinding.exportProgressApplyToAll.isChecked()) {
|
||||
autoConflict = CONFLICT_OVERWRITE;
|
||||
autoConflict = ConflictResolutionStrategy.CONFLICT_OVERWRITE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,10 +411,10 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
||||
* Skip the export file and set the autoConflict if user set the "do it for all" switch button.
|
||||
*/
|
||||
public void skip() {
|
||||
export(track, CONFLICT_SKIP);
|
||||
export(exportTask, ConflictResolutionStrategy.CONFLICT_SKIP);
|
||||
|
||||
if (viewBinding.exportProgressApplyToAll.isChecked()) {
|
||||
autoConflict = CONFLICT_SKIP;
|
||||
autoConflict = ConflictResolutionStrategy.CONFLICT_SKIP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,6 @@ import androidx.annotation.NonNull;
|
||||
import androidx.core.app.JobIntentService;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
import de.dennisguse.opentracks.util.ExportUtils;
|
||||
|
||||
public class ExportService extends JobIntentService {
|
||||
@@ -22,16 +19,14 @@ public class ExportService extends JobIntentService {
|
||||
private static final int JOB_ID = 1;
|
||||
|
||||
private static final String EXTRA_RECEIVER = "extra_receiver";
|
||||
private static final String EXTRA_TRACK_ID = "extra_track_id";
|
||||
private static final String EXTRA_TRACK_FILE_FORMAT = "extra_track_file_format";
|
||||
private static final String EXTRA_EXPORT_TASK = "export_task";
|
||||
private static final String EXTRA_DIRECTORY_URI = "extra_directory_uri";
|
||||
private static final String TAG = ExportService.class.getSimpleName();
|
||||
|
||||
public static void enqueue(Context context, ExportServiceResultReceiver receiver, Track.Id trackId, TrackFileFormat trackFileFormat, Uri directoryUri) {
|
||||
public static void enqueue(Context context, ExportServiceResultReceiver receiver, ExportTask exportTask, Uri directoryUri) {
|
||||
Intent intent = new Intent(context, JobService.class);
|
||||
intent.putExtra(EXTRA_RECEIVER, receiver);
|
||||
intent.putExtra(EXTRA_TRACK_ID, trackId);
|
||||
intent.putExtra(EXTRA_TRACK_FILE_FORMAT, trackFileFormat);
|
||||
intent.putExtra(EXTRA_EXPORT_TASK, exportTask);
|
||||
intent.putExtra(EXTRA_DIRECTORY_URI, directoryUri);
|
||||
enqueueWork(context, ExportService.class, JOB_ID, intent);
|
||||
}
|
||||
@@ -40,13 +35,12 @@ public class ExportService extends JobIntentService {
|
||||
protected void onHandleWork(@NonNull Intent intent) {
|
||||
// Get all data.
|
||||
ResultReceiver resultReceiver = intent.getParcelableExtra(EXTRA_RECEIVER);
|
||||
Track.Id trackId = intent.getParcelableExtra(EXTRA_TRACK_ID);
|
||||
TrackFileFormat trackFileFormat = (TrackFileFormat) intent.getSerializableExtra(EXTRA_TRACK_FILE_FORMAT);
|
||||
ExportTask exportTask = intent.getParcelableExtra(EXTRA_EXPORT_TASK);
|
||||
Uri directoryUri = intent.getParcelableExtra(EXTRA_DIRECTORY_URI);
|
||||
|
||||
// Prepare resultCode and bundle to send to the receiver.
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(ExportServiceResultReceiver.RESULT_EXTRA_TRACK_ID, trackId);
|
||||
bundle.putParcelable(ExportServiceResultReceiver.RESULT_EXTRA_EXPORT_TASK, exportTask);
|
||||
|
||||
// Build directory file.
|
||||
DocumentFile directoryFile = DocumentFile.fromTreeUri(this, directoryUri);
|
||||
@@ -57,9 +51,7 @@ public class ExportService extends JobIntentService {
|
||||
}
|
||||
|
||||
// Export.
|
||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(this);
|
||||
Track track = contentProviderUtils.getTrack(trackId);
|
||||
boolean success = ExportUtils.exportTrack(this, trackFileFormat, directoryFile, track);
|
||||
boolean success = ExportUtils.exportTrack(this, directoryFile, exportTask);
|
||||
|
||||
// Send result to the receiver.
|
||||
int resultCode = success ? ExportServiceResultReceiver.RESULT_CODE_SUCCESS : ExportServiceResultReceiver.RESULT_CODE_ERROR;
|
||||
|
||||
+6
-8
@@ -6,8 +6,6 @@ import android.os.ResultReceiver;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
|
||||
/**
|
||||
* Create a new ResultReceive to receive results.
|
||||
* Your {@link #onReceiveResult} method will be called from the thread running <var>handler</var> if given, or from an arbitrary thread if null.
|
||||
@@ -17,7 +15,7 @@ public class ExportServiceResultReceiver extends ResultReceiver {
|
||||
public static final int RESULT_CODE_SUCCESS = 1;
|
||||
public static final int RESULT_CODE_ERROR = 0;
|
||||
|
||||
public static final String RESULT_EXTRA_TRACK_ID = "result_extra_track_id";
|
||||
public static final String RESULT_EXTRA_EXPORT_TASK = "result_extra_export_task";
|
||||
|
||||
private final Receiver receiver;
|
||||
|
||||
@@ -28,19 +26,19 @@ public class ExportServiceResultReceiver extends ResultReceiver {
|
||||
|
||||
@Override
|
||||
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
||||
Track.Id trackId = resultData.getParcelable(ExportServiceResultReceiver.RESULT_EXTRA_TRACK_ID);
|
||||
ExportTask exportTask = resultData.getParcelable(ExportServiceResultReceiver.RESULT_EXTRA_EXPORT_TASK);
|
||||
switch (resultCode) {
|
||||
case RESULT_CODE_SUCCESS -> receiver.onExportSuccess(trackId);
|
||||
case RESULT_CODE_ERROR -> receiver.onExportError(trackId);
|
||||
case RESULT_CODE_SUCCESS -> receiver.onExportSuccess(exportTask);
|
||||
case RESULT_CODE_ERROR -> receiver.onExportError(exportTask);
|
||||
default -> throw new RuntimeException("Unknown resultCode.");
|
||||
}
|
||||
}
|
||||
|
||||
public interface Receiver {
|
||||
default void onExportSuccess(Track.Id trackId) {
|
||||
default void onExportSuccess(ExportTask exportTask) {
|
||||
}
|
||||
|
||||
default void onExportError(Track.Id trackId) {
|
||||
default void onExportError(ExportTask exportTask) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package de.dennisguse.opentracks.io.file.exporter;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||
|
||||
public class ExportTask implements Parcelable {
|
||||
|
||||
private final String filename; //TODO Name will only be used when exporting multiple tracks
|
||||
|
||||
private final TrackFileFormat trackFileFormat;
|
||||
|
||||
private final List<Track.Id> trackIds;
|
||||
|
||||
public ExportTask(@Nullable String filename, @NonNull TrackFileFormat trackFileFormat, @NonNull List<Track.Id> trackIds) {
|
||||
this.filename = filename;
|
||||
this.trackFileFormat = trackFileFormat;
|
||||
this.trackIds = trackIds;
|
||||
}
|
||||
|
||||
protected ExportTask(Parcel in) {
|
||||
filename = in.readString();
|
||||
trackFileFormat = TrackFileFormat.valueOf(in.readString());
|
||||
trackIds = in.createTypedArrayList(Track.Id.CREATOR);
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
public TrackFileFormat getTrackFileFormat() {
|
||||
return trackFileFormat;
|
||||
}
|
||||
|
||||
public List<Track.Id> getTrackIds() {
|
||||
return trackIds;
|
||||
}
|
||||
|
||||
public boolean isMultiExport() {
|
||||
return trackIds.size() > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ExportTask that = (ExportTask) o;
|
||||
return Objects.equals(filename, that.filename) && trackFileFormat == that.trackFileFormat && Objects.equals(trackIds, that.trackIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(filename, trackFileFormat, trackIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(filename);
|
||||
dest.writeString(trackFileFormat.name());
|
||||
dest.writeTypedList(trackIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Creator<ExportTask> CREATOR = new Creator<>() {
|
||||
@Override
|
||||
public ExportTask createFromParcel(Parcel in) {
|
||||
return new ExportTask(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExportTask[] newArray(int size) {
|
||||
return new ExportTask[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -98,12 +98,7 @@ public class GPXTrackExporter implements TrackExporter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writeTrack(Track track, @NonNull OutputStream outputStream) {
|
||||
return writeTrack(new Track[]{track}, outputStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream) {
|
||||
public boolean writeTrack(List<Track> tracks, @NonNull OutputStream outputStream) {
|
||||
try {
|
||||
prepare(outputStream);
|
||||
writeHeader();
|
||||
@@ -156,8 +151,12 @@ public class GPXTrackExporter implements TrackExporter {
|
||||
if (wroteSegment) writeCloseSegment();
|
||||
writeOpenSegment();
|
||||
wroteSegment = true;
|
||||
trackDistance = trackDistance.plus(writeTrackPoint(track.getZoneOffset(), trackPoint, sensorPoints, trackDistance));
|
||||
sensorPoints.clear();
|
||||
if (trackPoint.hasLocation()) {
|
||||
trackDistance = trackDistance.plus(writeTrackPoint(track.getZoneOffset(), trackPoint, sensorPoints, trackDistance));
|
||||
sensorPoints.clear();
|
||||
} else {
|
||||
sensorPoints.add(trackPoint);
|
||||
}
|
||||
}
|
||||
case SENSORPOINT -> sensorPoints.add(trackPoint);
|
||||
case TRACKPOINT -> {
|
||||
@@ -273,7 +272,7 @@ public class GPXTrackExporter implements TrackExporter {
|
||||
printWriter.println("<trk>");
|
||||
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
|
||||
printWriter.println("<desc>" + StringUtils.formatCData(track.getDescription()) + "</desc>");
|
||||
printWriter.println("<type>" + StringUtils.formatCData(track.getCategory()) + "</type>");
|
||||
printWriter.println("<type>" + StringUtils.formatCData(track.getActivityTypeLocalized()) + "</type>");
|
||||
|
||||
printWriter.println("<extensions>");
|
||||
printWriter.println("<topografix:color>c0c0c0</topografix:color>");
|
||||
|
||||
@@ -45,7 +45,7 @@ import de.dennisguse.opentracks.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Convert {@link Track} incl. {@link Marker} and {@link TrackPoint} to KML version 2.3.
|
||||
* https://docs.opengeospatial.org/is/12-007r2/12-007r2.html
|
||||
* <a href="https://docs.opengeospatial.org/is/12-007r2/12-007r2.html">...</a>
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
* @author Rodrigo Damazio
|
||||
@@ -59,7 +59,7 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
private static final String TRACK_STYLE = "track";
|
||||
private static final String SCHEMA_ID = "schema";
|
||||
|
||||
public static final String EXTENDED_DATA_TYPE_CATEGORY = "type";
|
||||
public static final String EXTENDED_DATA_TYPE_ACTIVITYTYPE = "type";
|
||||
|
||||
public static final String EXTENDED_DATA_TYPE_SPEED = "speed";
|
||||
public static final String EXTENDED_DATA_TYPE_DISTANCE = "distance";
|
||||
@@ -99,18 +99,14 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
this.contentProviderUtils = contentProviderUtils;
|
||||
}
|
||||
|
||||
public boolean writeTrack(Track track, @NonNull OutputStream outputStream) {
|
||||
return writeTrack(new Track[]{track}, outputStream);
|
||||
}
|
||||
|
||||
public boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream) {
|
||||
public boolean writeTrack(List<Track> tracks, @NonNull OutputStream outputStream) {
|
||||
try {
|
||||
prepare(outputStream);
|
||||
writeHeader(tracks);
|
||||
for (Track track : tracks) {
|
||||
writeMarkers(track);
|
||||
}
|
||||
boolean hasMultipleTracks = tracks.length > 1;
|
||||
boolean hasMultipleTracks = tracks.size() > 1;
|
||||
if (hasMultipleTracks) {
|
||||
writeMultiTrackBegin();
|
||||
}
|
||||
@@ -222,7 +218,7 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
}
|
||||
}
|
||||
|
||||
private void writeHeader(Track[] tracks) {
|
||||
private void writeHeader(List<Track> tracks) {
|
||||
if (printWriter != null) {
|
||||
printWriter.println(
|
||||
"""
|
||||
@@ -241,7 +237,7 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
printWriter.println("<open>1</open>");
|
||||
printWriter.println("<visibility>1</visibility>");
|
||||
|
||||
Track track = tracks[0];
|
||||
Track track = tracks.get(0);
|
||||
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
|
||||
printWriter.println("<atom:generator>" + StringUtils.formatCData(context.getString(R.string.app_name)) + "</atom:generator>");
|
||||
|
||||
@@ -293,7 +289,7 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
|
||||
private void writeMultiTrackBegin() {
|
||||
if (printWriter != null) {
|
||||
printWriter.println("<Folder id=tour>");
|
||||
printWriter.println("<Folder id=\"tracks\">");
|
||||
printWriter.println("<name>" + context.getString(R.string.generic_tracks) + "</name>");
|
||||
printWriter.println("<open>1</open>");
|
||||
}
|
||||
@@ -311,11 +307,11 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
|
||||
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
|
||||
printWriter.println("<description>" + StringUtils.formatCData(track.getDescription()) + "</description>");
|
||||
printWriter.println("<icon>" + StringUtils.formatCData(track.getIcon()) + "</icon>");
|
||||
printWriter.println("<icon>" + StringUtils.formatCData(track.getActivityType().getIconId()) + "</icon>");
|
||||
printWriter.println("<opentracks:trackid>" + track.getUuid() + "</opentracks:trackid>");
|
||||
|
||||
printWriter.println("<styleUrl>#" + TRACK_STYLE + "</styleUrl>");
|
||||
writeCategory(track.getCategory());
|
||||
writeActivityType(track.getActivityTypeLocalized());
|
||||
printWriter.println("<MultiTrack>");
|
||||
printWriter.println("<altitudeMode>absolute</altitudeMode>");
|
||||
printWriter.println("<interpolate>1</interpolate>");
|
||||
@@ -430,19 +426,19 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
/**
|
||||
* Writes a placemark.
|
||||
*
|
||||
* @param name the name
|
||||
* @param category the category
|
||||
* @param description the description
|
||||
* @param location the location
|
||||
* @param name the name
|
||||
* @param activityType the activityType
|
||||
* @param description the description
|
||||
* @param location the location
|
||||
*/
|
||||
private void writePlacemark(String name, String category, String description, Location location, ZoneOffset zoneOffset) {
|
||||
private void writePlacemark(String name, String activityType, String description, Location location, ZoneOffset zoneOffset) {
|
||||
if (location != null) {
|
||||
printWriter.println("<Placemark>");
|
||||
printWriter.println("<name>" + StringUtils.formatCData(name) + "</name>");
|
||||
printWriter.println("<description>" + StringUtils.formatCData(description) + "</description>");
|
||||
printWriter.println("<TimeStamp><when>" + getTime(zoneOffset, location) + "</when></TimeStamp>");
|
||||
printWriter.println("<styleUrl>#" + KMLTrackExporter.MARKER_STYLE + "</styleUrl>");
|
||||
writeCategory(category);
|
||||
writeActivityType(activityType);
|
||||
printWriter.println("<Point>");
|
||||
printWriter.println("<coordinates>" + getCoordinates(location, ",") + "</coordinates>");
|
||||
printWriter.println("</Point>");
|
||||
@@ -463,7 +459,7 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
printWriter.println("</Camera>");
|
||||
printWriter.println("<TimeStamp><when>" + getTime(zoneOffset, marker.getLocation()) + "</when></TimeStamp>");
|
||||
printWriter.println("<styleUrl>#" + MARKER_STYLE + "</styleUrl>");
|
||||
writeCategory(marker.getCategory());
|
||||
writeActivityType(marker.getCategory());
|
||||
|
||||
if (exportPhotos) {
|
||||
printWriter.println("<Icon><href>" + KmzTrackExporter.buildKmzImageFilePath(marker) + "</href></Icon>");
|
||||
@@ -518,23 +514,15 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the category.
|
||||
*
|
||||
* @param category the category
|
||||
*/
|
||||
private void writeCategory(String category) {
|
||||
if (category == null || category.equals("")) {
|
||||
private void writeActivityType(String activityTypeLocalized) {
|
||||
if (activityTypeLocalized == null || activityTypeLocalized.equals("")) {
|
||||
return;
|
||||
}
|
||||
printWriter.println("<ExtendedData>");
|
||||
printWriter.println("<Data name=\"" + EXTENDED_DATA_TYPE_CATEGORY + "\"><value>" + StringUtils.formatCData(category) + "</value></Data>");
|
||||
printWriter.println("<Data name=\"" + EXTENDED_DATA_TYPE_ACTIVITYTYPE + "\"><value>" + StringUtils.formatCData(activityTypeLocalized) + "</value></Data>");
|
||||
printWriter.println("</ExtendedData>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the track style.
|
||||
*/
|
||||
private void writeTrackStyle() {
|
||||
printWriter.println("<Style id=\"" + TRACK_STYLE + "\">");
|
||||
printWriter.println("<LineStyle><color>7f0000ff</color><width>4</width></LineStyle>");
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
@@ -64,12 +65,7 @@ public class KmzTrackExporter implements TrackExporter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writeTrack(Track track, @NonNull OutputStream outputStream) {
|
||||
return writeTrack(new Track[]{track}, outputStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream) {
|
||||
public boolean writeTrack(List<Track> tracks, @NonNull OutputStream outputStream) {
|
||||
try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
|
||||
// Add kml file
|
||||
ZipEntry zipEntry = new ZipEntry(KMZ_KML_FILE);
|
||||
@@ -91,7 +87,7 @@ public class KmzTrackExporter implements TrackExporter {
|
||||
}
|
||||
}
|
||||
|
||||
private void addImages(Context context, Track[] tracks, ZipOutputStream zipOutputStream) throws InterruptedException, IOException {
|
||||
private void addImages(Context context, List<Track> tracks, ZipOutputStream zipOutputStream) throws InterruptedException, IOException {
|
||||
for (Track track : tracks) {
|
||||
try (Cursor cursor = contentProviderUtils.getMarkerCursor(track.getId(), null, -1)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
@@ -145,6 +141,6 @@ public class KmzTrackExporter implements TrackExporter {
|
||||
public static String buildKmzImageFilePath(Marker marker) {
|
||||
String ext = FileUtils.getExtension(marker.getPhotoUrl());
|
||||
ext = ext == null ? "" : "." + ext;
|
||||
return KMZ_IMAGES_DIR + File.separatorChar + FileUtils.sanitizeFileName(marker.getId().getId() + ext);
|
||||
return KMZ_IMAGES_DIR + File.separatorChar + FileUtils.sanitizeFileName(marker.getId().id() + ext);
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package de.dennisguse.opentracks.io.file.exporter;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
|
||||
@@ -29,7 +30,5 @@ import de.dennisguse.opentracks.data.models.Track;
|
||||
*/
|
||||
public interface TrackExporter {
|
||||
|
||||
boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream);
|
||||
|
||||
boolean writeTrack(Track track, @NonNull OutputStream outputStream);
|
||||
boolean writeTrack(List<Track> tracks, @NonNull OutputStream outputStream);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user