mirror of https://github.com/tasks/tasks
New tests project, + legacy data structures for testing importing.
parent
0e1f0b4a8f
commit
bb0d0e0354
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" path="src"/>
|
||||||
|
<classpathentry kind="src" path="gen"/>
|
||||||
|
<classpathentry kind="src" path="plugin-src"/>
|
||||||
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||||
|
<classpathentry combineaccessrules="false" kind="src" path="/astrid-3.x"/>
|
||||||
|
<classpathentry kind="output" path="ecbuild"/>
|
||||||
|
</classpath>
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>astrid-3.x-tests</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
@ -0,0 +1,270 @@
|
|||||||
|
#Sat Aug 22 23:48:16 PDT 2009
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||||
|
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||||
|
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||||
|
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||||
|
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||||
|
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||||
|
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||||
|
org.eclipse.jdt.core.compiler.source=1.5
|
||||||
|
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
|
||||||
|
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
|
||||||
|
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
|
||||||
|
org.eclipse.jdt.core.formatter.comment.format_header=false
|
||||||
|
org.eclipse.jdt.core.formatter.comment.format_html=true
|
||||||
|
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
|
||||||
|
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
|
||||||
|
org.eclipse.jdt.core.formatter.comment.format_source_code=true
|
||||||
|
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
|
||||||
|
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
|
||||||
|
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
|
||||||
|
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
|
||||||
|
org.eclipse.jdt.core.formatter.comment.line_length=80
|
||||||
|
org.eclipse.jdt.core.formatter.compact_else_if=true
|
||||||
|
org.eclipse.jdt.core.formatter.continuation_indentation=2
|
||||||
|
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
|
||||||
|
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
|
||||||
|
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
|
||||||
|
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
|
||||||
|
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
|
||||||
|
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
|
||||||
|
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
|
||||||
|
org.eclipse.jdt.core.formatter.indent_empty_lines=false
|
||||||
|
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
|
||||||
|
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
|
||||||
|
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
|
||||||
|
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
|
||||||
|
org.eclipse.jdt.core.formatter.indentation.size=4
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
|
||||||
|
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
|
||||||
|
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
|
||||||
|
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
|
||||||
|
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
|
||||||
|
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
|
||||||
|
org.eclipse.jdt.core.formatter.lineSplit=80
|
||||||
|
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
|
||||||
|
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
|
||||||
|
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
|
||||||
|
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
|
||||||
|
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
|
||||||
|
org.eclipse.jdt.core.formatter.tabulation.char=space
|
||||||
|
org.eclipse.jdt.core.formatter.tabulation.size=4
|
||||||
|
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
||||||
|
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
#Sat Aug 22 23:48:16 PDT 2009
|
||||||
|
cleanup_settings_version=2
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
formatter_profile=_Astrid
|
||||||
|
formatter_settings_version=11
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
# We only want this apk build for tests.
|
||||||
|
LOCAL_MODULE_TAGS := tests
|
||||||
|
|
||||||
|
LOCAL_JAVA_LIBRARIES := android.test.runner
|
||||||
|
|
||||||
|
# Include all test java files.
|
||||||
|
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
||||||
|
|
||||||
|
# Notice that we don't have to include the src files of ApiDemos because, by
|
||||||
|
# running the tests using an instrumentation targeting ApiDemos, we
|
||||||
|
# automatically get all of its classes loaded into our environment.
|
||||||
|
|
||||||
|
LOCAL_PACKAGE_NAME := AstridTests
|
||||||
|
|
||||||
|
LOCAL_INSTRUMENTATION_FOR := Astrid
|
||||||
|
|
||||||
|
LOCAL_SDK_VERSION := current
|
||||||
|
|
||||||
|
include $(BUILD_PACKAGE)
|
||||||
|
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.todoroo.astrid.tests"
|
||||||
|
android:versionCode="1"
|
||||||
|
android:versionName="1.0">
|
||||||
|
|
||||||
|
<uses-sdk android:minSdkVersion="3" />
|
||||||
|
|
||||||
|
<!-- We add an application tag here just so that we can indicate that
|
||||||
|
this package needs to link against the android.test library,
|
||||||
|
which is needed when building test cases. -->
|
||||||
|
<application>
|
||||||
|
<uses-library android:name="android.test.runner" />
|
||||||
|
</application>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
This declares that this application uses the instrumentation test runner targeting
|
||||||
|
the package of the parent app. To run the tests use the command:
|
||||||
|
"adb shell am instrument -w com.xxx.xxx.tests/android.test.InstrumentationTestRunner"
|
||||||
|
-->
|
||||||
|
<instrumentation android:name="android.test.InstrumentationTestRunner"
|
||||||
|
android:targetPackage="com.todoroo.astrid"
|
||||||
|
android:label="Tests for Astrid"/>
|
||||||
|
</manifest>
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
# This file is used to override default values used by the Ant build system.
|
||||||
|
#
|
||||||
|
# This file must be checked in Version Control Systems, as it is
|
||||||
|
# integral to the build system of your project.
|
||||||
|
|
||||||
|
# The name of your application package as defined in the manifest.
|
||||||
|
# Used by the 'uninstall' rule.
|
||||||
|
#application-package=com.example.myproject
|
||||||
|
|
||||||
|
# The name of the source folder.
|
||||||
|
#source-folder=src
|
||||||
|
|
||||||
|
# The name of the output folder.
|
||||||
|
#out-folder=bin
|
||||||
|
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project name="Main" default="help">
|
||||||
|
|
||||||
|
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||||
|
It contain the path to the SDK. It should *NOT* be checked in in Version
|
||||||
|
Control Systems. -->
|
||||||
|
<property file="local.properties"/>
|
||||||
|
|
||||||
|
<!-- The build.properties file can be created by you and is never touched
|
||||||
|
by the 'android' tool. This is the place to change some of the default property values
|
||||||
|
used by the Ant rules.
|
||||||
|
Here are some properties you may want to change/update:
|
||||||
|
|
||||||
|
application-package
|
||||||
|
the name of your application package as defined in the manifest. Used by the
|
||||||
|
'uninstall' rule.
|
||||||
|
source-folder
|
||||||
|
the name of the source folder. Default is 'src'.
|
||||||
|
out-folder
|
||||||
|
the name of the output folder. Default is 'bin'.
|
||||||
|
|
||||||
|
Properties related to the SDK location or the project target should be updated
|
||||||
|
using the 'android' tool with the 'update' action.
|
||||||
|
|
||||||
|
This file is an integral part of the build system for your application and
|
||||||
|
should be checked in in Version Control Systems.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<property file="build.properties"/>
|
||||||
|
|
||||||
|
<!-- The default.properties file is created and updated by the 'android' tool, as well
|
||||||
|
as ADT.
|
||||||
|
This file is an integral part of the build system for your application and
|
||||||
|
should be checked in in Version Control Systems. -->
|
||||||
|
<property file="default.properties"/>
|
||||||
|
|
||||||
|
<!-- Custom Android task to deal with the project target, and import the proper rules.
|
||||||
|
This requires ant 1.6.0 or above. -->
|
||||||
|
<path id="android.antlibs">
|
||||||
|
<pathelement path="${sdk-location}/tools/lib/anttasks.jar" />
|
||||||
|
<pathelement path="${sdk-location}/tools/lib/sdklib.jar" />
|
||||||
|
<pathelement path="${sdk-location}/tools/lib/androidprefs.jar" />
|
||||||
|
<pathelement path="${sdk-location}/tools/lib/apkbuilder.jar" />
|
||||||
|
<pathelement path="${sdk-location}/tools/lib/jarutils.jar" />
|
||||||
|
</path>
|
||||||
|
|
||||||
|
<taskdef name="setup"
|
||||||
|
classname="com.android.ant.SetupTask"
|
||||||
|
classpathref="android.antlibs"/>
|
||||||
|
|
||||||
|
<!-- Execute the Android Setup task that will setup some properties specific to the target,
|
||||||
|
and import the rules files.
|
||||||
|
To customize the rules, copy/paste them below the task, and disable import by setting
|
||||||
|
the import attribute to false:
|
||||||
|
<setup import="false" />
|
||||||
|
|
||||||
|
This will ensure that the properties are setup correctly but that your customized
|
||||||
|
targets are used.
|
||||||
|
-->
|
||||||
|
<setup />
|
||||||
|
</project>
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
# This file is automatically generated by Android Tools.
|
||||||
|
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||||
|
#
|
||||||
|
# This file must be checked in Version Control Systems.
|
||||||
|
#
|
||||||
|
# To customize properties used by the Ant build system use,
|
||||||
|
# "build.properties", and override values to adapt the script to your
|
||||||
|
# project structure.
|
||||||
|
|
||||||
|
# Indicates whether an apk should be generated for each density.
|
||||||
|
split.density=false
|
||||||
|
# Project target.
|
||||||
|
target=android-4
|
||||||
@ -0,0 +1,130 @@
|
|||||||
|
package com.todoroo.astrid.reminders;
|
||||||
|
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import com.todoroo.andlib.test.utility.DateUtilities;
|
||||||
|
import com.todoroo.astrid.model.Task;
|
||||||
|
|
||||||
|
public class AlarmReceiverTests extends PluginTestCase {
|
||||||
|
|
||||||
|
/** simple test of task at deadline */
|
||||||
|
public void testDeadlineReminder() {
|
||||||
|
Task task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "poop");
|
||||||
|
task.setValue(Task.DUE_DATE, DateUtilities.now());
|
||||||
|
|
||||||
|
long id = createTask(task, null);
|
||||||
|
Intent alarmIntent = new Intent();
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_TASK_ID, id);
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_IS_DEADLINE, true);
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_IS_ALARMCLOCK, false);
|
||||||
|
|
||||||
|
AlarmReceiver rx = new AlarmReceiver();
|
||||||
|
AssertiveNotificationManager nm = new AssertiveNotificationManager(getContext());
|
||||||
|
AlarmReceiver.notificationManager = nm;
|
||||||
|
rx.onReceive(getContext(), alarmIntent);
|
||||||
|
nm.assertNotified();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** task at deadline, except hidden. no notification should sound */
|
||||||
|
public void testDeadlineReminderExceptHidden() {
|
||||||
|
Task task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "poop");
|
||||||
|
task.setValue(Task.DUE_DATE, DateUtilities.now());
|
||||||
|
task.setValue(Task.HIDDEN_UNTIL, DateUtilities.now() + 100);
|
||||||
|
|
||||||
|
long id = createTask(task, null);
|
||||||
|
Intent alarmIntent = new Intent();
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_TASK_ID, id);
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_IS_DEADLINE, true);
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_IS_ALARMCLOCK, false);
|
||||||
|
|
||||||
|
AlarmReceiver rx = new AlarmReceiver();
|
||||||
|
AssertiveNotificationManager nm = new AssertiveNotificationManager(getContext());
|
||||||
|
AlarmReceiver.notificationManager = nm;
|
||||||
|
rx.onReceive(getContext(), alarmIntent);
|
||||||
|
nm.assertNotNotified();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** task upcoming */
|
||||||
|
public void testUpcomingReminder() {
|
||||||
|
Task task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "poop");
|
||||||
|
task.setValue(Task.DUE_DATE, DateUtilities.now() + 100);
|
||||||
|
|
||||||
|
long id = createTask(task, null);
|
||||||
|
Intent alarmIntent = new Intent();
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_TASK_ID, id);
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_IS_DEADLINE, false);
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_IS_ALARMCLOCK, false);
|
||||||
|
|
||||||
|
AlarmReceiver rx = new AlarmReceiver();
|
||||||
|
AssertiveNotificationManager nm = new AssertiveNotificationManager(getContext());
|
||||||
|
AlarmReceiver.notificationManager = nm;
|
||||||
|
rx.onReceive(getContext(), alarmIntent);
|
||||||
|
nm.assertNotified();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** task overdue */
|
||||||
|
public void testOverdueReminder() {
|
||||||
|
Task task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "poop");
|
||||||
|
task.setValue(Task.DUE_DATE, DateUtilities.now() - 100);
|
||||||
|
|
||||||
|
long id = createTask(task, null);
|
||||||
|
Intent alarmIntent = new Intent();
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_TASK_ID, id);
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_IS_DEADLINE, false);
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_IS_ALARMCLOCK, false);
|
||||||
|
|
||||||
|
AlarmReceiver rx = new AlarmReceiver();
|
||||||
|
AssertiveNotificationManager nm = new AssertiveNotificationManager(getContext());
|
||||||
|
AlarmReceiver.notificationManager = nm;
|
||||||
|
rx.onReceive(getContext(), alarmIntent);
|
||||||
|
nm.assertNotified();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** task alarm clock */
|
||||||
|
public void testAlarmClock() {
|
||||||
|
Task task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "poop");
|
||||||
|
task.setValue(Task.DUE_DATE, DateUtilities.now());
|
||||||
|
|
||||||
|
long id = createTask(task, null);
|
||||||
|
Intent alarmIntent = new Intent();
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_TASK_ID, id);
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_IS_DEADLINE, true);
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_IS_ALARMCLOCK, true);
|
||||||
|
|
||||||
|
AlarmReceiver rx = new AlarmReceiver();
|
||||||
|
AssertiveNotificationManager nm = new AssertiveNotificationManager(getContext());
|
||||||
|
AlarmReceiver.notificationManager = nm;
|
||||||
|
rx.onReceive(getContext(), alarmIntent);
|
||||||
|
nm.assertNotified();
|
||||||
|
assertTrue((nm.getNotification().flags & Notification.FLAG_INSISTENT) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** test the intent that the alarm receiver creates */
|
||||||
|
public void testOpenIntent() throws Exception {
|
||||||
|
Task task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "poop");
|
||||||
|
task.setValue(Task.DUE_DATE, DateUtilities.now());
|
||||||
|
|
||||||
|
long id = createTask(task, null);
|
||||||
|
Intent alarmIntent = new Intent();
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_TASK_ID, id);
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_IS_DEADLINE, true);
|
||||||
|
alarmIntent.putExtra(AlarmReceiver.TOKEN_IS_ALARMCLOCK, false);
|
||||||
|
|
||||||
|
AlarmReceiver rx = new AlarmReceiver();
|
||||||
|
AssertiveNotificationManager nm = new AssertiveNotificationManager(getContext());
|
||||||
|
AlarmReceiver.notificationManager = nm;
|
||||||
|
rx.onReceive(getContext(), alarmIntent);
|
||||||
|
nm.assertNotified();
|
||||||
|
|
||||||
|
PendingIntent intent = nm.getNotification().contentIntent;
|
||||||
|
intent.send();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package com.todoroo.astrid.reminders;
|
||||||
|
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.todoroo.andlib.service.NotificationManager.AndroidNotificationManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification manager that provides notifications and adds an
|
||||||
|
* extra method for verification.
|
||||||
|
*
|
||||||
|
* @author timsu
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AssertiveNotificationManager extends AndroidNotificationManager {
|
||||||
|
|
||||||
|
Notification notification = null;
|
||||||
|
|
||||||
|
public AssertiveNotificationManager(Context context) {
|
||||||
|
super(context);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notify(int id, Notification notification) {
|
||||||
|
super.notify(id, notification);
|
||||||
|
this.notification = notification;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void assertNotified() {
|
||||||
|
if(notification == null)
|
||||||
|
throw new AssertionError("Notification was not triggered");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void assertNotNotified() {
|
||||||
|
if(notification != null)
|
||||||
|
throw new AssertionError("Notification was triggered");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Notification getNotification() {
|
||||||
|
return notification;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
notification = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,110 @@
|
|||||||
|
package com.todoroo.astrid.reminders;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.SharedPreferences.Editor;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.R;
|
||||||
|
import com.todoroo.astrid.reminders.service.NotificationService;
|
||||||
|
|
||||||
|
public class NotificationServiceTests extends AndroidTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test quiet hour determination logic
|
||||||
|
*/
|
||||||
|
public void testQuietHoursWrapped() {
|
||||||
|
Context context = getContext();
|
||||||
|
|
||||||
|
// test wrapped quiet hours
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||||
|
Editor editor = prefs.edit();
|
||||||
|
Resources r = getContext().getResources();
|
||||||
|
|
||||||
|
editor.putString(r.getString(R.string.rmd_EPr_quiet_hours_start_key),
|
||||||
|
Integer.toString(22));
|
||||||
|
editor.putString(r.getString(R.string.rmd_EPr_quiet_hours_end_key),
|
||||||
|
Integer.toString(8));
|
||||||
|
editor.commit();
|
||||||
|
|
||||||
|
Date date = new Date();
|
||||||
|
date.setHours(21);
|
||||||
|
date.setMinutes(59);
|
||||||
|
assertFalse(NotificationService.isInQuietHours(context, date));
|
||||||
|
|
||||||
|
date.setHours(22);
|
||||||
|
date.setMinutes(0);
|
||||||
|
assertTrue(NotificationService.isInQuietHours(context, date));
|
||||||
|
|
||||||
|
date.setHours(23);
|
||||||
|
assertTrue(NotificationService.isInQuietHours(context, date));
|
||||||
|
|
||||||
|
date.setHours(0);
|
||||||
|
assertTrue(NotificationService.isInQuietHours(context, date));
|
||||||
|
|
||||||
|
date.setHours(7);
|
||||||
|
date.setMinutes(59);
|
||||||
|
assertTrue(NotificationService.isInQuietHours(context, date));
|
||||||
|
|
||||||
|
date.setHours(8);
|
||||||
|
date.setMinutes(0);
|
||||||
|
assertFalse(NotificationService.isInQuietHours(context, date));
|
||||||
|
|
||||||
|
date.setHours(12);
|
||||||
|
assertFalse(NotificationService.isInQuietHours(context, date));
|
||||||
|
|
||||||
|
date.setHours(20);
|
||||||
|
assertFalse(NotificationService.isInQuietHours(context, date));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test quiet hour determination logic
|
||||||
|
*/
|
||||||
|
public void testQuietHoursUnwrapped() {
|
||||||
|
Context context = getContext();
|
||||||
|
|
||||||
|
// test wrapped quiet hours
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||||
|
Editor editor = prefs.edit();
|
||||||
|
Resources r = getContext().getResources();
|
||||||
|
|
||||||
|
editor.putString(r.getString(R.string.rmd_EPr_quiet_hours_start_key),
|
||||||
|
Integer.toString(10));
|
||||||
|
editor.putString(r.getString(R.string.rmd_EPr_quiet_hours_end_key),
|
||||||
|
Integer.toString(16));
|
||||||
|
editor.commit();
|
||||||
|
|
||||||
|
Date date = new Date();
|
||||||
|
date.setHours(9);
|
||||||
|
date.setMinutes(59);
|
||||||
|
assertFalse(NotificationService.isInQuietHours(context, date));
|
||||||
|
|
||||||
|
date.setHours(10);
|
||||||
|
date.setMinutes(0);
|
||||||
|
assertTrue(NotificationService.isInQuietHours(context, date));
|
||||||
|
|
||||||
|
date.setHours(11);
|
||||||
|
assertTrue(NotificationService.isInQuietHours(context, date));
|
||||||
|
|
||||||
|
date.setHours(13);
|
||||||
|
assertTrue(NotificationService.isInQuietHours(context, date));
|
||||||
|
|
||||||
|
date.setHours(15);
|
||||||
|
date.setMinutes(59);
|
||||||
|
assertTrue(NotificationService.isInQuietHours(context, date));
|
||||||
|
|
||||||
|
date.setHours(16);
|
||||||
|
date.setMinutes(0);
|
||||||
|
assertFalse(NotificationService.isInQuietHours(context, date));
|
||||||
|
|
||||||
|
date.setHours(23);
|
||||||
|
assertFalse(NotificationService.isInQuietHours(context, date));
|
||||||
|
|
||||||
|
date.setHours(0);
|
||||||
|
assertFalse(NotificationService.isInQuietHours(context, date));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.todoroo.astrid.reminders;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import com.todoroo.andlib.service.Autowired;
|
||||||
|
import com.todoroo.astrid.dao.MetadataDao;
|
||||||
|
import com.todoroo.astrid.dao.TaskDao;
|
||||||
|
import com.todoroo.astrid.model.Metadata;
|
||||||
|
import com.todoroo.astrid.model.Task;
|
||||||
|
import com.todoroo.astrid.test.DatabaseTestCase;
|
||||||
|
|
||||||
|
public class PluginTestCase extends DatabaseTestCase {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public TaskDao taskDao;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public MetadataDao metadataDao;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to create a task.
|
||||||
|
* @param task
|
||||||
|
* @param metadata
|
||||||
|
* @return task id
|
||||||
|
*/
|
||||||
|
public long createTask(Task task, HashMap<String, String> metadata) {
|
||||||
|
taskDao.save(database, task, false);
|
||||||
|
|
||||||
|
if(metadata != null) {
|
||||||
|
Metadata metadataItem = new Metadata();
|
||||||
|
metadataItem.setValue(Metadata.TASK, task.getId());
|
||||||
|
for(Entry<String, String> entry : metadata.entrySet()) {
|
||||||
|
metadataItem.setValue(Metadata.KEY, entry.getKey());
|
||||||
|
metadataItem.setValue(Metadata.VALUE, entry.getValue());
|
||||||
|
metadataDao.save(database, metadataItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return task.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,282 @@
|
|||||||
|
package com.todoroo.astrid.reminders.service;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import android.database.sqlite.SQLiteQueryBuilder;
|
||||||
|
|
||||||
|
import com.todoroo.andlib.test.data.TodorooCursor;
|
||||||
|
import com.todoroo.andlib.test.utility.DateUtilities;
|
||||||
|
import com.todoroo.astrid.model.Task;
|
||||||
|
import com.todoroo.astrid.reminders.AlarmReceiver;
|
||||||
|
import com.todoroo.astrid.reminders.Constants;
|
||||||
|
import com.todoroo.astrid.reminders.PluginTestCase;
|
||||||
|
import com.todoroo.astrid.reminders.service.ReminderService.Alarm;
|
||||||
|
|
||||||
|
public class ReminderServiceTests extends PluginTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test task fetching mechanism for reminders
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public void testTaskReminderFetch() {
|
||||||
|
ReminderService service = new ReminderService(getContext());
|
||||||
|
|
||||||
|
SQLiteQueryBuilder baseQuery = service.createBaseQuery();
|
||||||
|
TodorooCursor<Task> cursor = service.fetchTasksWithReminders(baseQuery);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// add new tasks
|
||||||
|
int now = DateUtilities.now();
|
||||||
|
Task task = new Task();
|
||||||
|
HashMap<String, String> metadata = new HashMap<String, String>();
|
||||||
|
|
||||||
|
task.setValue(Task.TITLE, "normal");
|
||||||
|
task.setValue(Task.DUE_DATE, now + 10);
|
||||||
|
metadata.put(Constants.KEY_REMINDER, Integer.toString(Constants.REMINDER_AT_DEADLINE));
|
||||||
|
long normalId = createTask(task, metadata);
|
||||||
|
|
||||||
|
task.clear();
|
||||||
|
task.setValue(Task.TITLE, "completed");
|
||||||
|
task.setValue(Task.DUE_DATE, now + 10);
|
||||||
|
task.setValue(Task.COMPLETION_DATE, now + 10);
|
||||||
|
metadata.put(Constants.KEY_REMINDER, Integer.toString(Constants.REMINDER_ALARM_CLOCK));
|
||||||
|
long completedId = createTask(task, metadata);
|
||||||
|
|
||||||
|
task.clear();
|
||||||
|
task.setValue(Task.TITLE, "hidden");
|
||||||
|
task.setValue(Task.DUE_DATE, now + 10);
|
||||||
|
task.setValue(Task.HIDDEN_UNTIL, now + 10);
|
||||||
|
metadata.put(Constants.KEY_REMINDER, Integer.toString(Constants.REMINDER_INCREASING));
|
||||||
|
long hiddenId = createTask(task, metadata);
|
||||||
|
|
||||||
|
task.clear();
|
||||||
|
task.setValue(Task.TITLE, "noalarm");
|
||||||
|
task.setValue(Task.DUE_DATE, now + 10);
|
||||||
|
metadata.put(Constants.KEY_REMINDER, Integer.toString(Constants.REMINDER_NONE));
|
||||||
|
long noAlarmId = createTask(task, metadata);
|
||||||
|
|
||||||
|
task.clear();
|
||||||
|
task.setValue(Task.TITLE, "overdue");
|
||||||
|
task.setValue(Task.DUE_DATE, now - 10);
|
||||||
|
metadata.put(Constants.KEY_REMINDER, Integer.toString(Constants.REMINDER_AT_DEADLINE));
|
||||||
|
long overdueId = createTask(task, metadata);
|
||||||
|
|
||||||
|
cursor = service.fetchTasksWithReminders(baseQuery);
|
||||||
|
assertEquals(2, cursor.getCount());
|
||||||
|
cursor.moveToFirst();
|
||||||
|
task.readFromCursor(cursor, ReminderService.PROPERTIES);
|
||||||
|
assertEquals(task.getId(), normalId);
|
||||||
|
assertEquals(task.getValue(ReminderService.REMINDER_MODE),
|
||||||
|
Integer.toString(Constants.REMINDER_AT_DEADLINE));
|
||||||
|
cursor.moveToNext();
|
||||||
|
task.readFromCursor(cursor, ReminderService.PROPERTIES);
|
||||||
|
assertEquals(task.getId(), hiddenId);
|
||||||
|
assertEquals(task.getValue(ReminderService.REMINDER_MODE),
|
||||||
|
Integer.toString(Constants.REMINDER_INCREASING));
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test task fetching mechanism for overdue interval
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public void testTaskOverdueFetch() {
|
||||||
|
ReminderService service = new ReminderService(getContext());
|
||||||
|
|
||||||
|
SQLiteQueryBuilder baseQuery = service.createBaseQuery();
|
||||||
|
TodorooCursor<Task> cursor = service.fetchTasksWithOverdueReminders(baseQuery);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// add new tasks
|
||||||
|
int now = DateUtilities.now();
|
||||||
|
Task task = new Task();
|
||||||
|
HashMap<String, String> metadata = new HashMap<String, String>();
|
||||||
|
|
||||||
|
task.setValue(Task.TITLE, "normal");
|
||||||
|
task.setValue(Task.DUE_DATE, now - 10);
|
||||||
|
metadata.put(Constants.KEY_OVERDUE, Integer.toString(1500));
|
||||||
|
long normalId = createTask(task, metadata);
|
||||||
|
|
||||||
|
task.clear();
|
||||||
|
task.setValue(Task.TITLE, "completed");
|
||||||
|
task.setValue(Task.DUE_DATE, now - 10);
|
||||||
|
task.setValue(Task.COMPLETION_DATE, now - 10);
|
||||||
|
metadata.put(Constants.KEY_OVERDUE, Integer.toString(1500));
|
||||||
|
long completedId = createTask(task, metadata);
|
||||||
|
|
||||||
|
task.clear();
|
||||||
|
task.setValue(Task.TITLE, "hidden");
|
||||||
|
task.setValue(Task.DUE_DATE, now - 10);
|
||||||
|
task.setValue(Task.HIDDEN_UNTIL, now + 10);
|
||||||
|
metadata.put(Constants.KEY_OVERDUE, Integer.toString(1500));
|
||||||
|
long hiddenId = createTask(task, metadata);
|
||||||
|
|
||||||
|
task.clear();
|
||||||
|
task.setValue(Task.TITLE, "noalarm");
|
||||||
|
task.setValue(Task.DUE_DATE, now - 10);
|
||||||
|
metadata.put(Constants.KEY_OVERDUE, Integer.toString(0));
|
||||||
|
long noAlarmId = createTask(task, metadata);
|
||||||
|
|
||||||
|
task.clear();
|
||||||
|
task.setValue(Task.TITLE, "not due");
|
||||||
|
task.setValue(Task.DUE_DATE, now + 10);
|
||||||
|
metadata.put(Constants.KEY_OVERDUE, Integer.toString(0));
|
||||||
|
long notDueId = createTask(task, metadata);
|
||||||
|
|
||||||
|
cursor = service.fetchTasksWithOverdueReminders(baseQuery);
|
||||||
|
assertEquals(2, cursor.getCount());
|
||||||
|
cursor.moveToFirst();
|
||||||
|
task.readFromCursor(cursor, ReminderService.PROPERTIES);
|
||||||
|
assertEquals(task.getId(), normalId);
|
||||||
|
assertEquals(task.getValue(ReminderService.OVERDUE_INTERVAL),
|
||||||
|
Integer.valueOf(1500));
|
||||||
|
cursor.moveToNext();
|
||||||
|
task.readFromCursor(cursor, ReminderService.PROPERTIES);
|
||||||
|
assertEquals(task.getId(), hiddenId);
|
||||||
|
assertEquals(task.getValue(ReminderService.OVERDUE_INTERVAL),
|
||||||
|
Integer.valueOf(1500));
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test task fetching mechanism for reminders
|
||||||
|
*/
|
||||||
|
public void testTaskFetchForReminders() {
|
||||||
|
ReminderService service = new ReminderService(getContext());
|
||||||
|
|
||||||
|
// try invalid
|
||||||
|
assertNull("could fetch invalid", service.fetchTask(-99));
|
||||||
|
|
||||||
|
// add new tasks
|
||||||
|
Task task = new Task();
|
||||||
|
HashMap<String, String> metadata = new HashMap<String, String>();
|
||||||
|
task.setValue(Task.TITLE, "salami");
|
||||||
|
task.setValue(Task.DUE_DATE, 100);
|
||||||
|
metadata.put(Constants.KEY_OVERDUE, "123");
|
||||||
|
metadata.put(Constants.KEY_LAST_NOTIFIED, "345");
|
||||||
|
metadata.put(Constants.KEY_REMINDER, "567");
|
||||||
|
long id = createTask(task, metadata);
|
||||||
|
|
||||||
|
task = service.fetchTask(id);
|
||||||
|
assertEquals(task.getValue(Task.TITLE), "salami");
|
||||||
|
assertEquals(task.getValue(ReminderService.OVERDUE_INTERVAL), Integer.valueOf(123));
|
||||||
|
assertEquals(task.getValue(ReminderService.LAST_NOTIFIED), Integer.valueOf(345));
|
||||||
|
assertEquals(task.getValue(ReminderService.REMINDER_MODE), Integer.valueOf(567));
|
||||||
|
|
||||||
|
task.setValue(ReminderService.OVERDUE_INTERVAL, 321);
|
||||||
|
task.setValue(ReminderService.LAST_NOTIFIED, 543);
|
||||||
|
task.setValue(ReminderService.REMINDER_MODE, 765);
|
||||||
|
|
||||||
|
service.writeReminderOptions(task);
|
||||||
|
task = service.fetchTask(id);
|
||||||
|
|
||||||
|
assertEquals(task.getValue(ReminderService.OVERDUE_INTERVAL), Integer.valueOf(321));
|
||||||
|
assertEquals(task.getValue(ReminderService.LAST_NOTIFIED), Integer.valueOf(543));
|
||||||
|
assertEquals(task.getValue(ReminderService.REMINDER_MODE), Integer.valueOf(765));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test alarm generation
|
||||||
|
*/
|
||||||
|
public void testAlarmGeneration() {
|
||||||
|
ReminderService service = new ReminderService(getContext());
|
||||||
|
int now = DateUtilities.now();
|
||||||
|
|
||||||
|
// test simple task with deadline
|
||||||
|
Task task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "blah");
|
||||||
|
task.setValue(Task.DUE_DATE, now + 10000);
|
||||||
|
task.setValue(ReminderService.REMINDER_MODE, Constants.REMINDER_AT_DEADLINE);
|
||||||
|
Alarm alarm = service.createReminderAlarm(task);
|
||||||
|
assertEquals(task.getValue(Task.DUE_DATE), Integer.valueOf(alarm.alarmTime));
|
||||||
|
|
||||||
|
// test simple task no reminders
|
||||||
|
task.setValue(ReminderService.REMINDER_MODE, Constants.REMINDER_NONE);
|
||||||
|
alarm = service.createReminderAlarm(task);
|
||||||
|
assertNull(alarm);
|
||||||
|
|
||||||
|
// test simple task with deadline passed and no overdue interval
|
||||||
|
task.setValue(Task.DUE_DATE, now - 10);
|
||||||
|
task.setValue(ReminderService.REMINDER_MODE, Constants.REMINDER_AT_DEADLINE);
|
||||||
|
alarm = service.createReminderAlarm(task);
|
||||||
|
assertNull(alarm);
|
||||||
|
|
||||||
|
// test alarm clock task
|
||||||
|
task.setValue(Task.DUE_DATE, now + 10000);
|
||||||
|
task.setValue(ReminderService.REMINDER_MODE, Constants.REMINDER_ALARM_CLOCK);
|
||||||
|
alarm = service.createReminderAlarm(task);
|
||||||
|
assertEquals(task.getValue(Task.DUE_DATE), Integer.valueOf(alarm.alarmTime));
|
||||||
|
|
||||||
|
// test overdue alarm clock task
|
||||||
|
task.setValue(Task.DUE_DATE, now - 10);
|
||||||
|
alarm = service.createReminderAlarm(task);
|
||||||
|
assertNull(alarm);
|
||||||
|
|
||||||
|
// test increasing 30 days from now
|
||||||
|
task.setValue(ReminderService.REMINDER_MODE, Constants.REMINDER_INCREASING);
|
||||||
|
task.setValue(ReminderService.LAST_NOTIFIED, now);
|
||||||
|
task.setValue(Task.DUE_DATE, now + 30 * 86400);
|
||||||
|
alarm = service.createReminderAlarm(task);
|
||||||
|
assertTrue(alarm.alarmTime > now + 5 * 86400 &&
|
||||||
|
alarm.alarmTime < now + 25 * 86400);
|
||||||
|
|
||||||
|
// test increasing 30 days from now, with last notified of 100 days ago
|
||||||
|
task.setValue(ReminderService.REMINDER_MODE, Constants.REMINDER_INCREASING);
|
||||||
|
task.setValue(Task.DUE_DATE, now + 30 * 86400);
|
||||||
|
task.setValue(ReminderService.LAST_NOTIFIED, now - 100 * 86400);
|
||||||
|
alarm = service.createReminderAlarm(task);
|
||||||
|
assertTrue(alarm.alarmTime > 0 &&
|
||||||
|
alarm.alarmTime < now + 1 * 86400);
|
||||||
|
|
||||||
|
// test increasing when we're within the day boundary and task is
|
||||||
|
// not defined with a specific time
|
||||||
|
task.setValue(Task.URGENCY, Task.URGENCY_THIS_WEEK);
|
||||||
|
task.setValue(Task.DUE_DATE, now + 80000);
|
||||||
|
task.setValue(ReminderService.LAST_NOTIFIED, now);
|
||||||
|
alarm = service.createReminderAlarm(task);
|
||||||
|
assertTrue(alarm.intent.getBooleanExtra(AlarmReceiver.TOKEN_IS_DEADLINE, false));
|
||||||
|
assertEquals(task.getValue(Task.DUE_DATE), Integer.valueOf(alarm.alarmTime));
|
||||||
|
|
||||||
|
// now same due date, but we've defined specific time
|
||||||
|
task.setValue(Task.URGENCY, Task.URGENCY_SPECIFIC_DAY_TIME);
|
||||||
|
alarm = service.createReminderAlarm(task);
|
||||||
|
assertTrue(DateUtilities.now() < alarm.alarmTime &&
|
||||||
|
alarm.alarmTime < task.getValue(Task.DUE_DATE));
|
||||||
|
|
||||||
|
// move the due date right up against actual
|
||||||
|
task.setValue(Task.DUE_DATE, now + 1000);
|
||||||
|
alarm = service.createReminderAlarm(task);
|
||||||
|
assertEquals(task.getValue(Task.DUE_DATE), Integer.valueOf(alarm.alarmTime));
|
||||||
|
assertTrue(alarm.intent.getBooleanExtra(AlarmReceiver.TOKEN_IS_DEADLINE, false));
|
||||||
|
|
||||||
|
// and after due date
|
||||||
|
task.setValue(Task.DUE_DATE, now - 80000);
|
||||||
|
alarm = service.createReminderAlarm(task);
|
||||||
|
assertNull(alarm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test alarm generation (overdue)
|
||||||
|
*/
|
||||||
|
public void testOverdueAlarmGeneration() {
|
||||||
|
ReminderService service = new ReminderService(getContext());
|
||||||
|
int now = DateUtilities.now();
|
||||||
|
|
||||||
|
// test simple overdue
|
||||||
|
Task task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "blah");
|
||||||
|
|
||||||
|
task.setValue(Task.DUE_DATE, now - 100);
|
||||||
|
task.setValue(ReminderService.OVERDUE_INTERVAL, 1000);
|
||||||
|
Alarm alarm = service.createOverdueAlarm(task);
|
||||||
|
assertTrue(now + 500 < alarm.alarmTime && alarm.alarmTime < now + 1500);
|
||||||
|
|
||||||
|
// same case, but almost exact due as normal
|
||||||
|
task.setValue(Task.DUE_DATE, DateUtilities.now());
|
||||||
|
alarm = service.createOverdueAlarm(task);
|
||||||
|
assertTrue(now + 500 < alarm.alarmTime && alarm.alarmTime < now + 1500);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
package com.todoroo.astrid.rmilk;
|
||||||
|
|
||||||
|
public class RTMTestCase {
|
||||||
|
String token = "cb4281f7154114ed0e4ccc3a02d373c5a2429532";
|
||||||
|
}
|
||||||
@ -0,0 +1,240 @@
|
|||||||
|
package com.todoroo.andlib.service;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
import com.todoroo.andlib.service.AbstractDependencyInjector;
|
||||||
|
import com.todoroo.andlib.service.Autowired;
|
||||||
|
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||||
|
|
||||||
|
public class DependencyInjectionTests extends AndroidTestCase {
|
||||||
|
|
||||||
|
public void testNoAutowire() {
|
||||||
|
DependencyInjectionService service = new DependencyInjectionService();
|
||||||
|
service.setInjectors(new AbstractDependencyInjector[] {});
|
||||||
|
|
||||||
|
Object test = new Object();
|
||||||
|
service.inject(test);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSimpleStringInjectionAutowire() {
|
||||||
|
DependencyInjectionService service = new DependencyInjectionService();
|
||||||
|
service.setInjectors(new AbstractDependencyInjector[] {
|
||||||
|
new AbstractDependencyInjector() {
|
||||||
|
|
||||||
|
public Object getInjection(Object object, Field field) {
|
||||||
|
if(field.getName().equals("foo"))
|
||||||
|
return "bar";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// test various permissions
|
||||||
|
Object test = new Object() {
|
||||||
|
@Autowired
|
||||||
|
public String foo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return foo;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
service.inject(test);
|
||||||
|
assertEquals("bar", test.toString());
|
||||||
|
|
||||||
|
test = new Object() {
|
||||||
|
@Autowired
|
||||||
|
String foo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return foo;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
service.inject(test);
|
||||||
|
assertEquals("bar", test.toString());
|
||||||
|
|
||||||
|
test = new Object() {
|
||||||
|
@Autowired
|
||||||
|
protected String foo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return foo;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
service.inject(test);
|
||||||
|
assertEquals("bar", test.toString());
|
||||||
|
|
||||||
|
test = new Object() {
|
||||||
|
@Autowired
|
||||||
|
private String foo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return foo;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
service.inject(test);
|
||||||
|
assertEquals("bar", test.toString());
|
||||||
|
|
||||||
|
// test no annotation
|
||||||
|
test = new Object() {
|
||||||
|
public String foo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return foo;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
service.inject(test);
|
||||||
|
assertNull( test.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testHierarchicalStringInjectionAutowire() {
|
||||||
|
DependencyInjectionService service = new DependencyInjectionService();
|
||||||
|
service.setInjectors(new AbstractDependencyInjector[] {
|
||||||
|
new AbstractDependencyInjector() {
|
||||||
|
|
||||||
|
public Object getInjection(Object object, Field field) {
|
||||||
|
if(field.getName().equals("foo"))
|
||||||
|
return "bar";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new AbstractDependencyInjector() {
|
||||||
|
|
||||||
|
public Object getInjection(Object object, Field field) {
|
||||||
|
return "malarkey";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object test = new Object() {
|
||||||
|
@Autowired
|
||||||
|
public String foo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return foo;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
service.inject(test);
|
||||||
|
assertEquals("bar", test.toString());
|
||||||
|
|
||||||
|
test = new Object() {
|
||||||
|
@Autowired
|
||||||
|
public String forks;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return forks;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
service.inject(test);
|
||||||
|
assertEquals("malarkey", test.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMissingInjection() {
|
||||||
|
DependencyInjectionService service = new DependencyInjectionService();
|
||||||
|
service.setInjectors(new AbstractDependencyInjector[] {
|
||||||
|
new AbstractDependencyInjector() {
|
||||||
|
|
||||||
|
public Object getInjection(Object object, Field field) {
|
||||||
|
if(field.getName().equals("wozzle"))
|
||||||
|
return "bar";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object test = new Object() {
|
||||||
|
@Autowired
|
||||||
|
public String foo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return foo;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
service.inject(test);
|
||||||
|
fail("could inject with missing injector");
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
assertNull(test.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultipleInjection() {
|
||||||
|
DependencyInjectionService service = new DependencyInjectionService();
|
||||||
|
service.setInjectors(new AbstractDependencyInjector[] {
|
||||||
|
new AbstractDependencyInjector() {
|
||||||
|
|
||||||
|
public Object getInjection(Object object, Field field) {
|
||||||
|
if(field.getName().equals("foo"))
|
||||||
|
return "bar";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object test1 = new Object() {
|
||||||
|
@Autowired
|
||||||
|
public String foo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return foo;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Object test2 = new Object() {
|
||||||
|
@Autowired
|
||||||
|
public String foo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return foo;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
service.inject(test1);
|
||||||
|
service.inject(test2);
|
||||||
|
assertEquals("bar", test1.toString());
|
||||||
|
assertEquals("bar", test2.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ParentInjectee {
|
||||||
|
@Autowired
|
||||||
|
protected String foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ChildInjectee extends ParentInjectee {
|
||||||
|
@Autowired
|
||||||
|
protected String bar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testInheritedInjection() {
|
||||||
|
DependencyInjectionService service = new DependencyInjectionService();
|
||||||
|
service.setInjectors(new AbstractDependencyInjector[] {
|
||||||
|
new AbstractDependencyInjector() {
|
||||||
|
|
||||||
|
public Object getInjection(Object object, Field field) {
|
||||||
|
if(field.getName().equals("foo"))
|
||||||
|
return "gotfoo";
|
||||||
|
else if(field.getName().equals("bar"))
|
||||||
|
return "hasbar";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ChildInjectee child = new ChildInjectee();
|
||||||
|
service.inject(child);
|
||||||
|
assertEquals("gotfoo", child.foo);
|
||||||
|
assertEquals("hasbar", child.bar);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
package com.todoroo.andlib.service;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
public class TestDependencyInjector implements AbstractDependencyInjector {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dependencies this class knows how to handle
|
||||||
|
*/
|
||||||
|
private final HashMap<String, Object> injectables = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public TestDependencyInjector(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addInjectable(String field, Object injection) {
|
||||||
|
injectables.put(field, injection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getInjection(Object object, Field field) {
|
||||||
|
if(injectables.containsKey(field.getName())) {
|
||||||
|
return injectables.get(field.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- static stuff
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install TestDependencyInjector above other injectors
|
||||||
|
*/
|
||||||
|
public synchronized static TestDependencyInjector initialize(String name) {
|
||||||
|
ArrayList<AbstractDependencyInjector> list =
|
||||||
|
new ArrayList<AbstractDependencyInjector>(Arrays.asList(DependencyInjectionService.getInstance().getInjectors()));
|
||||||
|
for(Iterator<AbstractDependencyInjector> i = list.iterator(); i.hasNext(); ) {
|
||||||
|
AbstractDependencyInjector injector = i.next();
|
||||||
|
|
||||||
|
// if another one of these injectors already exists in the
|
||||||
|
// stack, remove it
|
||||||
|
if(injector instanceof TestDependencyInjector) {
|
||||||
|
if(((TestDependencyInjector)injector).name.equals(name))
|
||||||
|
i.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TestDependencyInjector instance = new TestDependencyInjector(name);
|
||||||
|
list.add(0, instance);
|
||||||
|
DependencyInjectionService.getInstance().setInjectors(list.toArray(new AbstractDependencyInjector[list.size()]));
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.todoroo.andlib.test;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
public class SimpleAndroidTest extends AndroidTestCase {
|
||||||
|
|
||||||
|
public void testSimpleAssert() throws Throwable {
|
||||||
|
Assert.assertTrue(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package com.todoroo.andlib.test;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility methods used in unit tests
|
||||||
|
*
|
||||||
|
* @author Tim Su <tim@todoroo.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TestUtilities {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sleep, suppressing exceptions
|
||||||
|
*
|
||||||
|
* @param millis
|
||||||
|
*/
|
||||||
|
public static void sleepDeep(long millis) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(millis);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
package com.todoroo.andlib.test;
|
||||||
|
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
import com.todoroo.andlib.service.ContextManager;
|
||||||
|
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base test case for Astrid tests
|
||||||
|
*
|
||||||
|
* @author Tim Su <tim@todoroo.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TodorooTestCase extends AndroidTestCase {
|
||||||
|
|
||||||
|
public TodorooTestCase() {
|
||||||
|
DependencyInjectionService.getInstance().inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
ContextManager.setContext(this.getContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.todoroo.astrid;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
import android.test.suitebuilder.TestSuiteBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A test suite containing activity-related tests
|
||||||
|
*/
|
||||||
|
public class ActivityTests extends TestSuite {
|
||||||
|
|
||||||
|
public static Test suite() {
|
||||||
|
return new TestSuiteBuilder(ActivityTests.class)
|
||||||
|
.includePackages("com.todoroo.astrid.activity")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.todoroo.astrid;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
import android.test.suitebuilder.TestSuiteBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A test suite containing all tests for ApiDemos.
|
||||||
|
*
|
||||||
|
* To run all suites found in this apk:
|
||||||
|
* $ adb shell am instrument -w \
|
||||||
|
* com.example.android.apis.tests/android.test.InstrumentationTestRunner
|
||||||
|
*
|
||||||
|
* To run just this suite from the command line:
|
||||||
|
* $ adb shell am instrument -w \
|
||||||
|
* -e class com.example.android.apis.AllTests \
|
||||||
|
* com.example.android.apis.tests/android.test.InstrumentationTestRunner
|
||||||
|
*
|
||||||
|
* To run an individual test case, e.g. {@link com.example.android.apis.os.MorseCodeConverterTest}:
|
||||||
|
* $ adb shell am instrument -w \
|
||||||
|
* -e class com.example.android.apis.os.MorseCodeConverterTest \
|
||||||
|
* com.example.android.apis.tests/android.test.InstrumentationTestRunner
|
||||||
|
*
|
||||||
|
* To run an individual test, e.g. {@link com.example.android.apis.os.MorseCodeConverterTest#testCharacterS()}:
|
||||||
|
* $ adb shell am instrument -w \
|
||||||
|
* -e class com.example.android.apis.os.MorseCodeConverterTest#testCharacterS \
|
||||||
|
* com.example.android.apis.tests/android.test.InstrumentationTestRunner
|
||||||
|
*/
|
||||||
|
public class AllTests extends TestSuite {
|
||||||
|
|
||||||
|
public static Test suite() {
|
||||||
|
return new TestSuiteBuilder(AllTests.class)
|
||||||
|
.includeAllPackagesUnderHere()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.todoroo.astrid.dao;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.test.DatabaseTestCase;
|
||||||
|
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
|
||||||
|
|
||||||
|
public class BasicDatabaseTests extends DatabaseTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that it's possible to open the database multiple times, to no effect
|
||||||
|
*/
|
||||||
|
public void testOpenMultipleTimes() {
|
||||||
|
SQLiteDatabase sqlDatabase = database.getDatabase();
|
||||||
|
database.openForReading(getContext());
|
||||||
|
assertEquals(sqlDatabase, database.getDatabase());
|
||||||
|
database.openForWriting(getContext());
|
||||||
|
assertEquals(sqlDatabase, database.getDatabase());
|
||||||
|
database.openForReading(getContext());
|
||||||
|
assertEquals(sqlDatabase, database.getDatabase());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testCloseAndReopen() {
|
||||||
|
SQLiteDatabase sqlDatabase = database.getDatabase();
|
||||||
|
database.close();
|
||||||
|
database.openForReading(getContext());
|
||||||
|
assertNotSame(sqlDatabase, database.getDatabase());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,187 @@
|
|||||||
|
package com.todoroo.astrid.dao;
|
||||||
|
|
||||||
|
import com.todoroo.andlib.service.Autowired;
|
||||||
|
import com.todoroo.andlib.test.data.Property;
|
||||||
|
import com.todoroo.andlib.test.data.TodorooCursor;
|
||||||
|
import com.todoroo.astrid.dao.MetadataDao.MetadataSql;
|
||||||
|
import com.todoroo.astrid.model.Metadata;
|
||||||
|
import com.todoroo.astrid.model.Task;
|
||||||
|
import com.todoroo.astrid.service.MetadataService;
|
||||||
|
import com.todoroo.astrid.test.DatabaseTestCase;
|
||||||
|
|
||||||
|
public class MetadataDaoTests extends DatabaseTestCase {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
MetadataDao metadataDao;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
TaskDao taskDao;
|
||||||
|
|
||||||
|
public static Property<?>[] KEYS = new Property<?>[] { Metadata.ID,
|
||||||
|
Metadata.KEY };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test basic creation, fetch, and save
|
||||||
|
*/
|
||||||
|
public void testCrud() throws Exception {
|
||||||
|
TodorooCursor<Metadata> cursor = metadataDao.fetch(database,
|
||||||
|
MetadataService.idProperty(), null, null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// create "happy"
|
||||||
|
Metadata metadata = new Metadata();
|
||||||
|
metadata.setValue(Metadata.KEY, "happy");
|
||||||
|
assertTrue(metadataDao.save(database, metadata));
|
||||||
|
cursor = metadataDao.fetch(database, MetadataService.idProperty(), null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
long happyId = metadata.getId();
|
||||||
|
assertNotSame(Metadata.NO_ID, happyId);
|
||||||
|
metadata = metadataDao.fetch(database, KEYS, happyId);
|
||||||
|
assertEquals("happy", metadata.getValue(Metadata.KEY));
|
||||||
|
|
||||||
|
// create "sad"
|
||||||
|
metadata = new Metadata();
|
||||||
|
metadata.setValue(Metadata.KEY, "sad");
|
||||||
|
assertTrue(metadataDao.save(database, metadata));
|
||||||
|
cursor = metadataDao.fetch(database, MetadataService.idProperty(), null, null);
|
||||||
|
assertEquals(2, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// rename sad to melancholy
|
||||||
|
long sadId = metadata.getId();
|
||||||
|
assertNotSame(Metadata.NO_ID, sadId);
|
||||||
|
metadata.setValue(Metadata.KEY, "melancholy");
|
||||||
|
assertTrue(metadataDao.save(database, metadata));
|
||||||
|
cursor = metadataDao.fetch(database, MetadataService.idProperty(), null, null);
|
||||||
|
assertEquals(2, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// check state
|
||||||
|
metadata = metadataDao.fetch(database, KEYS, happyId);
|
||||||
|
assertEquals("happy", metadata.getValue(Metadata.KEY));
|
||||||
|
metadata = metadataDao.fetch(database, KEYS, sadId);
|
||||||
|
assertEquals("melancholy", metadata.getValue(Metadata.KEY));
|
||||||
|
|
||||||
|
// delete sad
|
||||||
|
assertTrue(metadataDao.delete(database, sadId));
|
||||||
|
cursor = metadataDao.fetch(database, KEYS, null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.moveToFirst();
|
||||||
|
metadata.readFromCursor(cursor, KEYS);
|
||||||
|
assertEquals("happy", metadata.getValue(Metadata.KEY));
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test metadata bound to task
|
||||||
|
*/
|
||||||
|
public void testMetadataConditions() throws Exception {
|
||||||
|
// create "happy"
|
||||||
|
Metadata metadata = new Metadata();
|
||||||
|
metadata.setValue(Metadata.KEY, "with1");
|
||||||
|
metadata.setValue(Metadata.TASK, 1L);
|
||||||
|
assertTrue(metadataDao.save(database, metadata));
|
||||||
|
|
||||||
|
metadata = new Metadata();
|
||||||
|
metadata.setValue(Metadata.KEY, "with2");
|
||||||
|
metadata.setValue(Metadata.TASK, 2L);
|
||||||
|
assertTrue(metadataDao.save(database, metadata));
|
||||||
|
|
||||||
|
metadata = new Metadata();
|
||||||
|
metadata.setValue(Metadata.KEY, "with1");
|
||||||
|
metadata.setValue(Metadata.TASK, 1L);
|
||||||
|
assertTrue(metadataDao.save(database, metadata));
|
||||||
|
|
||||||
|
|
||||||
|
TodorooCursor<Metadata> cursor = metadataDao.fetch(database,
|
||||||
|
KEYS, MetadataSql.byTask(1), null);
|
||||||
|
assertEquals(2, cursor.getCount());
|
||||||
|
cursor.moveToFirst();
|
||||||
|
metadata.readFromCursor(cursor, KEYS);
|
||||||
|
assertEquals("with1", metadata.getValue(Metadata.KEY));
|
||||||
|
cursor.moveToNext();
|
||||||
|
metadata.readFromCursor(cursor, KEYS);
|
||||||
|
assertEquals("with1", metadata.getValue(Metadata.KEY));
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
cursor = metadataDao.fetch(database,
|
||||||
|
MetadataService.idProperty(), MetadataSql.byTask(3), null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
int deleted = metadataDao.deleteWhere(database, MetadataSql.byTask(1));
|
||||||
|
assertEquals(2, deleted);
|
||||||
|
cursor = metadataDao.fetch(database,
|
||||||
|
MetadataService.idProperty(), null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test metadata deletion
|
||||||
|
*/
|
||||||
|
public void testFetchDangling() throws Exception {
|
||||||
|
// fetch with nothing in db
|
||||||
|
TodorooCursor<Metadata> cursor = metadataDao.fetchDangling(database, KEYS);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
Task task1 = new Task();
|
||||||
|
taskDao.save(database, task1);
|
||||||
|
Task task2 = new Task();
|
||||||
|
taskDao.save(database, task2);
|
||||||
|
Task task3 = new Task();
|
||||||
|
taskDao.save(database, task3);
|
||||||
|
|
||||||
|
// fetch with only tasks
|
||||||
|
cursor = metadataDao.fetchDangling(database, KEYS);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
Metadata metadata = new Metadata();
|
||||||
|
metadata.setValue(Metadata.KEY, "with1");
|
||||||
|
metadata.setValue(Metadata.TASK, task1.getId());
|
||||||
|
assertTrue(metadataDao.save(database, metadata));
|
||||||
|
|
||||||
|
metadata = new Metadata();
|
||||||
|
metadata.setValue(Metadata.KEY, "with2");
|
||||||
|
metadata.setValue(Metadata.TASK, task2.getId());
|
||||||
|
assertTrue(metadataDao.save(database, metadata));
|
||||||
|
|
||||||
|
metadata = new Metadata();
|
||||||
|
metadata.setValue(Metadata.KEY, "with3");
|
||||||
|
metadata.setValue(Metadata.TASK, task3.getId());
|
||||||
|
assertTrue(metadataDao.save(database, metadata));
|
||||||
|
|
||||||
|
// fetch with tasks and corresponding metadata
|
||||||
|
cursor = metadataDao.fetchDangling(database, KEYS);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
long task2Id = task2.getId();
|
||||||
|
taskDao.delete(database, task2.getId());
|
||||||
|
|
||||||
|
// note: we should not have any dangling, since deleting a task
|
||||||
|
// will automatically delete metadata
|
||||||
|
cursor = metadataDao.fetchDangling(database, KEYS);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
metadata = new Metadata();
|
||||||
|
metadata.setValue(Metadata.KEY, "with2");
|
||||||
|
metadata.setValue(Metadata.TASK, task2Id);
|
||||||
|
assertTrue(metadataDao.save(database, metadata));
|
||||||
|
|
||||||
|
// but if we simulate something bad happening by creating
|
||||||
|
// it manually.. well, what can i say, it should be broken
|
||||||
|
cursor = metadataDao.fetchDangling(database, KEYS);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.moveToFirst();
|
||||||
|
metadata.readFromCursor(cursor, KEYS);
|
||||||
|
assertEquals("with2", metadata.getValue(Metadata.KEY));
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,216 @@
|
|||||||
|
package com.todoroo.astrid.dao;
|
||||||
|
|
||||||
|
import com.todoroo.andlib.service.Autowired;
|
||||||
|
import com.todoroo.andlib.test.data.Property;
|
||||||
|
import com.todoroo.andlib.test.data.TodorooCursor;
|
||||||
|
import com.todoroo.andlib.test.utility.DateUtilities;
|
||||||
|
import com.todoroo.astrid.dao.TaskDao.TaskSql;
|
||||||
|
import com.todoroo.astrid.model.Task;
|
||||||
|
import com.todoroo.astrid.test.DatabaseTestCase;
|
||||||
|
|
||||||
|
public class TaskDaoTests extends DatabaseTestCase {
|
||||||
|
|
||||||
|
public static Property<?>[] IDS = new Property<?>[] { Task.ID };
|
||||||
|
|
||||||
|
public static Property<?>[] TITLES = new Property<?>[] { Task.ID,
|
||||||
|
Task.TITLE };
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
TaskDao taskDao;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test basic task creation, fetch, and save
|
||||||
|
*/
|
||||||
|
public void testTaskCreation() throws Exception {
|
||||||
|
TodorooCursor<Task> cursor = taskDao.fetch(database,
|
||||||
|
IDS, null, null, null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// create task "happy"
|
||||||
|
Task task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "happy");
|
||||||
|
assertTrue(taskDao.save(database, task, false));
|
||||||
|
cursor = taskDao.fetch(database, IDS, null, null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
long happyId = task.getId();
|
||||||
|
assertNotSame(Task.NO_ID, happyId);
|
||||||
|
task = taskDao.fetch(database, TITLES, happyId);
|
||||||
|
assertEquals("happy", task.getValue(Task.TITLE));
|
||||||
|
|
||||||
|
// create task "sad"
|
||||||
|
task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "sad");
|
||||||
|
assertTrue(taskDao.save(database, task, false));
|
||||||
|
cursor = taskDao.fetch(database, IDS, null, null, null);
|
||||||
|
assertEquals(2, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// rename sad to melancholy
|
||||||
|
long sadId = task.getId();
|
||||||
|
assertNotSame(Task.NO_ID, sadId);
|
||||||
|
task.setValue(Task.TITLE, "melancholy");
|
||||||
|
assertTrue(taskDao.save(database, task, false));
|
||||||
|
cursor = taskDao.fetch(database, IDS, null, null, null);
|
||||||
|
assertEquals(2, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// check state
|
||||||
|
task = taskDao.fetch(database, TITLES, happyId);
|
||||||
|
assertEquals("happy", task.getValue(Task.TITLE));
|
||||||
|
task = taskDao.fetch(database, TITLES, sadId);
|
||||||
|
assertEquals("melancholy", task.getValue(Task.TITLE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test various task fetch conditions
|
||||||
|
*/
|
||||||
|
public void testTaskConditions() throws Exception {
|
||||||
|
// create normal task
|
||||||
|
Task task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "normal");
|
||||||
|
assertTrue(taskDao.save(database, task, false));
|
||||||
|
|
||||||
|
// create blank task
|
||||||
|
task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "");
|
||||||
|
assertTrue(taskDao.save(database, task, false));
|
||||||
|
|
||||||
|
// create hidden task
|
||||||
|
task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "hidden");
|
||||||
|
task.setValue(Task.HIDDEN_UNTIL, DateUtilities.now() + 10000);
|
||||||
|
assertTrue(taskDao.save(database, task, false));
|
||||||
|
|
||||||
|
// create task with deadlines
|
||||||
|
task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "deadlineInFuture");
|
||||||
|
task.setValue(Task.DUE_DATE, DateUtilities.now() + 10000);
|
||||||
|
assertTrue(taskDao.save(database, task, false));
|
||||||
|
|
||||||
|
task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "deadlineInPast");
|
||||||
|
task.setValue(Task.DUE_DATE, DateUtilities.now() - 10000);
|
||||||
|
assertTrue(taskDao.save(database, task, false));
|
||||||
|
|
||||||
|
// create completed task
|
||||||
|
task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "completed");
|
||||||
|
task.setValue(Task.COMPLETION_DATE, DateUtilities.now() - 10000);
|
||||||
|
assertTrue(taskDao.save(database, task, false));
|
||||||
|
|
||||||
|
// check has no name
|
||||||
|
TodorooCursor<Task> cursor = taskDao.fetch(database,
|
||||||
|
TITLES, TaskSql.hasNoName(), null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.moveToNext();
|
||||||
|
assertEquals("", cursor.getString(1));
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// check has deadlines
|
||||||
|
cursor = taskDao.fetch(database, TITLES, TaskSql
|
||||||
|
.hasDeadlines(), Task.DUE_DATE + " ASC", null);
|
||||||
|
assertEquals(2, cursor.getCount());
|
||||||
|
cursor.moveToNext();
|
||||||
|
assertEquals("deadlineInPast", cursor.getString(1));
|
||||||
|
cursor.moveToNext();
|
||||||
|
assertEquals("deadlineInFuture", cursor.getString(1));
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// check is active
|
||||||
|
cursor = taskDao.fetch(database, TITLES, TaskSql
|
||||||
|
.isActive(), null, null);
|
||||||
|
assertEquals(5, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// check due before / after
|
||||||
|
cursor = taskDao.fetch(database, TITLES, TaskSql
|
||||||
|
.dueBefore(DateUtilities.now()), null, null);
|
||||||
|
cursor.moveToNext();
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
cursor = taskDao.fetch(database, TITLES, TaskSql
|
||||||
|
.dueAfter(DateUtilities.now()), null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// check completed before
|
||||||
|
cursor = taskDao.fetch(database, TITLES, TaskSql
|
||||||
|
.completedBefore(DateUtilities.now()), null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// check is visible
|
||||||
|
cursor = taskDao.fetch(database, TITLES, TaskSql
|
||||||
|
.isVisible(DateUtilities.now()), null, null);
|
||||||
|
assertEquals(5, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test task deletion
|
||||||
|
*/
|
||||||
|
public void testTDeletion() throws Exception {
|
||||||
|
TodorooCursor<Task> cursor = taskDao.fetch(database,
|
||||||
|
IDS, null, null, null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// create task "happy"
|
||||||
|
Task task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "happy");
|
||||||
|
assertTrue(taskDao.save(database, task, false));
|
||||||
|
cursor = taskDao.fetch(database, IDS, null, null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// delete
|
||||||
|
long happyId = task.getId();
|
||||||
|
assertTrue(taskDao.delete(database, happyId));
|
||||||
|
cursor = taskDao.fetch(database, IDS, null, null, null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test save without prior create doesn't work
|
||||||
|
*/
|
||||||
|
public void testSaveWithoutCreate() throws Exception {
|
||||||
|
TodorooCursor<Task> cursor;
|
||||||
|
|
||||||
|
// try to save task "happy"
|
||||||
|
Task task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "happy");
|
||||||
|
task.setValue(Task.ID, 1L);
|
||||||
|
|
||||||
|
assertFalse(taskDao.save(database, task, false));
|
||||||
|
|
||||||
|
cursor = taskDao.fetch(database, IDS, null, null, null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test passing invalid task indices to various things
|
||||||
|
*/
|
||||||
|
public void testInvalidIndex() throws Exception {
|
||||||
|
TodorooCursor<Task> cursor;
|
||||||
|
|
||||||
|
cursor = taskDao.fetch(database, IDS, null, null, null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
assertNull(taskDao.fetch(database, IDS, 1));
|
||||||
|
|
||||||
|
assertFalse(taskDao.delete(database, 1));
|
||||||
|
|
||||||
|
// make sure db still works
|
||||||
|
cursor = taskDao.fetch(database, IDS, null, null, null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO check eventing
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.timsu.astrid.data.AbstractModel;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/** Abstract controller class. Mostly contains some static fields */
|
||||||
|
abstract public class AbstractController {
|
||||||
|
|
||||||
|
protected Context context;
|
||||||
|
|
||||||
|
// special columns
|
||||||
|
public static final String KEY_ROWID = "_id";
|
||||||
|
|
||||||
|
// database and table names
|
||||||
|
protected static final String TASK_TABLE_NAME = "tasks";
|
||||||
|
protected static final String TAG_TABLE_NAME = "tags";
|
||||||
|
protected static final String TAG_TASK_MAP_NAME = "tagTaskMap";
|
||||||
|
protected static final String ALERT_TABLE_NAME = "alerts";
|
||||||
|
protected static final String SYNC_TABLE_NAME = "sync";
|
||||||
|
|
||||||
|
abstract public void open();
|
||||||
|
abstract public void close();
|
||||||
|
|
||||||
|
// cursor iterator
|
||||||
|
|
||||||
|
public static class CursorIterator<TYPE extends AbstractModel> implements Iterator<TYPE> {
|
||||||
|
Cursor cursor;
|
||||||
|
Class<TYPE> cls;
|
||||||
|
|
||||||
|
public CursorIterator(Cursor cursor, Class<TYPE> cls) {
|
||||||
|
this.cursor = cursor;
|
||||||
|
this.cls = cls;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
return !cursor.isLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TYPE next() {
|
||||||
|
try {
|
||||||
|
TYPE model = cls.getConstructor(Cursor.class).newInstance(cursor);
|
||||||
|
cursor.moveToNext();
|
||||||
|
return model;
|
||||||
|
|
||||||
|
// ugh...
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.e("CursorIterator", e.toString());
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
Log.e("CursorIterator", e.toString());
|
||||||
|
} catch (InstantiationException e) {
|
||||||
|
Log.e("CursorIterator", e.toString());
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
Log.e("CursorIterator", e.toString());
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
Log.e("CursorIterator", e.toString());
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
Log.e("CursorIterator", e.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
throw new UnsupportedOperationException("Can't remove this way");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.database.Cursor;
|
||||||
|
|
||||||
|
/** A data object backed by a database */
|
||||||
|
public abstract class AbstractModel {
|
||||||
|
|
||||||
|
/* Data Source Ordering:
|
||||||
|
*
|
||||||
|
* In order to return the best data, we want to check first what the user
|
||||||
|
* has explicitly set (setValues), then the values we have read out of
|
||||||
|
* the database (values), the database itself (cursor), then defaults
|
||||||
|
* (getDefaultValues)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** User set values */
|
||||||
|
protected ContentValues setValues = new ContentValues();
|
||||||
|
|
||||||
|
/** Cached values from database */
|
||||||
|
private ContentValues values = new ContentValues();
|
||||||
|
|
||||||
|
/** Cursor into the database */
|
||||||
|
private Cursor cursor = null;
|
||||||
|
|
||||||
|
// --- constructors
|
||||||
|
|
||||||
|
/** Construct a model from scratch */
|
||||||
|
public AbstractModel() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Construct a model from a database object */
|
||||||
|
public AbstractModel(Cursor cursor) {
|
||||||
|
this.cursor = cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- data source getters
|
||||||
|
|
||||||
|
/** Get the user-set values for this object */
|
||||||
|
public ContentValues getSetValues() {
|
||||||
|
return setValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the default values for this object */
|
||||||
|
abstract public ContentValues getDefaultValues();
|
||||||
|
|
||||||
|
/** Get a list of all field/value pairs merged across data sources */
|
||||||
|
public ContentValues getMergedValues() {
|
||||||
|
ContentValues mergedValues = new ContentValues();
|
||||||
|
|
||||||
|
mergedValues.putAll(getDefaultValues());
|
||||||
|
mergedValues.putAll(values);
|
||||||
|
mergedValues.putAll(setValues);
|
||||||
|
|
||||||
|
return mergedValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return the database cursor */
|
||||||
|
public Cursor getCursor() {
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- checking against cached values
|
||||||
|
|
||||||
|
protected void putIfChangedFromDatabase(String field, String newValue) {
|
||||||
|
if(!setValues.containsKey(field) && values.containsKey(field)) {
|
||||||
|
String value = values.getAsString(field);
|
||||||
|
if(value == null) {
|
||||||
|
if(newValue == null)
|
||||||
|
return;
|
||||||
|
} else if(value.equals(newValue))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setValues.put(field, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void putIfChangedFromDatabase(String field, Long newValue) {
|
||||||
|
if(!setValues.containsKey(field) && values.containsKey(field)) {
|
||||||
|
Long value = values.getAsLong(field);
|
||||||
|
if(value == null) {
|
||||||
|
if(newValue == null)
|
||||||
|
return;
|
||||||
|
} else if(value.equals(newValue))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setValues.put(field, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void putIfChangedFromDatabase(String field, Integer newValue) {
|
||||||
|
if(!setValues.containsKey(field) && values.containsKey(field)) {
|
||||||
|
Integer value = values.getAsInteger(field);
|
||||||
|
if(value == null) {
|
||||||
|
if(newValue == null)
|
||||||
|
return;
|
||||||
|
} else if(value.equals(newValue))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setValues.put(field, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void putIfChangedFromDatabase(String field, Double newValue) {
|
||||||
|
if(!setValues.containsKey(field) && values.containsKey(field)) {
|
||||||
|
Double value = values.getAsDouble(field);
|
||||||
|
if(value == null) {
|
||||||
|
if(newValue == null)
|
||||||
|
return;
|
||||||
|
} else if(value.equals(newValue))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setValues.put(field, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static final HashMap<Class<?>, HashMap<String, Integer>>
|
||||||
|
columnIndexCache = new HashMap<Class<?>, HashMap<String, Integer>>();
|
||||||
|
private int getColumnIndex(String field) {
|
||||||
|
HashMap<String, Integer> classCache;
|
||||||
|
classCache = columnIndexCache.get(getClass());
|
||||||
|
if(classCache == null) {
|
||||||
|
classCache = new HashMap<String, Integer>();
|
||||||
|
columnIndexCache.put(getClass(), classCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer index = classCache.get(field);
|
||||||
|
if(index == null) {
|
||||||
|
index = cursor.getColumnIndexOrThrow(field);
|
||||||
|
classCache.put(field, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- data retrieval for the different object types
|
||||||
|
|
||||||
|
protected String retrieveString(String field) {
|
||||||
|
if(setValues.containsKey(field))
|
||||||
|
return setValues.getAsString(field);
|
||||||
|
|
||||||
|
if(values.containsKey(field))
|
||||||
|
return values.getAsString(field);
|
||||||
|
|
||||||
|
// if we have a database to hit, do that now
|
||||||
|
if(cursor != null) {
|
||||||
|
String value = cursor.getString(getColumnIndex(field));
|
||||||
|
values.put(field, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do we have defaults?
|
||||||
|
ContentValues defaults = getDefaultValues();
|
||||||
|
if(defaults != null && defaults.containsKey(field))
|
||||||
|
return defaults.getAsString(field);
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException("Could not read field " + field);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Integer retrieveInteger(String field) {
|
||||||
|
if(setValues.containsKey(field))
|
||||||
|
return setValues.getAsInteger(field);
|
||||||
|
|
||||||
|
if(values.containsKey(field))
|
||||||
|
return values.getAsInteger(field);
|
||||||
|
|
||||||
|
// if we have a database to hit, do that now
|
||||||
|
if(cursor != null) {
|
||||||
|
try {
|
||||||
|
Integer value = cursor.getInt(getColumnIndex(field));
|
||||||
|
values.put(field, value);
|
||||||
|
return value;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// error reading from cursor, try to continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// do we have defaults?
|
||||||
|
ContentValues defaults = getDefaultValues();
|
||||||
|
if(defaults != null && defaults.containsKey(field))
|
||||||
|
return defaults.getAsInteger(field);
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException("Could not read field " + field);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Long retrieveLong(String field) {
|
||||||
|
if(setValues.containsKey(field))
|
||||||
|
return setValues.getAsLong(field);
|
||||||
|
|
||||||
|
if(values.containsKey(field))
|
||||||
|
return values.getAsLong(field);
|
||||||
|
|
||||||
|
// if we have a database to hit, do that now
|
||||||
|
if(cursor != null) {
|
||||||
|
Long value = cursor.getLong(getColumnIndex(field));
|
||||||
|
values.put(field, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do we have defaults?
|
||||||
|
ContentValues defaults = getDefaultValues();
|
||||||
|
if(defaults != null && defaults.containsKey(field))
|
||||||
|
return defaults.getAsLong(field);
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException("Could not read field " + field);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Double retrieveDouble(String field) {
|
||||||
|
if(setValues.containsKey(field))
|
||||||
|
return setValues.getAsDouble(field);
|
||||||
|
|
||||||
|
if(values.containsKey(field))
|
||||||
|
return values.getAsDouble(field);
|
||||||
|
|
||||||
|
// if we have a database to hit, do that now
|
||||||
|
if(cursor != null) {
|
||||||
|
Double value = cursor.getDouble(getColumnIndex(field));
|
||||||
|
values.put(field, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do we have defaults?
|
||||||
|
ContentValues defaults = getDefaultValues();
|
||||||
|
if(defaults != null && defaults.containsKey(field))
|
||||||
|
return defaults.getAsDouble(field);
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException("Could not read field " + field);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- retrieving composite objects
|
||||||
|
|
||||||
|
protected Date retrieveDate(String field) {
|
||||||
|
Long time;
|
||||||
|
try {
|
||||||
|
time = retrieveLong(field);
|
||||||
|
if(time == null || time == 0)
|
||||||
|
return null;
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Date(time);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data;
|
||||||
|
|
||||||
|
|
||||||
|
/** Identifier of a single object. Extend this class to create your own */
|
||||||
|
public abstract class Identifier {
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
public Identifier(long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String idAsString() {
|
||||||
|
return Long.toString(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return (int)id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if(o == null || o.getClass() != getClass())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return ((Identifier)o).getId() == getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getClass().getSimpleName() + ": " + id;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.alerts;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractModel;
|
||||||
|
import com.todoroo.astrid.legacy.data.task.TaskIdentifier;
|
||||||
|
|
||||||
|
|
||||||
|
/** A single alert on a task */
|
||||||
|
public class Alert extends AbstractModel {
|
||||||
|
|
||||||
|
/** Version number of this model */
|
||||||
|
static final int VERSION = 1;
|
||||||
|
|
||||||
|
// field names
|
||||||
|
|
||||||
|
static final String TASK = "task";
|
||||||
|
static final String DATE = "date";
|
||||||
|
|
||||||
|
/** Default values container */
|
||||||
|
private static final ContentValues defaultValues = new ContentValues();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ContentValues getDefaultValues() {
|
||||||
|
return defaultValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String[] FIELD_LIST = new String[] {
|
||||||
|
AbstractController.KEY_ROWID,
|
||||||
|
TASK,
|
||||||
|
DATE,
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- database helper
|
||||||
|
|
||||||
|
/** Database Helper manages creating new tables and updating old ones */
|
||||||
|
static class AlertDatabaseHelper extends SQLiteOpenHelper {
|
||||||
|
String tableName;
|
||||||
|
Context context;
|
||||||
|
|
||||||
|
AlertDatabaseHelper(Context context, String databaseName, String tableName) {
|
||||||
|
super(context, databaseName, null, VERSION);
|
||||||
|
this.tableName = tableName;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void onCreate(SQLiteDatabase db) {
|
||||||
|
String sql = new StringBuilder().
|
||||||
|
append("CREATE TABLE IF NOT EXISTS ").append(tableName).append(" (").
|
||||||
|
append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, ").
|
||||||
|
append(TASK).append(" integer not null,").
|
||||||
|
append(DATE).append(" integer not null,").
|
||||||
|
append("unique (").append(TASK).append(",").append(DATE).append(")").
|
||||||
|
append(");").toString();
|
||||||
|
db.execSQL(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
|
Log.w(getClass().getSimpleName(), "Upgrading database from version " +
|
||||||
|
oldVersion + " to " + newVersion + ".");
|
||||||
|
|
||||||
|
switch(oldVersion) {
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Alerts: Unsupported migration from " + oldVersion + " to " + newVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- constructor pass-through
|
||||||
|
|
||||||
|
Alert(TaskIdentifier task, Date date) {
|
||||||
|
super();
|
||||||
|
setTask(task);
|
||||||
|
setDate(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Alert(Cursor cursor) {
|
||||||
|
super(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- getters and setters: expose them as you see fit
|
||||||
|
|
||||||
|
public boolean isNew() {
|
||||||
|
return getCursor() == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TaskIdentifier getTask() {
|
||||||
|
return new TaskIdentifier(retrieveLong(TASK));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getDate() {
|
||||||
|
return new Date(retrieveLong(DATE));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setTask(TaskIdentifier task) {
|
||||||
|
setValues.put(TASK, task.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDate(Date date) {
|
||||||
|
setValues.put(DATE, date.getTime());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.alerts;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.SQLException;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
import com.todoroo.astrid.legacy.data.alerts.Alert.AlertDatabaseHelper;
|
||||||
|
import com.todoroo.astrid.legacy.data.task.TaskIdentifier;
|
||||||
|
|
||||||
|
/** Controller for Tag-related operations */
|
||||||
|
public class AlertController extends AbstractController {
|
||||||
|
|
||||||
|
private SQLiteDatabase alertDatabase;
|
||||||
|
|
||||||
|
/** Get a cursor to tag identifiers */
|
||||||
|
public Cursor getTaskAlertsCursor(TaskIdentifier taskId) throws SQLException {
|
||||||
|
Cursor cursor = alertDatabase.query(ALERT_TABLE_NAME,
|
||||||
|
Alert.FIELD_LIST, Alert.TASK + " = ?",
|
||||||
|
new String[] { taskId.idAsString() }, null, null, null);
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a list of alerts for the given task */
|
||||||
|
public List<Date> getTaskAlerts(TaskIdentifier
|
||||||
|
taskId) throws SQLException {
|
||||||
|
List<Date> list = new LinkedList<Date>();
|
||||||
|
Cursor cursor = alertDatabase.query(ALERT_TABLE_NAME,
|
||||||
|
Alert.FIELD_LIST, Alert.TASK + " = ?",
|
||||||
|
new String[] { taskId.idAsString() }, null, null, null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(cursor.getCount() == 0)
|
||||||
|
return list;
|
||||||
|
do {
|
||||||
|
cursor.moveToNext();
|
||||||
|
list.add(new Alert(cursor).getDate());
|
||||||
|
} while(!cursor.isLast());
|
||||||
|
|
||||||
|
return list;
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Get a list of alerts that are set for the future */
|
||||||
|
public Set<TaskIdentifier> getTasksWithActiveAlerts() throws SQLException {
|
||||||
|
Set<TaskIdentifier> list = new HashSet<TaskIdentifier>();
|
||||||
|
Cursor cursor = alertDatabase.query(ALERT_TABLE_NAME,
|
||||||
|
Alert.FIELD_LIST, Alert.DATE + " > ?",
|
||||||
|
new String[] { Long.toString(System.currentTimeMillis()) }, null, null, null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(cursor.getCount() == 0)
|
||||||
|
return list;
|
||||||
|
do {
|
||||||
|
cursor.moveToNext();
|
||||||
|
list.add(new Alert(cursor).getTask());
|
||||||
|
} while(!cursor.isLast());
|
||||||
|
|
||||||
|
return list;
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Remove all alerts from the task */
|
||||||
|
public boolean removeAlerts(TaskIdentifier taskId)
|
||||||
|
throws SQLException{
|
||||||
|
return alertDatabase.delete(ALERT_TABLE_NAME,
|
||||||
|
String.format("%s = ?",
|
||||||
|
Alert.TASK),
|
||||||
|
new String[] { taskId.idAsString() }) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add the given tag to the task */
|
||||||
|
public boolean addAlert(TaskIdentifier taskId, Date date)
|
||||||
|
throws SQLException {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(Alert.DATE, date.getTime());
|
||||||
|
values.put(Alert.TASK, taskId.getId());
|
||||||
|
return alertDatabase.insert(ALERT_TABLE_NAME, Alert.TASK,
|
||||||
|
values) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- boilerplate
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor - takes the context to allow the database to be
|
||||||
|
* opened/created
|
||||||
|
*/
|
||||||
|
public AlertController(Context context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the notes database. If it cannot be opened, try to create a new
|
||||||
|
* instance of the database. If it cannot be created, throw an exception to
|
||||||
|
* signal the failure
|
||||||
|
*
|
||||||
|
* @return this (self reference, allowing this to be chained in an
|
||||||
|
* initialization call)
|
||||||
|
* @throws SQLException if the database could be neither opened or created
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void open() throws SQLException {
|
||||||
|
alertDatabase = new AlertDatabaseHelper(context,
|
||||||
|
ALERT_TABLE_NAME, ALERT_TABLE_NAME).getWritableDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Closes database resource */
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
alertDatabase.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.enums;
|
||||||
|
|
||||||
|
import com.timsu.astrid.R;
|
||||||
|
|
||||||
|
public enum Importance {
|
||||||
|
// MOST IMPORTANT
|
||||||
|
|
||||||
|
LEVEL_1(R.string.importance_1,
|
||||||
|
R.color.importance_1,
|
||||||
|
R.color.task_list_importance_1),
|
||||||
|
LEVEL_2(R.string.importance_2,
|
||||||
|
R.color.importance_2,
|
||||||
|
R.color.task_list_importance_2),
|
||||||
|
LEVEL_3(R.string.importance_3,
|
||||||
|
R.color.importance_3,
|
||||||
|
R.color.task_list_importance_3),
|
||||||
|
LEVEL_4(R.string.importance_4,
|
||||||
|
R.color.importance_4,
|
||||||
|
R.color.task_list_importance_4),
|
||||||
|
|
||||||
|
// LEAST IMPORTANT
|
||||||
|
;
|
||||||
|
|
||||||
|
int label;
|
||||||
|
int color;
|
||||||
|
int taskListColor;
|
||||||
|
public static final Importance DEFAULT = LEVEL_3;
|
||||||
|
|
||||||
|
private Importance(int label, int color, int taskListColor) {
|
||||||
|
this.label = label;
|
||||||
|
this.color = color;
|
||||||
|
this.taskListColor = taskListColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLabelResource() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColorResource() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTaskListColor() {
|
||||||
|
return taskListColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.enums;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import android.content.res.Resources;
|
||||||
|
|
||||||
|
import com.timsu.astrid.R;
|
||||||
|
|
||||||
|
public enum RepeatInterval {
|
||||||
|
|
||||||
|
DAYS(R.string.repeat_days) {
|
||||||
|
@Override
|
||||||
|
public void offsetDateBy(Date input, int number) {
|
||||||
|
input.setDate(input.getDate() + number);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
WEEKS(R.string.repeat_weeks) {
|
||||||
|
@Override
|
||||||
|
public void offsetDateBy(Date input, int number) {
|
||||||
|
input.setDate(input.getDate() + 7 * number);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MONTHS(R.string.repeat_months) {
|
||||||
|
@Override
|
||||||
|
public void offsetDateBy(Date input, int number) {
|
||||||
|
input.setMonth(input.getMonth() + number);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
HOURS(R.string.repeat_hours) {
|
||||||
|
@Override
|
||||||
|
public void offsetDateBy(Date input, int number) {
|
||||||
|
input.setHours(input.getHours() + number);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
int label;
|
||||||
|
|
||||||
|
private RepeatInterval(int label) {
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLabelResource() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public void offsetDateBy(Date input, int number);
|
||||||
|
|
||||||
|
public static String[] getLabels(Resources r) {
|
||||||
|
int intervalCount = RepeatInterval.values().length;
|
||||||
|
String[] result = new String[intervalCount];
|
||||||
|
|
||||||
|
for(int i = 0; i < intervalCount; i++)
|
||||||
|
result[i] = r.getString(RepeatInterval.values()[i].getLabelResource());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.sync;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.SQLException;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
import com.todoroo.astrid.legacy.data.sync.SyncMapping.SyncMappingDatabaseHelper;
|
||||||
|
import com.todoroo.astrid.legacy.data.task.AbstractTaskModel;
|
||||||
|
import com.todoroo.astrid.legacy.data.task.TaskIdentifier;
|
||||||
|
import com.todoroo.astrid.legacy.data.task.TaskModelForSync;
|
||||||
|
|
||||||
|
/** Controller for Tag-related operations */
|
||||||
|
public class SyncDataController extends AbstractController {
|
||||||
|
|
||||||
|
private SQLiteDatabase syncDatabase;
|
||||||
|
|
||||||
|
|
||||||
|
// --- updated tasks list
|
||||||
|
|
||||||
|
/** Mark all updated tasks as finished synchronizing */
|
||||||
|
public boolean clearUpdatedTaskList(int syncServiceId) throws SQLException {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(SyncMapping.UPDATED, 0);
|
||||||
|
return syncDatabase.update(SYNC_TABLE_NAME, values,
|
||||||
|
SyncMapping.SYNC_SERVICE + " = " + syncServiceId, null) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicate that this task's properties were updated */
|
||||||
|
public boolean addToUpdatedList(TaskIdentifier taskId) throws SQLException {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(SyncMapping.UPDATED, 1);
|
||||||
|
return syncDatabase.update(SYNC_TABLE_NAME, values,
|
||||||
|
SyncMapping.TASK + " = " + taskId.getId(), null) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void taskUpdated(Context context, AbstractTaskModel task) {
|
||||||
|
if(!(task instanceof TaskModelForSync)) {
|
||||||
|
SyncDataController syncController = new SyncDataController(context);
|
||||||
|
syncController.open();
|
||||||
|
syncController.addToUpdatedList(task.getTaskIdentifier());
|
||||||
|
syncController.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- sync mapping
|
||||||
|
|
||||||
|
/** Get all mappings for the given synchronization service */
|
||||||
|
public HashSet<SyncMapping> getSyncMappings(int syncServiceId) throws SQLException {
|
||||||
|
HashSet<SyncMapping> list = new HashSet<SyncMapping>();
|
||||||
|
Cursor cursor = syncDatabase.query(SYNC_TABLE_NAME,
|
||||||
|
SyncMapping.FIELD_LIST,
|
||||||
|
SyncMapping.SYNC_SERVICE + " = " + syncServiceId,
|
||||||
|
null, null, null, null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(cursor.getCount() == 0)
|
||||||
|
return list;
|
||||||
|
do {
|
||||||
|
cursor.moveToNext();
|
||||||
|
list.add(new SyncMapping(cursor));
|
||||||
|
} while(!cursor.isLast());
|
||||||
|
|
||||||
|
return list;
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get all mappings for specified task for all synchronization services */
|
||||||
|
public HashSet<SyncMapping> getSyncMappings(TaskIdentifier taskId)
|
||||||
|
throws SQLException {
|
||||||
|
HashSet<SyncMapping> list = new HashSet<SyncMapping>();
|
||||||
|
Cursor cursor = syncDatabase.query(SYNC_TABLE_NAME,
|
||||||
|
SyncMapping.FIELD_LIST,
|
||||||
|
SyncMapping.TASK + " = ?",
|
||||||
|
new String[] { "" + taskId.getId() },
|
||||||
|
null, null, null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(cursor.getCount() == 0)
|
||||||
|
return list;
|
||||||
|
do {
|
||||||
|
cursor.moveToNext();
|
||||||
|
list.add(new SyncMapping(cursor));
|
||||||
|
} while(!cursor.isLast());
|
||||||
|
|
||||||
|
return list;
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get mapping for given task */
|
||||||
|
public SyncMapping getSyncMapping(int syncServiceId, TaskIdentifier taskId)
|
||||||
|
throws SQLException {
|
||||||
|
Cursor cursor = syncDatabase.query(SYNC_TABLE_NAME,
|
||||||
|
SyncMapping.FIELD_LIST,
|
||||||
|
SyncMapping.SYNC_SERVICE + " = ? AND " +
|
||||||
|
SyncMapping.TASK + " = ?",
|
||||||
|
new String[] { "" + syncServiceId, "" + taskId.getId() },
|
||||||
|
null, null, null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(cursor.getCount() == 0)
|
||||||
|
return null;
|
||||||
|
cursor.moveToNext();
|
||||||
|
return new SyncMapping(cursor);
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Saves the given task to the database. Returns true on success. */
|
||||||
|
public boolean saveSyncMapping(SyncMapping mapping) {
|
||||||
|
long newRow = syncDatabase.insert(SYNC_TABLE_NAME, SyncMapping.TASK,
|
||||||
|
mapping.getMergedValues());
|
||||||
|
|
||||||
|
mapping.setId(newRow);
|
||||||
|
|
||||||
|
return newRow >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Deletes the given mapping. Returns true on success */
|
||||||
|
public boolean deleteSyncMapping(SyncMapping mapping) {
|
||||||
|
// was never saved
|
||||||
|
if(mapping.getId() == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return syncDatabase.delete(SYNC_TABLE_NAME, KEY_ROWID + "=" +
|
||||||
|
mapping.getId(), null) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Deletes the given mapping. Returns true on success */
|
||||||
|
public boolean deleteAllMappings(int syncServiceId) {
|
||||||
|
return syncDatabase.delete(SYNC_TABLE_NAME, SyncMapping.SYNC_SERVICE +
|
||||||
|
"=" + syncServiceId, null) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- boilerplate
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor - takes the context to allow the database to be
|
||||||
|
* opened/created
|
||||||
|
*/
|
||||||
|
public SyncDataController(Context context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the notes database. If it cannot be opened, try to create a new
|
||||||
|
* instance of the database. If it cannot be created, throw an exception to
|
||||||
|
* signal the failure
|
||||||
|
*
|
||||||
|
* @return this (self reference, allowing this to be chained in an
|
||||||
|
* initialization call)
|
||||||
|
* @throws SQLException if the database could be neither opened or created
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public synchronized void open() throws SQLException {
|
||||||
|
SQLiteOpenHelper helper = new SyncMappingDatabaseHelper(context,
|
||||||
|
SYNC_TABLE_NAME, SYNC_TABLE_NAME);
|
||||||
|
syncDatabase = helper.getWritableDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Closes database resource */
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
syncDatabase.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.sync;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractModel;
|
||||||
|
import com.todoroo.astrid.legacy.data.task.TaskIdentifier;
|
||||||
|
|
||||||
|
|
||||||
|
/** A single tag on a task */
|
||||||
|
public class SyncMapping extends AbstractModel {
|
||||||
|
|
||||||
|
|
||||||
|
/** Version number of this model */
|
||||||
|
static final int VERSION = 1;
|
||||||
|
|
||||||
|
// field names
|
||||||
|
|
||||||
|
static final String TASK = "task";
|
||||||
|
static final String SYNC_SERVICE = "service";
|
||||||
|
static final String REMOTE_ID = "remoteId";
|
||||||
|
static final String UPDATED = "updated";
|
||||||
|
|
||||||
|
/** Default values container */
|
||||||
|
private static final ContentValues defaultValues = new ContentValues();
|
||||||
|
static {
|
||||||
|
defaultValues.put(UPDATED, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ContentValues getDefaultValues() {
|
||||||
|
return defaultValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String[] FIELD_LIST = new String[] {
|
||||||
|
AbstractController.KEY_ROWID,
|
||||||
|
TASK,
|
||||||
|
SYNC_SERVICE,
|
||||||
|
REMOTE_ID,
|
||||||
|
UPDATED,
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- database helper
|
||||||
|
|
||||||
|
/** Database Helper manages creating new tables and updating old ones */
|
||||||
|
static class SyncMappingDatabaseHelper extends SQLiteOpenHelper {
|
||||||
|
String tableName;
|
||||||
|
Context context;
|
||||||
|
|
||||||
|
SyncMappingDatabaseHelper(Context context, String databaseName, String tableName) {
|
||||||
|
super(context, databaseName, null, VERSION);
|
||||||
|
this.tableName = tableName;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void onCreate(SQLiteDatabase db) {
|
||||||
|
String sql = new StringBuilder().
|
||||||
|
append("CREATE TABLE IF NOT EXISTS ").append(tableName).append(" (").
|
||||||
|
append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, ").
|
||||||
|
append(TASK).append(" integer not null,").
|
||||||
|
append(SYNC_SERVICE).append(" integer not null,").
|
||||||
|
append(REMOTE_ID).append(" text not null,").
|
||||||
|
append(UPDATED).append(" integer not null,").
|
||||||
|
append("unique (").append(TASK).append(",").append(SYNC_SERVICE).append(")").
|
||||||
|
append(");").toString();
|
||||||
|
db.execSQL(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
|
Log.w(getClass().getSimpleName(), "Upgrading database from version " +
|
||||||
|
oldVersion + " to " + newVersion + ".");
|
||||||
|
|
||||||
|
switch(oldVersion) {
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Sync: Unsupported migration from " + oldVersion + " to " + newVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- constructor pass-through
|
||||||
|
|
||||||
|
public SyncMapping(TaskIdentifier task, int syncServiceId, String remoteId) {
|
||||||
|
super();
|
||||||
|
setTask(task);
|
||||||
|
setSyncServiceId(syncServiceId);
|
||||||
|
setRemoteId(remoteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
SyncMapping(Cursor cursor) {
|
||||||
|
super(cursor);
|
||||||
|
getId();
|
||||||
|
getTask();
|
||||||
|
getSyncServiceId();
|
||||||
|
getRemoteId();
|
||||||
|
isUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- getters and setters
|
||||||
|
|
||||||
|
public void setId(long id) {
|
||||||
|
putIfChangedFromDatabase(AbstractController.KEY_ROWID, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getId() {
|
||||||
|
try {
|
||||||
|
return retrieveLong(AbstractController.KEY_ROWID);
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TaskIdentifier getTask() {
|
||||||
|
return new TaskIdentifier(retrieveLong(TASK));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSyncServiceId() {
|
||||||
|
return retrieveInteger(SYNC_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRemoteId() {
|
||||||
|
return retrieveString(REMOTE_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUpdated() {
|
||||||
|
return retrieveInteger(UPDATED) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setTask(TaskIdentifier task) {
|
||||||
|
setValues.put(TASK, task.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSyncServiceId(int id) {
|
||||||
|
setValues.put(SYNC_SERVICE, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setRemoteId(String remoteId) {
|
||||||
|
setValues.put(REMOTE_ID, remoteId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.tag;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractModel;
|
||||||
|
|
||||||
|
|
||||||
|
/** Abstract model of a task. Subclasses implement the getters and setters
|
||||||
|
* they are interested in.
|
||||||
|
*
|
||||||
|
* @author timsu
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class AbstractTagModel extends AbstractModel {
|
||||||
|
|
||||||
|
/** Version number of this model */
|
||||||
|
static final int VERSION = 1;
|
||||||
|
|
||||||
|
// field names
|
||||||
|
|
||||||
|
static final String NAME = "name";
|
||||||
|
static final String NOTES = "notes";
|
||||||
|
// reserved fields
|
||||||
|
static final String ICON = "icon";
|
||||||
|
static final String PARENT = "parent";
|
||||||
|
static final String FLAGS = "flags";
|
||||||
|
static final String LOCATION_LAT = "locationLat";
|
||||||
|
static final String LOCATION_LONG = "locationLong";
|
||||||
|
static final String NOTIFICATIONS = "notifications";
|
||||||
|
// end reserved fields
|
||||||
|
static final String CREATION_DATE = "creationDate";
|
||||||
|
|
||||||
|
/** Default values container */
|
||||||
|
private static final ContentValues defaultValues = new ContentValues();
|
||||||
|
|
||||||
|
static {
|
||||||
|
defaultValues.put(NAME, "");
|
||||||
|
defaultValues.put(NOTES, "");
|
||||||
|
defaultValues.put(ICON, 0);
|
||||||
|
defaultValues.put(PARENT, 0);
|
||||||
|
defaultValues.put(FLAGS, 0);
|
||||||
|
defaultValues.put(LOCATION_LAT, 0);
|
||||||
|
defaultValues.put(LOCATION_LONG, 0);
|
||||||
|
defaultValues.put(NOTIFICATIONS, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ContentValues getDefaultValues() {
|
||||||
|
return defaultValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- database helper
|
||||||
|
|
||||||
|
/** Database Helper manages creating new tables and updating old ones */
|
||||||
|
static class TagModelDatabaseHelper extends SQLiteOpenHelper {
|
||||||
|
String tableName;
|
||||||
|
Context context;
|
||||||
|
|
||||||
|
TagModelDatabaseHelper(Context context, String databaseName, String tableName) {
|
||||||
|
super(context, databaseName, null, VERSION);
|
||||||
|
this.tableName = tableName;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void onCreate(SQLiteDatabase db) {
|
||||||
|
String sql = new StringBuilder().
|
||||||
|
append("CREATE TABLE IF NOT EXISTS ").append(tableName).append(" (").
|
||||||
|
append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, ").
|
||||||
|
append(NAME).append(" text unique,").
|
||||||
|
append(NOTES).append(" text,").
|
||||||
|
append(ICON).append(" integer,").
|
||||||
|
append(PARENT).append(" integer,").
|
||||||
|
append(FLAGS).append(" integer,").
|
||||||
|
append(LOCATION_LAT).append(" integer,").
|
||||||
|
append(LOCATION_LONG).append(" integer,").
|
||||||
|
append(NOTIFICATIONS).append(" integer,").
|
||||||
|
append(CREATION_DATE).append(" integer").
|
||||||
|
append(");").toString();
|
||||||
|
db.execSQL(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
|
Log.w(getClass().getSimpleName(), "Upgrading database from version " +
|
||||||
|
oldVersion + " to " + newVersion + ".");
|
||||||
|
|
||||||
|
switch(oldVersion) {
|
||||||
|
default:
|
||||||
|
// we don't know how to handle it... show an error
|
||||||
|
throw new RuntimeException("Tags: Unsupported migration from " + oldVersion + " to " + newVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- utility methods
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// --- identifier
|
||||||
|
|
||||||
|
private TagIdentifier identifier = null;
|
||||||
|
|
||||||
|
public TagIdentifier getTagIdentifier() {
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTagIdentifier(TagIdentifier identifier) {
|
||||||
|
this.identifier = identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- constructor pass-through
|
||||||
|
|
||||||
|
AbstractTagModel() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read identifier from database */
|
||||||
|
AbstractTagModel(Cursor cursor) {
|
||||||
|
super(cursor);
|
||||||
|
|
||||||
|
Integer id = retrieveInteger(AbstractController.KEY_ROWID);
|
||||||
|
setTagIdentifier(new TagIdentifier(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get identifier from argument */
|
||||||
|
AbstractTagModel(TagIdentifier identifier, Cursor cursor) {
|
||||||
|
super(cursor);
|
||||||
|
|
||||||
|
setTagIdentifier(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- getters and setters: expose them as you see fit
|
||||||
|
|
||||||
|
protected String getName() {
|
||||||
|
return retrieveString(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getNotes() {
|
||||||
|
return retrieveString(NOTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Date getCreationDate() {
|
||||||
|
return retrieveDate(CREATION_DATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- setters
|
||||||
|
|
||||||
|
protected void setName(String name) {
|
||||||
|
setValues.put(NAME, name.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setNotes(String notes) {
|
||||||
|
setValues.put(NOTES, notes);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setCreationDate(Date creationDate) {
|
||||||
|
putDate(setValues, CREATION_DATE, creationDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- utility methods
|
||||||
|
|
||||||
|
static void putDate(ContentValues cv, String fieldName, Date date) {
|
||||||
|
if(date == null)
|
||||||
|
cv.put(fieldName, (Long)null);
|
||||||
|
else
|
||||||
|
cv.put(fieldName, date.getTime());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,320 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.tag;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.SQLException;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
|
||||||
|
import com.timsu.astrid.provider.TasksProvider;
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
import com.todoroo.astrid.legacy.data.tag.AbstractTagModel.TagModelDatabaseHelper;
|
||||||
|
import com.todoroo.astrid.legacy.data.tag.TagToTaskMapping.TagToTaskMappingDatabaseHelper;
|
||||||
|
import com.todoroo.astrid.legacy.data.task.TaskIdentifier;
|
||||||
|
import com.todoroo.astrid.legacy.data.task.AbstractTaskModel.TaskModelDatabaseHelper;
|
||||||
|
|
||||||
|
/** Controller for Tag-related operations */
|
||||||
|
public class TagController extends AbstractController {
|
||||||
|
|
||||||
|
private SQLiteDatabase tagDatabase, tagToTaskMapDatabase;
|
||||||
|
|
||||||
|
// --- tag batch operations
|
||||||
|
|
||||||
|
/** Get a list of all tags */
|
||||||
|
public LinkedList<TagModelForView> getAllTags()
|
||||||
|
throws SQLException {
|
||||||
|
LinkedList<TagModelForView> list = new LinkedList<TagModelForView>();
|
||||||
|
Cursor cursor = tagDatabase.query(TAG_TABLE_NAME,
|
||||||
|
TagModelForView.FIELD_LIST, null, null, null, null, null, null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(cursor.getCount() == 0)
|
||||||
|
return list;
|
||||||
|
do {
|
||||||
|
cursor.moveToNext();
|
||||||
|
list.add(new TagModelForView(cursor));
|
||||||
|
} while(!cursor.isLast());
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- tag to task map batch operations
|
||||||
|
|
||||||
|
/** Get a list of all tags as an id => tag map */
|
||||||
|
public HashMap<TagIdentifier, TagModelForView> getAllTagsAsMap() throws SQLException {
|
||||||
|
HashMap<TagIdentifier, TagModelForView> map = new HashMap<TagIdentifier, TagModelForView>();
|
||||||
|
for(TagModelForView tag : getAllTags())
|
||||||
|
map.put(tag.getTagIdentifier(), tag);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a list of tag identifiers for the given task */
|
||||||
|
public LinkedList<TagIdentifier> getTaskTags(TaskIdentifier
|
||||||
|
taskId) throws SQLException {
|
||||||
|
LinkedList<TagIdentifier> list = new LinkedList<TagIdentifier>();
|
||||||
|
Cursor cursor = tagToTaskMapDatabase.query(TAG_TASK_MAP_NAME,
|
||||||
|
TagToTaskMapping.FIELD_LIST, TagToTaskMapping.TASK + " = ?",
|
||||||
|
new String[] { taskId.idAsString() }, null, null, null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(cursor.getCount() == 0)
|
||||||
|
return list;
|
||||||
|
do {
|
||||||
|
cursor.moveToNext();
|
||||||
|
list.add(new TagToTaskMapping(cursor).getTag());
|
||||||
|
} while(!cursor.isLast());
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a list of task identifiers for the given tag.
|
||||||
|
* This searches for TAGGED tasks only.
|
||||||
|
* Use getUntaggedTasks() to get a list of UNTAGGED tasks **/
|
||||||
|
public LinkedList<TaskIdentifier> getTaggedTasks(TagIdentifier tagId)
|
||||||
|
throws SQLException {
|
||||||
|
LinkedList<TaskIdentifier> list = new LinkedList<TaskIdentifier>();
|
||||||
|
Cursor cursor = tagToTaskMapDatabase.query(TAG_TASK_MAP_NAME,
|
||||||
|
TagToTaskMapping.FIELD_LIST, TagToTaskMapping.TAG + " = ?",
|
||||||
|
new String[] { tagId.idAsString() }, null, null, null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(cursor.getCount() == 0)
|
||||||
|
return list;
|
||||||
|
do {
|
||||||
|
cursor.moveToNext();
|
||||||
|
list.add(new TagToTaskMapping(cursor).getTask());
|
||||||
|
} while(!cursor.isLast());
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a list of task identifiers in the provided set that are UNtagged.
|
||||||
|
*
|
||||||
|
* The calling SubActivity must provide the set of tasks, since
|
||||||
|
* TagController cannot access the appropriate instance of TaskController.
|
||||||
|
*
|
||||||
|
* The current implementation is not very efficient, because queries
|
||||||
|
* the TagToTask map once for each active task.
|
||||||
|
**/
|
||||||
|
public LinkedList<TaskIdentifier> getUntaggedTasks() throws SQLException {
|
||||||
|
HashSet<Long> ids = new HashSet<Long>();
|
||||||
|
|
||||||
|
String[] tagMapColumns = new String[] { TagToTaskMapping.TASK };
|
||||||
|
Cursor tagMapCursor = tagToTaskMapDatabase.query(TAG_TASK_MAP_NAME,
|
||||||
|
tagMapColumns, null, null, TagToTaskMapping.TASK, null,
|
||||||
|
TagToTaskMapping.TASK + " ASC");
|
||||||
|
|
||||||
|
SQLiteDatabase taskDatabase = new TaskModelDatabaseHelper(context,
|
||||||
|
TASK_TABLE_NAME, TASK_TABLE_NAME).getReadableDatabase();
|
||||||
|
String[] taskColumns = new String[] { KEY_ROWID };
|
||||||
|
Cursor taskCursor = taskDatabase.query(TASK_TABLE_NAME, taskColumns,
|
||||||
|
null, null, null, null, KEY_ROWID + " ASC");
|
||||||
|
|
||||||
|
LinkedList<TaskIdentifier> list = new LinkedList<TaskIdentifier>();
|
||||||
|
try {
|
||||||
|
if(taskCursor.getCount() == 0)
|
||||||
|
return list;
|
||||||
|
|
||||||
|
do {
|
||||||
|
taskCursor.moveToNext();
|
||||||
|
ids.add(taskCursor.getLong(0));
|
||||||
|
} while(!taskCursor.isLast());
|
||||||
|
|
||||||
|
if(tagMapCursor.getCount() > 0) {
|
||||||
|
do {
|
||||||
|
tagMapCursor.moveToNext();
|
||||||
|
ids.remove(tagMapCursor.getLong(0));
|
||||||
|
} while(!tagMapCursor.isLast());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
taskCursor.close();
|
||||||
|
tagMapCursor.close();
|
||||||
|
taskDatabase.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Long id : ids)
|
||||||
|
list.add(new TaskIdentifier(id));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- single tag operations
|
||||||
|
|
||||||
|
public TagIdentifier createTag(String name) throws SQLException {
|
||||||
|
if(name == null)
|
||||||
|
throw new NullPointerException("Name can't be null");
|
||||||
|
|
||||||
|
TagModelForView newTag = new TagModelForView(name);
|
||||||
|
long row = tagDatabase.insertOrThrow(TAG_TABLE_NAME, AbstractTagModel.NAME,
|
||||||
|
newTag.getMergedValues());
|
||||||
|
return new TagIdentifier(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates or saves the given tag */
|
||||||
|
public boolean saveTag(AbstractTagModel tag) throws SQLException {
|
||||||
|
boolean saveSucessful;
|
||||||
|
|
||||||
|
if(tag.getTagIdentifier() == null) {
|
||||||
|
long newRow = tagDatabase.insert(TAG_TABLE_NAME, AbstractTagModel.NAME,
|
||||||
|
tag.getMergedValues());
|
||||||
|
tag.setTagIdentifier(new TagIdentifier(newRow));
|
||||||
|
|
||||||
|
saveSucessful = newRow >= 0;
|
||||||
|
} else {
|
||||||
|
long id = tag.getTagIdentifier().getId();
|
||||||
|
saveSucessful = tagDatabase.update(TAG_TABLE_NAME, tag.getSetValues(),
|
||||||
|
KEY_ROWID + "=" + id, null) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return saveSucessful;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a TaskModelForView corresponding to the given Tag Name */
|
||||||
|
public TagModelForView fetchTagFromName(String name) throws SQLException {
|
||||||
|
Cursor cursor = tagDatabase.query(true, TAG_TABLE_NAME,
|
||||||
|
TagModelForView.FIELD_LIST,
|
||||||
|
AbstractTagModel.NAME + " = ?", new String[] {name}, null, null, null, null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (cursor != null && cursor.getCount() > 0) {
|
||||||
|
cursor.moveToFirst();
|
||||||
|
TagModelForView model = new TagModelForView(cursor);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if(cursor != null)
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a TaskModelForView corresponding to the given TagIdentifier */
|
||||||
|
public TagModelForView fetchTagForView(TagIdentifier tagId) throws SQLException {
|
||||||
|
long id = tagId.getId();
|
||||||
|
Cursor cursor = tagDatabase.query(true, TAG_TABLE_NAME,
|
||||||
|
TagModelForView.FIELD_LIST,
|
||||||
|
KEY_ROWID + "=" + id, null, null, null, null, null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.moveToFirst();
|
||||||
|
TagModelForView model = new TagModelForView(cursor);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new SQLException("Returned empty set!");
|
||||||
|
} finally {
|
||||||
|
if(cursor != null)
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Deletes the tag and removes tag/task mappings */
|
||||||
|
public boolean deleteTag( TagIdentifier tagId)
|
||||||
|
throws SQLException{
|
||||||
|
if(tagToTaskMapDatabase.delete(TAG_TASK_MAP_NAME,
|
||||||
|
TagToTaskMapping.TAG + " = " + tagId.idAsString(), null) < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int res = tagDatabase.delete(TAG_TABLE_NAME,
|
||||||
|
KEY_ROWID + " = " + tagId.idAsString(), null);
|
||||||
|
|
||||||
|
return res > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- single tag to task operations
|
||||||
|
|
||||||
|
/** Remove the given tag from the task */
|
||||||
|
public boolean removeTag(TaskIdentifier taskId, TagIdentifier tagId)
|
||||||
|
throws SQLException{
|
||||||
|
|
||||||
|
int res = tagToTaskMapDatabase.delete(TAG_TASK_MAP_NAME,
|
||||||
|
String.format("%s = ? AND %s = ?",
|
||||||
|
TagToTaskMapping.TAG, TagToTaskMapping.TASK),
|
||||||
|
new String[] { tagId.idAsString(), taskId.idAsString() });
|
||||||
|
|
||||||
|
// notify modification
|
||||||
|
TasksProvider.notifyDatabaseModification();
|
||||||
|
|
||||||
|
return res > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add the given tag to the task */
|
||||||
|
public boolean addTag(TaskIdentifier taskId, TagIdentifier tagId)
|
||||||
|
throws SQLException {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(TagToTaskMapping.TAG, tagId.getId());
|
||||||
|
values.put(TagToTaskMapping.TASK, taskId.getId());
|
||||||
|
|
||||||
|
long res = tagToTaskMapDatabase.insert(TAG_TASK_MAP_NAME, TagToTaskMapping.TAG,
|
||||||
|
values);
|
||||||
|
|
||||||
|
return res >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- boilerplate
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor - takes the context to allow the database to be
|
||||||
|
* opened/created
|
||||||
|
*/
|
||||||
|
public TagController(Context context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the notes database. If it cannot be opened, try to create a new
|
||||||
|
* instance of the database. If it cannot be created, throw an exception to
|
||||||
|
* signal the failure
|
||||||
|
*
|
||||||
|
* @return this (self reference, allowing this to be chained in an
|
||||||
|
* initialization call)
|
||||||
|
* @throws SQLException if the database could be neither opened or created
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public synchronized void open() throws SQLException {
|
||||||
|
tagToTaskMapDatabase = new TagToTaskMappingDatabaseHelper(context,
|
||||||
|
TAG_TASK_MAP_NAME, TAG_TASK_MAP_NAME).getWritableDatabase();
|
||||||
|
tagDatabase = new TagModelDatabaseHelper(context,
|
||||||
|
TAG_TABLE_NAME, TAG_TABLE_NAME).getWritableDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Closes database resource */
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
tagDatabase.close();
|
||||||
|
tagToTaskMapDatabase.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.tag;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.Identifier;
|
||||||
|
|
||||||
|
|
||||||
|
public class TagIdentifier extends Identifier {
|
||||||
|
|
||||||
|
public TagIdentifier(long id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.tag;
|
||||||
|
|
||||||
|
import android.database.Cursor;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
|
||||||
|
|
||||||
|
/** Tag model for viewing purposes. Contains task name */
|
||||||
|
public class TagModelForView extends AbstractTagModel {
|
||||||
|
|
||||||
|
static String[] FIELD_LIST = new String[] {
|
||||||
|
AbstractController.KEY_ROWID,
|
||||||
|
NAME,
|
||||||
|
};
|
||||||
|
|
||||||
|
// negative number, should not conflict with database row #'s
|
||||||
|
public static final TagIdentifier UNTAGGED_IDENTIFIER = new TagIdentifier(Long.MIN_VALUE);
|
||||||
|
public static final String UNTAGGED_DEFAULT_NAME = "[untagged]";
|
||||||
|
private static TagModelForView UNTAGGED_TASKS = new TagModelForView(UNTAGGED_DEFAULT_NAME);
|
||||||
|
|
||||||
|
public static final String HIDDEN_FROM_MAIN_LIST_PREFIX = "_";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a TagModelForView object to represent "Untagged" tasks,
|
||||||
|
* whose Identifier is defined by the static final UNTAGGED_IDENTIFIER.
|
||||||
|
*
|
||||||
|
* Pass in a string to show the "Untagged" name in the desired language.
|
||||||
|
* @param untaggedLabel
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static TagModelForView getUntaggedModel(String untaggedLabel) {
|
||||||
|
UNTAGGED_TASKS = new TagModelForView(untaggedLabel);
|
||||||
|
UNTAGGED_TASKS.setTagIdentifier(UNTAGGED_IDENTIFIER);
|
||||||
|
return UNTAGGED_TASKS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the default/last-used TagModelForView representing "Untagged"
|
||||||
|
* tasks. Set the localized name using getUntaggedModel(String...)
|
||||||
|
*/
|
||||||
|
public static TagModelForView getUntaggedModel() {
|
||||||
|
UNTAGGED_TASKS.setTagIdentifier(UNTAGGED_IDENTIFIER);
|
||||||
|
return UNTAGGED_TASKS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- constructors
|
||||||
|
|
||||||
|
/** Constructor for creating a new model */
|
||||||
|
TagModelForView(String name) {
|
||||||
|
super();
|
||||||
|
setName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Constructor for getting an existing model */
|
||||||
|
TagModelForView(Cursor cursor) {
|
||||||
|
super(cursor);
|
||||||
|
getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- getters and setters
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return super.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldHideFromMainList() {
|
||||||
|
return getName().startsWith(HIDDEN_FROM_MAIN_LIST_PREFIX);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggleHideFromMainList() {
|
||||||
|
if(shouldHideFromMainList())
|
||||||
|
setName(getName().substring(HIDDEN_FROM_MAIN_LIST_PREFIX.length()));
|
||||||
|
else
|
||||||
|
setName(HIDDEN_FROM_MAIN_LIST_PREFIX + getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.tag;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractModel;
|
||||||
|
import com.todoroo.astrid.legacy.data.task.TaskIdentifier;
|
||||||
|
|
||||||
|
|
||||||
|
/** A single tag on a task */
|
||||||
|
public class TagToTaskMapping extends AbstractModel {
|
||||||
|
|
||||||
|
/** Version number of this model */
|
||||||
|
static final int VERSION = 2;
|
||||||
|
|
||||||
|
// field names
|
||||||
|
|
||||||
|
static final String TASK = "task";
|
||||||
|
static final String TAG = "tag";
|
||||||
|
|
||||||
|
/** Default values container */
|
||||||
|
private static final ContentValues defaultValues = new ContentValues();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ContentValues getDefaultValues() {
|
||||||
|
return defaultValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String[] FIELD_LIST = new String[] {
|
||||||
|
AbstractController.KEY_ROWID,
|
||||||
|
TASK,
|
||||||
|
TAG,
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- database helper
|
||||||
|
|
||||||
|
/** Database Helper manages creating new tables and updating old ones */
|
||||||
|
static class TagToTaskMappingDatabaseHelper extends SQLiteOpenHelper {
|
||||||
|
String tableName;
|
||||||
|
Context context;
|
||||||
|
|
||||||
|
TagToTaskMappingDatabaseHelper(Context context, String databaseName, String tableName) {
|
||||||
|
super(context, databaseName, null, VERSION);
|
||||||
|
this.tableName = tableName;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void onCreate(SQLiteDatabase db) {
|
||||||
|
String sql = new StringBuilder().
|
||||||
|
append("CREATE TABLE IF NOT EXISTS ").append(tableName).append(" (").
|
||||||
|
append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, ").
|
||||||
|
append(TASK).append(" integer not null,").
|
||||||
|
append(TAG).append(" integer not null,").
|
||||||
|
append("unique (").append(TASK).append(",").append(TAG).append(")").
|
||||||
|
append(");").toString();
|
||||||
|
db.execSQL(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
|
Log.w(getClass().getSimpleName(), "Upgrading database from version " +
|
||||||
|
oldVersion + " to " + newVersion + ".");
|
||||||
|
|
||||||
|
switch(oldVersion) {
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Tag: Unsupported migration from " + oldVersion + " to " + newVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- constructor pass-through
|
||||||
|
|
||||||
|
TagToTaskMapping(TaskIdentifier task, TagIdentifier tag) {
|
||||||
|
super();
|
||||||
|
setTask(task);
|
||||||
|
setTag(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
TagToTaskMapping(Cursor cursor) {
|
||||||
|
super(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- getters and setters: expose them as you see fit
|
||||||
|
|
||||||
|
public boolean isNew() {
|
||||||
|
return getCursor() == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TaskIdentifier getTask() {
|
||||||
|
return new TaskIdentifier(retrieveInteger(TASK));
|
||||||
|
}
|
||||||
|
|
||||||
|
public TagIdentifier getTag() {
|
||||||
|
return new TagIdentifier(retrieveInteger(TAG));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setTask(TaskIdentifier task) {
|
||||||
|
setValues.put(TASK, task.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setTag(TagIdentifier tag) {
|
||||||
|
setValues.put(TAG, tag.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,606 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.task;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractModel;
|
||||||
|
import com.todoroo.astrid.legacy.data.enums.Importance;
|
||||||
|
import com.todoroo.astrid.legacy.data.enums.RepeatInterval;
|
||||||
|
|
||||||
|
|
||||||
|
/** Abstract model of a task. Subclasses implement the getters and setters
|
||||||
|
* they are interested in.
|
||||||
|
*
|
||||||
|
* @author timsu
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class AbstractTaskModel extends AbstractModel {
|
||||||
|
|
||||||
|
/** Version number of this model */
|
||||||
|
static final int VERSION = 8;
|
||||||
|
|
||||||
|
public static final int COMPLETE_PERCENTAGE = 100;
|
||||||
|
|
||||||
|
// field names
|
||||||
|
|
||||||
|
public static final String NAME = "name";
|
||||||
|
public static final String NOTES = "notes";
|
||||||
|
public static final String PROGRESS_PERCENTAGE = "progressPercentage";
|
||||||
|
public static final String IMPORTANCE = "importance";
|
||||||
|
public static final String ESTIMATED_SECONDS = "estimatedSeconds";
|
||||||
|
public static final String ELAPSED_SECONDS = "elapsedSeconds";
|
||||||
|
public static final String TIMER_START = "timerStart";
|
||||||
|
public static final String DEFINITE_DUE_DATE = "definiteDueDate";
|
||||||
|
public static final String PREFERRED_DUE_DATE = "preferredDueDate";
|
||||||
|
public static final String HIDDEN_UNTIL = "hiddenUntil";
|
||||||
|
public static final String POSTPONE_COUNT = "postponeCount";
|
||||||
|
public static final String NOTIFICATIONS = "notifications";
|
||||||
|
public static final String NOTIFICATION_FLAGS = "notificationFlags";
|
||||||
|
public static final String LAST_NOTIFIED = "lastNotified";
|
||||||
|
public static final String REPEAT = "repeat";
|
||||||
|
public static final String CREATION_DATE = "creationDate";
|
||||||
|
public static final String COMPLETION_DATE = "completionDate";
|
||||||
|
public static final String CALENDAR_URI = "calendarUri";
|
||||||
|
public static final String FLAGS = "flags";
|
||||||
|
|
||||||
|
// reserved fields ---
|
||||||
|
public static final String BLOCKING_ON = "blockingOn";
|
||||||
|
|
||||||
|
// notification flags
|
||||||
|
public static final int NOTIFY_BEFORE_DEADLINE = 1 << 0;
|
||||||
|
public static final int NOTIFY_AT_DEADLINE = 1 << 1;
|
||||||
|
public static final int NOTIFY_AFTER_DEADLINE = 1 << 2;
|
||||||
|
public static final int NOTIFY_NONSTOP = 1 << 3;
|
||||||
|
|
||||||
|
// other flags
|
||||||
|
public static final int FLAG_SYNC_ON_COMPLETE = 1 << 0;
|
||||||
|
|
||||||
|
/** Number of bits to shift repeat value by */
|
||||||
|
public static final int REPEAT_VALUE_OFFSET = 3;
|
||||||
|
|
||||||
|
/** Default values container */
|
||||||
|
private static final ContentValues defaultValues = new ContentValues();
|
||||||
|
|
||||||
|
static {
|
||||||
|
defaultValues.put(NAME, "");
|
||||||
|
defaultValues.put(NOTES, "");
|
||||||
|
defaultValues.put(PROGRESS_PERCENTAGE, 0);
|
||||||
|
defaultValues.put(IMPORTANCE, Importance.DEFAULT.ordinal());
|
||||||
|
defaultValues.put(ESTIMATED_SECONDS, 0);
|
||||||
|
defaultValues.put(ELAPSED_SECONDS, 0);
|
||||||
|
defaultValues.put(TIMER_START, 0);
|
||||||
|
defaultValues.put(DEFINITE_DUE_DATE, 0);
|
||||||
|
defaultValues.put(PREFERRED_DUE_DATE, 0);
|
||||||
|
defaultValues.put(HIDDEN_UNTIL, 0);
|
||||||
|
defaultValues.put(BLOCKING_ON, 0);
|
||||||
|
defaultValues.put(POSTPONE_COUNT, 0);
|
||||||
|
defaultValues.put(NOTIFICATIONS, 0);
|
||||||
|
defaultValues.put(NOTIFICATION_FLAGS, NOTIFY_AT_DEADLINE);
|
||||||
|
defaultValues.put(LAST_NOTIFIED, 0);
|
||||||
|
defaultValues.put(REPEAT, 0);
|
||||||
|
defaultValues.put(COMPLETION_DATE, 0);
|
||||||
|
defaultValues.put(CALENDAR_URI, (String)null);
|
||||||
|
defaultValues.put(FLAGS, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- database helper
|
||||||
|
|
||||||
|
/** Database Helper manages creating new tables and updating old ones */
|
||||||
|
public static class TaskModelDatabaseHelper extends SQLiteOpenHelper {
|
||||||
|
String tableName;
|
||||||
|
Context context;
|
||||||
|
|
||||||
|
public TaskModelDatabaseHelper(Context context, String databaseName, String tableName) {
|
||||||
|
super(context, databaseName, null, VERSION);
|
||||||
|
this.tableName = tableName;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void onCreate(SQLiteDatabase db) {
|
||||||
|
String sql = new StringBuilder().
|
||||||
|
append("CREATE TABLE IF NOT EXISTS ").append(tableName).append(" (").
|
||||||
|
append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, ").
|
||||||
|
append(NAME).append(" text not null,").
|
||||||
|
append(NOTES).append(" text not null,").
|
||||||
|
append(PROGRESS_PERCENTAGE).append(" integer not null,").
|
||||||
|
append(IMPORTANCE).append(" integer not null,").
|
||||||
|
append(ESTIMATED_SECONDS).append(" integer,").
|
||||||
|
append(ELAPSED_SECONDS).append(" integer,").
|
||||||
|
append(TIMER_START).append(" integer,").
|
||||||
|
append(DEFINITE_DUE_DATE).append(" integer,").
|
||||||
|
append(PREFERRED_DUE_DATE).append(" integer,").
|
||||||
|
append(HIDDEN_UNTIL).append(" integer,").
|
||||||
|
append(BLOCKING_ON).append(" integer,").
|
||||||
|
append(POSTPONE_COUNT).append(" integer,").
|
||||||
|
append(NOTIFICATIONS).append(" integer,").
|
||||||
|
append(NOTIFICATION_FLAGS).append(" integer,").
|
||||||
|
append(LAST_NOTIFIED).append(" integer,").
|
||||||
|
append(REPEAT).append(" integer,").
|
||||||
|
append(FLAGS).append(" integer,").
|
||||||
|
append(CREATION_DATE).append(" integer,").
|
||||||
|
append(COMPLETION_DATE).append(" integer,").
|
||||||
|
append(CALENDAR_URI).append(" text").
|
||||||
|
append(");").toString();
|
||||||
|
db.execSQL(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("fallthrough")
|
||||||
|
public synchronized void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
|
Log.w(getClass().getSimpleName(), "Upgrading database from version " +
|
||||||
|
oldVersion + " to " + newVersion + ".");
|
||||||
|
String sql;
|
||||||
|
|
||||||
|
// note: we execute sql statements in their own try block to be more
|
||||||
|
// graceful if an upgrade dies halfway or something
|
||||||
|
switch(oldVersion) {
|
||||||
|
case 1:
|
||||||
|
sql = new StringBuilder().append("ALTER TABLE ").
|
||||||
|
append(tableName).append(" ADD COLUMN ").
|
||||||
|
append(LAST_NOTIFIED).append(" integer").toString();
|
||||||
|
try {
|
||||||
|
db.execSQL(sql);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("astrid", "Error updating table!", e);
|
||||||
|
}
|
||||||
|
sql = new StringBuilder().append("ALTER TABLE ").
|
||||||
|
append(tableName).append(" ADD COLUMN ").
|
||||||
|
append(NOTIFICATION_FLAGS).append(" integer").toString();
|
||||||
|
try {
|
||||||
|
db.execSQL(sql);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("astrid", "Error updating table!", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
sql = new StringBuilder().append("ALTER TABLE ").
|
||||||
|
append(tableName).append(" ADD COLUMN ").
|
||||||
|
append(REPEAT).append(" integer").toString();
|
||||||
|
try {
|
||||||
|
db.execSQL(sql);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("astrid", "Error updating table!", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
sql = new StringBuilder().append("ALTER TABLE ").
|
||||||
|
append(tableName).append(" ADD COLUMN ").
|
||||||
|
append(CALENDAR_URI).append(" text").toString();
|
||||||
|
try {
|
||||||
|
db.execSQL(sql);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("astrid", "Error updating table!", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
sql = new StringBuilder().append("ALTER TABLE ").
|
||||||
|
append(tableName).append(" ADD COLUMN ").
|
||||||
|
append(POSTPONE_COUNT).append(" integer").toString();
|
||||||
|
try {
|
||||||
|
db.execSQL(sql);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("astrid", "Error updating table!", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
// apparently some people didn't get the flags column
|
||||||
|
// from version 5 to version 6, so we try again
|
||||||
|
|
||||||
|
sql = new StringBuilder().append("ALTER TABLE ").
|
||||||
|
append(tableName).append(" ADD COLUMN ").
|
||||||
|
append(FLAGS).append(" integer").toString();
|
||||||
|
try {
|
||||||
|
db.execSQL(sql);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("astrid", "Error updating table!", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
// not a real change, but make sure that columns that are null
|
||||||
|
// are converted into zeros, which was my previous assumption
|
||||||
|
|
||||||
|
for(String column : new String[] {
|
||||||
|
ESTIMATED_SECONDS,
|
||||||
|
ELAPSED_SECONDS,
|
||||||
|
TIMER_START,
|
||||||
|
DEFINITE_DUE_DATE,
|
||||||
|
PREFERRED_DUE_DATE,
|
||||||
|
HIDDEN_UNTIL,
|
||||||
|
POSTPONE_COUNT,
|
||||||
|
LAST_NOTIFIED,
|
||||||
|
REPEAT,
|
||||||
|
CREATION_DATE,
|
||||||
|
COMPLETION_DATE }) {
|
||||||
|
sql = String.format("UPDATE %s SET %s = 0 WHERE %s ISNULL",
|
||||||
|
tableName, column, column);
|
||||||
|
try {
|
||||||
|
db.execSQL(sql);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("astrid", "Error updating table!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- break point
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// we don't know how to handle it... show an error
|
||||||
|
throw new RuntimeException("Tasks: Unsupported migration from " + oldVersion + " to " + newVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- utility methods
|
||||||
|
|
||||||
|
/** Gets task color. Requires definiteDueDate and importance */
|
||||||
|
protected int getTaskColorResource(Context context) {
|
||||||
|
if(getDefiniteDueDate() != null && getDefiniteDueDate().getTime() <
|
||||||
|
System.currentTimeMillis()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks whether task is done. Requires progressPercentage */
|
||||||
|
protected boolean isTaskCompleted() {
|
||||||
|
return getProgressPercentage() >= COMPLETE_PERCENTAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Stops the timer & increments elapsed time. Requires timerStart and
|
||||||
|
* elapsedSeconds */
|
||||||
|
protected void stopTimerAndUpdateElapsedTime() {
|
||||||
|
if(getTimerStart() == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
long start = getTimerStart().getTime();
|
||||||
|
setTimerStart(null);
|
||||||
|
long secondsElapsed = (System.currentTimeMillis() - start)/1000;
|
||||||
|
setElapsedSeconds((int) (getElapsedSeconds() + secondsElapsed));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void prefetchData(String[] fields) {
|
||||||
|
for(String field : fields) {
|
||||||
|
if(field.equals(NAME))
|
||||||
|
getName();
|
||||||
|
else if(field.equals(NOTES))
|
||||||
|
getNotes();
|
||||||
|
else if(field.equals(PROGRESS_PERCENTAGE))
|
||||||
|
getProgressPercentage();
|
||||||
|
else if(field.equals(IMPORTANCE))
|
||||||
|
getImportance();
|
||||||
|
else if(field.equals(ESTIMATED_SECONDS))
|
||||||
|
getEstimatedSeconds();
|
||||||
|
else if(field.equals(ELAPSED_SECONDS))
|
||||||
|
getElapsedSeconds();
|
||||||
|
else if(field.equals(TIMER_START))
|
||||||
|
getTimerStart();
|
||||||
|
else if(field.equals(DEFINITE_DUE_DATE))
|
||||||
|
getDefiniteDueDate();
|
||||||
|
else if(field.equals(PREFERRED_DUE_DATE))
|
||||||
|
getPreferredDueDate();
|
||||||
|
else if(field.equals(HIDDEN_UNTIL))
|
||||||
|
getHiddenUntil();
|
||||||
|
else if(field.equals(BLOCKING_ON))
|
||||||
|
getBlockingOn();
|
||||||
|
else if(field.equals(POSTPONE_COUNT))
|
||||||
|
getPostponeCount();
|
||||||
|
else if(field.equals(NOTIFICATIONS))
|
||||||
|
getNotificationIntervalSeconds();
|
||||||
|
else if(field.equals(CREATION_DATE))
|
||||||
|
getCreationDate();
|
||||||
|
else if(field.equals(COMPLETION_DATE))
|
||||||
|
getCompletionDate();
|
||||||
|
else if(field.equals(NOTIFICATION_FLAGS))
|
||||||
|
getNotificationFlags();
|
||||||
|
else if(field.equals(LAST_NOTIFIED))
|
||||||
|
getLastNotificationDate();
|
||||||
|
else if(field.equals(REPEAT))
|
||||||
|
getRepeat();
|
||||||
|
else if(field.equals(FLAGS))
|
||||||
|
getFlags();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- helper classes
|
||||||
|
|
||||||
|
public static class RepeatInfo {
|
||||||
|
private RepeatInterval interval;
|
||||||
|
private int value;
|
||||||
|
|
||||||
|
public RepeatInfo(RepeatInterval repeatInterval, int value) {
|
||||||
|
this.interval = repeatInterval;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date shiftDate(Date input) {
|
||||||
|
Date newDate = (Date)input.clone();
|
||||||
|
interval.offsetDateBy(newDate, value);
|
||||||
|
return newDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RepeatInterval getInterval() {
|
||||||
|
return interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- task identifier
|
||||||
|
|
||||||
|
private TaskIdentifier identifier = null;
|
||||||
|
|
||||||
|
public TaskIdentifier getTaskIdentifier() {
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTaskIdentifier(TaskIdentifier identifier) {
|
||||||
|
this.identifier = identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- constructors and abstract methods
|
||||||
|
|
||||||
|
AbstractTaskModel() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read identifier from database */
|
||||||
|
AbstractTaskModel(Cursor cursor) {
|
||||||
|
super(cursor);
|
||||||
|
|
||||||
|
Integer id = retrieveInteger(AbstractController.KEY_ROWID);
|
||||||
|
setTaskIdentifier(new TaskIdentifier(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get identifier from argument */
|
||||||
|
AbstractTaskModel(TaskIdentifier identifier, Cursor cursor) {
|
||||||
|
super(cursor);
|
||||||
|
|
||||||
|
setTaskIdentifier(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ContentValues getDefaultValues() {
|
||||||
|
return defaultValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- getters and setters: expose them as you see fit
|
||||||
|
|
||||||
|
protected String getName() {
|
||||||
|
return retrieveString(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getNotes() {
|
||||||
|
return retrieveString(NOTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getProgressPercentage() {
|
||||||
|
return retrieveInteger(PROGRESS_PERCENTAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Importance getImportance() {
|
||||||
|
Integer value = retrieveInteger(IMPORTANCE);
|
||||||
|
if(value == null)
|
||||||
|
return null;
|
||||||
|
return Importance.values()[value];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Integer getEstimatedSeconds() {
|
||||||
|
return retrieveInteger(ESTIMATED_SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Integer getElapsedSeconds() {
|
||||||
|
return retrieveInteger(ELAPSED_SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Date getTimerStart() {
|
||||||
|
return retrieveDate(TIMER_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Date getDefiniteDueDate() {
|
||||||
|
return retrieveDate(DEFINITE_DUE_DATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Date getPreferredDueDate() {
|
||||||
|
return retrieveDate(PREFERRED_DUE_DATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Date getHiddenUntil() {
|
||||||
|
return retrieveDate(HIDDEN_UNTIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isHidden() {
|
||||||
|
if(getHiddenUntil() == null)
|
||||||
|
return false;
|
||||||
|
return getHiddenUntil().getTime() > System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Date getCreationDate() {
|
||||||
|
return retrieveDate(CREATION_DATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Date getCompletionDate() {
|
||||||
|
return retrieveDate(COMPLETION_DATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TaskIdentifier getBlockingOn() {
|
||||||
|
Long value = retrieveLong(BLOCKING_ON);
|
||||||
|
if(value == null)
|
||||||
|
return null;
|
||||||
|
return new TaskIdentifier(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Integer getPostponeCount() {
|
||||||
|
return retrieveInteger(POSTPONE_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Integer getNotificationIntervalSeconds() {
|
||||||
|
return retrieveInteger(NOTIFICATIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getNotificationFlags() {
|
||||||
|
return retrieveInteger(NOTIFICATION_FLAGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Date getLastNotificationDate() {
|
||||||
|
return retrieveDate(LAST_NOTIFIED);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected RepeatInfo getRepeat() {
|
||||||
|
int repeat = retrieveInteger(REPEAT);
|
||||||
|
if(repeat == 0)
|
||||||
|
return null;
|
||||||
|
int value = repeat >> REPEAT_VALUE_OFFSET;
|
||||||
|
RepeatInterval interval = RepeatInterval.values()
|
||||||
|
[repeat - (value << REPEAT_VALUE_OFFSET)];
|
||||||
|
|
||||||
|
return new RepeatInfo(interval, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getCalendarUri() {
|
||||||
|
String uri = retrieveString(CALENDAR_URI);
|
||||||
|
if(uri != null && uri.length() == 0)
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getFlags() {
|
||||||
|
return retrieveInteger(FLAGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- setters
|
||||||
|
|
||||||
|
protected void setName(String name) {
|
||||||
|
putIfChangedFromDatabase(NAME, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setNotes(String notes) {
|
||||||
|
putIfChangedFromDatabase(NOTES, notes);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setProgressPercentage(int progressPercentage) {
|
||||||
|
putIfChangedFromDatabase(PROGRESS_PERCENTAGE, progressPercentage);
|
||||||
|
|
||||||
|
if(getProgressPercentage() != progressPercentage &&
|
||||||
|
progressPercentage == COMPLETE_PERCENTAGE)
|
||||||
|
setCompletionDate(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setImportance(Importance importance) {
|
||||||
|
putIfChangedFromDatabase(IMPORTANCE, importance.ordinal());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setEstimatedSeconds(Integer estimatedSeconds) {
|
||||||
|
putIfChangedFromDatabase(ESTIMATED_SECONDS, estimatedSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setElapsedSeconds(int elapsedSeconds) {
|
||||||
|
putIfChangedFromDatabase(ELAPSED_SECONDS, elapsedSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setTimerStart(Date timerStart) {
|
||||||
|
putDate(TIMER_START, timerStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setDefiniteDueDate(Date definiteDueDate) {
|
||||||
|
putDate(DEFINITE_DUE_DATE, definiteDueDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setPreferredDueDate(Date preferredDueDate) {
|
||||||
|
putDate(PREFERRED_DUE_DATE, preferredDueDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setHiddenUntil(Date hiddenUntil) {
|
||||||
|
putDate(HIDDEN_UNTIL, hiddenUntil);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setBlockingOn(TaskIdentifier blockingOn) {
|
||||||
|
if(blockingOn == null || blockingOn.equals(getTaskIdentifier()))
|
||||||
|
putIfChangedFromDatabase(BLOCKING_ON, (Integer)null);
|
||||||
|
else
|
||||||
|
putIfChangedFromDatabase(BLOCKING_ON, blockingOn.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setPostponeCount(int postponeCount) {
|
||||||
|
putIfChangedFromDatabase(POSTPONE_COUNT, postponeCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setCreationDate(Date creationDate) {
|
||||||
|
putDate(CREATION_DATE, creationDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setCompletionDate(Date completionDate) {
|
||||||
|
putDate(COMPLETION_DATE, completionDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setNotificationIntervalSeconds(Integer intervalInSeconds) {
|
||||||
|
putIfChangedFromDatabase(NOTIFICATIONS, intervalInSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setNotificationFlags(int flags) {
|
||||||
|
putIfChangedFromDatabase(NOTIFICATION_FLAGS, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setLastNotificationTime(Date date) {
|
||||||
|
putDate(LAST_NOTIFIED, date);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setRepeat(RepeatInfo repeatInfo) {
|
||||||
|
int repeat;
|
||||||
|
if(repeatInfo == null)
|
||||||
|
repeat = 0;
|
||||||
|
else
|
||||||
|
repeat = (repeatInfo.value << REPEAT_VALUE_OFFSET) +
|
||||||
|
repeatInfo.interval.ordinal();
|
||||||
|
putIfChangedFromDatabase(REPEAT, repeat);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setCalendarUri(String uri) {
|
||||||
|
putIfChangedFromDatabase(CALENDAR_URI, uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setFlags(int flags) {
|
||||||
|
putIfChangedFromDatabase(FLAGS, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- utility methods
|
||||||
|
|
||||||
|
protected void putDate(String fieldName, Date date) {
|
||||||
|
if(date == null)
|
||||||
|
putIfChangedFromDatabase(fieldName, 0);
|
||||||
|
else
|
||||||
|
putIfChangedFromDatabase(fieldName, date.getTime());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,556 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.task;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.SQLException;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
import com.todoroo.astrid.legacy.data.sync.SyncDataController;
|
||||||
|
import com.todoroo.astrid.legacy.data.task.AbstractTaskModel.RepeatInfo;
|
||||||
|
import com.todoroo.astrid.legacy.data.task.AbstractTaskModel.TaskModelDatabaseHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for task-related operations
|
||||||
|
*
|
||||||
|
* @author timsu
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TaskController extends AbstractController {
|
||||||
|
|
||||||
|
private SQLiteDatabase database;
|
||||||
|
|
||||||
|
// --- task list operations
|
||||||
|
|
||||||
|
/** Return a list of all active tasks with notifications */
|
||||||
|
public HashSet<TaskModelForNotify> getTasksWithNotifications() {
|
||||||
|
HashSet<TaskModelForNotify> list = new HashSet<TaskModelForNotify>();
|
||||||
|
Cursor cursor = database.query(TASK_TABLE_NAME, TaskModelForNotify.FIELD_LIST,
|
||||||
|
String.format("%s < %d AND (%s != 0 OR %s != 0)",
|
||||||
|
AbstractTaskModel.PROGRESS_PERCENTAGE,
|
||||||
|
AbstractTaskModel.COMPLETE_PERCENTAGE,
|
||||||
|
AbstractTaskModel.NOTIFICATIONS,
|
||||||
|
AbstractTaskModel.NOTIFICATION_FLAGS), null, null, null, null, null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(cursor.getCount() == 0)
|
||||||
|
return list;
|
||||||
|
do {
|
||||||
|
cursor.moveToNext();
|
||||||
|
list.add(new TaskModelForNotify(cursor));
|
||||||
|
} while(!cursor.isLast());
|
||||||
|
|
||||||
|
return list;
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return a list of all active tasks with deadlines */
|
||||||
|
public ArrayList<TaskModelForNotify> getTasksWithDeadlines() {
|
||||||
|
ArrayList<TaskModelForNotify> list = new ArrayList<TaskModelForNotify>();
|
||||||
|
Cursor cursor = database.query(TASK_TABLE_NAME, TaskModelForNotify.FIELD_LIST,
|
||||||
|
String.format("%s < %d AND (%s != 0 OR %s != 0)",
|
||||||
|
AbstractTaskModel.PROGRESS_PERCENTAGE,
|
||||||
|
AbstractTaskModel.COMPLETE_PERCENTAGE,
|
||||||
|
AbstractTaskModel.DEFINITE_DUE_DATE,
|
||||||
|
AbstractTaskModel.PREFERRED_DUE_DATE), null, null, null, null, null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(cursor.getCount() == 0)
|
||||||
|
return list;
|
||||||
|
|
||||||
|
do {
|
||||||
|
cursor.moveToNext();
|
||||||
|
list.add(new TaskModelForNotify(cursor));
|
||||||
|
} while(!cursor.isLast());
|
||||||
|
|
||||||
|
return list;
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return a list of all of the tasks with progress < COMPLETE_PERCENTAGE */
|
||||||
|
public Cursor getActiveTaskListCursor() {
|
||||||
|
return database.query(TASK_TABLE_NAME, TaskModelForList.FIELD_LIST,
|
||||||
|
AbstractTaskModel.PROGRESS_PERCENTAGE + " < " +
|
||||||
|
AbstractTaskModel.COMPLETE_PERCENTAGE, null, null, null,
|
||||||
|
null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return a list of all tasks */
|
||||||
|
public Cursor getAllTaskListCursor() {
|
||||||
|
return database.query(TASK_TABLE_NAME, TaskModelForList.FIELD_LIST,
|
||||||
|
null, null, null, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return a list of all tasks */
|
||||||
|
public Cursor getBackupTaskListCursor() {
|
||||||
|
return database.query(TASK_TABLE_NAME, TaskModelForXml.FIELD_LIST,
|
||||||
|
AbstractTaskModel.PROGRESS_PERCENTAGE + " < " +
|
||||||
|
AbstractTaskModel.COMPLETE_PERCENTAGE, null, null, null,
|
||||||
|
null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Delete all completed tasks with date < older than date */
|
||||||
|
public int deleteCompletedTasksOlderThan(Date olderThanDate) {
|
||||||
|
return database.delete(TASK_TABLE_NAME, String.format("`%s` >= '%d' AND `%s` <= '%d'",
|
||||||
|
AbstractTaskModel.PROGRESS_PERCENTAGE, AbstractTaskModel.COMPLETE_PERCENTAGE,
|
||||||
|
AbstractTaskModel.COMPLETION_DATE, olderThanDate.getTime()), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create a list of tasks from the db cursor given */
|
||||||
|
public ArrayList<TaskModelForList> createTaskListFromCursor(Cursor cursor) {
|
||||||
|
ArrayList<TaskModelForList> list = new ArrayList<TaskModelForList>();
|
||||||
|
|
||||||
|
if(cursor.getCount() == 0)
|
||||||
|
return list;
|
||||||
|
|
||||||
|
do {
|
||||||
|
cursor.moveToNext();
|
||||||
|
list.add(new TaskModelForList(cursor));
|
||||||
|
} while(!cursor.isLast());
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Helper method to take a cursor pointing to a list of id's and generate
|
||||||
|
* a hashset */
|
||||||
|
private HashSet<TaskIdentifier> createTaskIdentifierSet(Cursor cursor) {
|
||||||
|
HashSet<TaskIdentifier> list = new HashSet<TaskIdentifier>();
|
||||||
|
try {
|
||||||
|
if(cursor.getCount() == 0)
|
||||||
|
return list;
|
||||||
|
|
||||||
|
do {
|
||||||
|
cursor.moveToNext();
|
||||||
|
list.add(new TaskIdentifier(cursor.getInt(
|
||||||
|
cursor.getColumnIndexOrThrow(KEY_ROWID))));
|
||||||
|
} while(!cursor.isLast());
|
||||||
|
|
||||||
|
return list;
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get identifiers for all tasks */
|
||||||
|
public HashSet<TaskIdentifier> getAllTaskIdentifiers() {
|
||||||
|
Cursor cursor = database.query(TASK_TABLE_NAME, new String[] { KEY_ROWID },
|
||||||
|
null, null, null, null, null, null);
|
||||||
|
return createTaskIdentifierSet(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get identifiers for all non-completed tasks */
|
||||||
|
public HashSet<TaskIdentifier> getActiveTaskIdentifiers() {
|
||||||
|
Cursor cursor = database.query(TASK_TABLE_NAME, new String[] { KEY_ROWID },
|
||||||
|
AbstractTaskModel.PROGRESS_PERCENTAGE + " < " +
|
||||||
|
AbstractTaskModel.COMPLETE_PERCENTAGE, null, null, null, null, null);
|
||||||
|
return createTaskIdentifierSet(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get identifiers for all non-completed, non-hidden tasks */
|
||||||
|
public HashSet<TaskIdentifier> getActiveVisibleTaskIdentifiers() {
|
||||||
|
Cursor cursor = database.query(TASK_TABLE_NAME, new String[] { KEY_ROWID },
|
||||||
|
AbstractTaskModel.PROGRESS_PERCENTAGE + " < " +
|
||||||
|
AbstractTaskModel.COMPLETE_PERCENTAGE + " AND (" +
|
||||||
|
AbstractTaskModel.HIDDEN_UNTIL + " ISNULL OR " + AbstractTaskModel.HIDDEN_UNTIL + " < " +
|
||||||
|
System.currentTimeMillis() + ")", null, null, null, null, null);
|
||||||
|
return createTaskIdentifierSet(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Create a weighted list of tasks from the db cursor given */
|
||||||
|
public Cursor getTaskListCursorById(List<TaskIdentifier> idList) {
|
||||||
|
|
||||||
|
StringBuilder where = new StringBuilder();
|
||||||
|
for(int i = 0; i < idList.size(); i++) {
|
||||||
|
where.append(KEY_ROWID);
|
||||||
|
where.append("=");
|
||||||
|
where.append(idList.get(i).idAsString());
|
||||||
|
if(i < idList.size()-1)
|
||||||
|
where.append(" OR ");
|
||||||
|
}
|
||||||
|
|
||||||
|
// hack for empty arrays
|
||||||
|
if(idList.size() == 0)
|
||||||
|
where.append("0");
|
||||||
|
|
||||||
|
return database.query(true, TASK_TABLE_NAME,
|
||||||
|
TaskModelForList.FIELD_LIST, where.toString(), null, null,
|
||||||
|
null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- single task operations
|
||||||
|
|
||||||
|
/** Delete the given task */
|
||||||
|
public boolean deleteTask(TaskIdentifier taskId) {
|
||||||
|
if(taskId == null)
|
||||||
|
throw new UnsupportedOperationException("Cannot delete uncreated task!");
|
||||||
|
long id = taskId.getId();
|
||||||
|
cleanupTask(taskId, false);
|
||||||
|
|
||||||
|
return database.delete(TASK_TABLE_NAME, KEY_ROWID + "=" + id, null) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Saves the given task to the database. Returns true on success.
|
||||||
|
*
|
||||||
|
* @param duringSync set to true when save is part of a synchronize
|
||||||
|
*/
|
||||||
|
public boolean saveTask(AbstractTaskModel task, boolean duringSync) {
|
||||||
|
boolean saveSucessful;
|
||||||
|
|
||||||
|
if(task.getTaskIdentifier() == null) {
|
||||||
|
long newRow = database.insert(TASK_TABLE_NAME, AbstractTaskModel.NAME,
|
||||||
|
task.getMergedValues());
|
||||||
|
task.setTaskIdentifier(new TaskIdentifier(newRow));
|
||||||
|
|
||||||
|
saveSucessful = newRow >= 0;
|
||||||
|
} else {
|
||||||
|
long id = task.getTaskIdentifier().getId();
|
||||||
|
ContentValues values = task.getSetValues();
|
||||||
|
|
||||||
|
if(values.size() == 0) // nothing changed
|
||||||
|
return true;
|
||||||
|
|
||||||
|
onTaskSave(task, values, duringSync);
|
||||||
|
|
||||||
|
saveSucessful = database.update(TASK_TABLE_NAME, values,
|
||||||
|
KEY_ROWID + "=" + id, null) > 0;
|
||||||
|
|
||||||
|
// task was completed
|
||||||
|
if(values.containsKey(AbstractTaskModel.PROGRESS_PERCENTAGE) &&
|
||||||
|
values.getAsInteger(AbstractTaskModel.PROGRESS_PERCENTAGE)
|
||||||
|
== AbstractTaskModel.COMPLETE_PERCENTAGE) {
|
||||||
|
onTaskCompleted(task, values, duringSync);
|
||||||
|
}
|
||||||
|
|
||||||
|
SyncDataController.taskUpdated(context, task);
|
||||||
|
}
|
||||||
|
|
||||||
|
return saveSucessful;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the task is saved. Perform some processing on the task.
|
||||||
|
*
|
||||||
|
* @param task
|
||||||
|
* @param values
|
||||||
|
*/
|
||||||
|
private void onTaskSave(AbstractTaskModel task, ContentValues values, boolean duringSync) {
|
||||||
|
// save task completed date
|
||||||
|
if(values.containsKey(AbstractTaskModel.PROGRESS_PERCENTAGE) &&
|
||||||
|
values.getAsInteger(AbstractTaskModel.PROGRESS_PERCENTAGE)
|
||||||
|
== AbstractTaskModel.COMPLETE_PERCENTAGE) {
|
||||||
|
values.put(AbstractTaskModel.COMPLETION_DATE, System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when this task is set to completed.
|
||||||
|
*
|
||||||
|
* @param task task to process
|
||||||
|
* @param values mutable map of values to save
|
||||||
|
*/
|
||||||
|
private void onTaskCompleted(AbstractTaskModel task, ContentValues values, boolean duringSync) {
|
||||||
|
Cursor cursor = fetchTaskCursor(task.getTaskIdentifier(),
|
||||||
|
TaskModelForHandlers.FIELD_LIST);
|
||||||
|
TaskModelForHandlers model = new TaskModelForHandlers(cursor, values);
|
||||||
|
|
||||||
|
// handle repeat
|
||||||
|
RepeatInfo repeatInfo = model.getRepeat();
|
||||||
|
if(repeatInfo != null) {
|
||||||
|
model.repeatTaskBy(context, this, repeatInfo);
|
||||||
|
database.update(TASK_TABLE_NAME, values, KEY_ROWID + "=" +
|
||||||
|
task.getTaskIdentifier().getId(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor.close();
|
||||||
|
cleanupTask(task.getTaskIdentifier(), repeatInfo != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Clean up state from a task. Called when deleting or completing it */
|
||||||
|
private void cleanupTask(TaskIdentifier taskId, boolean isRepeating) {
|
||||||
|
// delete calendar event if not repeating
|
||||||
|
if(!isRepeating) {
|
||||||
|
try {
|
||||||
|
Cursor cursor = fetchTaskCursor(taskId, new String[] {
|
||||||
|
AbstractTaskModel.CALENDAR_URI });
|
||||||
|
cursor.moveToFirst();
|
||||||
|
String uri = cursor.getString(0);
|
||||||
|
cursor.close();
|
||||||
|
if(uri != null && uri.length() > 0) {
|
||||||
|
ContentResolver cr = context.getContentResolver();
|
||||||
|
cr.delete(Uri.parse(uri), null, null);
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(AbstractTaskModel.CALENDAR_URI, (String)null);
|
||||||
|
database.update(TASK_TABLE_NAME, values, KEY_ROWID + "=" +
|
||||||
|
taskId.getId(), null);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("astrid", "Error deleting calendar event", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set last notification date */
|
||||||
|
public boolean setLastNotificationTime(TaskIdentifier taskId, Date date) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(AbstractTaskModel.LAST_NOTIFIED, date.getTime());
|
||||||
|
return database.update(TASK_TABLE_NAME, values,
|
||||||
|
KEY_ROWID + "=" + taskId.getId(), null) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- fetching different models
|
||||||
|
|
||||||
|
/** Creates a new task and returns the task identifier */
|
||||||
|
public TaskModelForEdit createNewTaskForEdit() {
|
||||||
|
TaskModelForEdit task = new TaskModelForEdit();
|
||||||
|
task.setTaskIdentifier(null);
|
||||||
|
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a TaskModelForEdit corresponding to the given TaskIdentifier */
|
||||||
|
public TaskModelForEdit fetchTaskForEdit(Activity activity, TaskIdentifier
|
||||||
|
taskId) throws SQLException {
|
||||||
|
Cursor cursor = fetchTaskCursor(taskId, TaskModelForEdit.FIELD_LIST);
|
||||||
|
activity.startManagingCursor(cursor);
|
||||||
|
TaskModelForEdit model = new TaskModelForEdit(taskId, cursor);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a TaskModelForList corresponding to the given TaskIdentifier */
|
||||||
|
public TaskModelForList fetchTaskForList(TaskIdentifier taskId) throws SQLException {
|
||||||
|
Cursor cursor = fetchTaskCursor(taskId, TaskModelForList.FIELD_LIST);
|
||||||
|
TaskModelForList model = new TaskModelForList(cursor);
|
||||||
|
cursor.close();
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a TaskModelForXml corresponding to the given TaskIdentifier */
|
||||||
|
public TaskModelForXml fetchTaskForXml(TaskIdentifier taskId) throws SQLException {
|
||||||
|
Cursor cursor = fetchTaskCursor(taskId, TaskModelForXml.FIELD_LIST);
|
||||||
|
TaskModelForXml model = new TaskModelForXml(cursor);
|
||||||
|
cursor.close();
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attempts to return a TaskModelForXml for the given name and creation date */
|
||||||
|
public TaskModelForXml fetchTaskForXml(String name, Date creationDate) {
|
||||||
|
Cursor cursor;
|
||||||
|
try {
|
||||||
|
cursor = fetchTaskCursor(name, creationDate.getTime(),
|
||||||
|
TaskModelForXml.FIELD_LIST);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (cursor == null || cursor.getCount() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TaskModelForXml model = new TaskModelForXml(cursor);
|
||||||
|
cursor.close();
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a TaskModelForReminder corresponding to the given TaskIdentifier */
|
||||||
|
public TaskModelForReminder fetchTaskForReminder(TaskIdentifier taskId) throws SQLException {
|
||||||
|
Cursor cursor = fetchTaskCursor(taskId, TaskModelForReminder.FIELD_LIST);
|
||||||
|
TaskModelForReminder model = new TaskModelForReminder(cursor);
|
||||||
|
cursor.close();
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a TaskModelForSync corresponding to the given TaskIdentifier */
|
||||||
|
public TaskModelForSync fetchTaskForSync(TaskIdentifier taskId) throws SQLException {
|
||||||
|
Cursor cursor = fetchTaskCursor(taskId, TaskModelForSync.FIELD_LIST);
|
||||||
|
TaskModelForSync model = new TaskModelForSync(cursor);
|
||||||
|
cursor.close();
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a TaskModelForView by name */
|
||||||
|
public TaskModelForSync searchForTaskForSync(String name) throws SQLException {
|
||||||
|
Cursor cursor = database.query(true, TASK_TABLE_NAME, TaskModelForSync.FIELD_LIST,
|
||||||
|
AbstractTaskModel.NAME + " = ? AND " +
|
||||||
|
AbstractTaskModel.PROGRESS_PERCENTAGE + " < "+
|
||||||
|
AbstractTaskModel.COMPLETE_PERCENTAGE,
|
||||||
|
new String[] { name }, null, null, null, null);
|
||||||
|
try {
|
||||||
|
if (cursor == null || cursor.getCount() == 0)
|
||||||
|
return null;
|
||||||
|
cursor.moveToFirst();
|
||||||
|
TaskModelForSync model = new TaskModelForSync(cursor);
|
||||||
|
return model;
|
||||||
|
} finally {
|
||||||
|
if(cursor != null)
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a TaskModelForView corresponding to the given TaskIdentifier */
|
||||||
|
public TaskModelForNotify fetchTaskForNotify(TaskIdentifier taskId) throws SQLException {
|
||||||
|
Cursor cursor = fetchTaskCursor(taskId, TaskModelForNotify.FIELD_LIST);
|
||||||
|
TaskModelForNotify model = new TaskModelForNotify(cursor);
|
||||||
|
cursor.close();
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Moves cursor to the task.
|
||||||
|
* Don't forget to close the cursor when you're done. */
|
||||||
|
private Cursor fetchTaskCursor(TaskIdentifier taskId, String[] fieldList) {
|
||||||
|
long id = taskId.getId();
|
||||||
|
Cursor cursor = database.query(true, TASK_TABLE_NAME, fieldList,
|
||||||
|
KEY_ROWID + "=" + id, null, null, null, null, null);
|
||||||
|
if (cursor == null)
|
||||||
|
throw new SQLException("Returned empty set!");
|
||||||
|
|
||||||
|
cursor.moveToFirst();
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns null if unsuccessful, otherwise moves cursor to the task.
|
||||||
|
* Don't forget to close the cursor when you're done. */
|
||||||
|
private Cursor fetchTaskCursor(String name, long creationDate, String[] fieldList) {
|
||||||
|
// truncate millis
|
||||||
|
final String where = AbstractTaskModel.NAME + " = ? AND "
|
||||||
|
+ AbstractTaskModel.CREATION_DATE + " LIKE ?";
|
||||||
|
|
||||||
|
String approximateCreationDate = (creationDate / 1000) + "%";
|
||||||
|
Cursor cursor = database.query(true, TASK_TABLE_NAME, fieldList,
|
||||||
|
where, new String[] {name, approximateCreationDate}, null, null, null, null);
|
||||||
|
if (cursor == null)
|
||||||
|
throw new SQLException("Returned empty set!");
|
||||||
|
|
||||||
|
if (cursor.moveToFirst()) {
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
cursor.close();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// --- methods supporting individual features
|
||||||
|
|
||||||
|
/** Returns a TaskModelForView corresponding to the given TaskIdentifier */
|
||||||
|
public int fetchTaskPostponeCount(TaskIdentifier taskId) throws SQLException {
|
||||||
|
Cursor cursor = fetchTaskCursor(taskId, new String[] {AbstractTaskModel.POSTPONE_COUNT});
|
||||||
|
try {
|
||||||
|
if (cursor == null || cursor.getCount() == 0)
|
||||||
|
return 0;
|
||||||
|
cursor.moveToFirst();
|
||||||
|
return cursor.getInt(0);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return 0;
|
||||||
|
} finally {
|
||||||
|
if(cursor != null)
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<TaskModelForWidget> getTasksForWidget(String limit) {
|
||||||
|
|
||||||
|
Cursor cursor = database.query(TASK_TABLE_NAME, TaskModelForWidget.FIELD_LIST,
|
||||||
|
AbstractTaskModel.PROGRESS_PERCENTAGE + " < " +
|
||||||
|
AbstractTaskModel.COMPLETE_PERCENTAGE + " AND (" +
|
||||||
|
AbstractTaskModel.HIDDEN_UNTIL + " ISNULL OR " + AbstractTaskModel.HIDDEN_UNTIL + " < " +
|
||||||
|
System.currentTimeMillis() + ")", null, null, null,
|
||||||
|
AbstractTaskModel.IMPORTANCE + " * " + (5 * 24 * 3600 * 1000L) +
|
||||||
|
" + CASE WHEN MAX(pdd, ddd) = 0 THEN " +
|
||||||
|
(System.currentTimeMillis() + (7 * 24 * 3600 * 1000L)) +
|
||||||
|
" ELSE (CASE WHEN pdd = 0 THEN ddd ELSE pdd END) END ASC", limit);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ArrayList<TaskModelForWidget> list = new ArrayList<TaskModelForWidget>();
|
||||||
|
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext())
|
||||||
|
list.add(new TaskModelForWidget(cursor));
|
||||||
|
return list;
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<TaskModelForProvider> getTasksForProvider(String limit) {
|
||||||
|
|
||||||
|
Cursor cursor = database.query(TASK_TABLE_NAME, TaskModelForWidget.FIELD_LIST,
|
||||||
|
AbstractTaskModel.PROGRESS_PERCENTAGE + " < " +
|
||||||
|
AbstractTaskModel.COMPLETE_PERCENTAGE + " AND (" +
|
||||||
|
AbstractTaskModel.HIDDEN_UNTIL + " ISNULL OR " + AbstractTaskModel.HIDDEN_UNTIL + " < " +
|
||||||
|
System.currentTimeMillis() + ")", null, null, null,
|
||||||
|
AbstractTaskModel.IMPORTANCE + " * " + (5 * 24 * 3600 * 1000L) +
|
||||||
|
" + CASE WHEN MAX(pdd, ddd) = 0 THEN " +
|
||||||
|
(System.currentTimeMillis() + (7 * 24 * 3600 * 1000L)) +
|
||||||
|
" ELSE (CASE WHEN pdd = 0 THEN ddd ELSE pdd END) END ASC", limit);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ArrayList<TaskModelForProvider> list = new ArrayList<TaskModelForProvider>();
|
||||||
|
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext())
|
||||||
|
list.add(new TaskModelForProvider(cursor));
|
||||||
|
return list;
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- boilerplate
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor - takes the context to allow the database to be
|
||||||
|
* opened/created
|
||||||
|
*/
|
||||||
|
public TaskController(Context activity) {
|
||||||
|
this.context = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the notes database. If it cannot be opened, try to create a new
|
||||||
|
* instance of the database. If it cannot be created, throw an exception to
|
||||||
|
* signal the failure
|
||||||
|
*
|
||||||
|
* @return this (self reference, allowing this to be chained in an
|
||||||
|
* initialization call)
|
||||||
|
* @throws SQLException if the database could be neither opened or created
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public synchronized void open() throws SQLException {
|
||||||
|
SQLiteOpenHelper databaseHelper = new TaskModelDatabaseHelper(
|
||||||
|
context, TASK_TABLE_NAME, TASK_TABLE_NAME);
|
||||||
|
database = databaseHelper.getWritableDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Closes database resource */
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
database.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.task;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.Identifier;
|
||||||
|
|
||||||
|
|
||||||
|
public class TaskIdentifier extends Identifier {
|
||||||
|
|
||||||
|
public TaskIdentifier(long id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.task;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import android.database.Cursor;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.enums.Importance;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Fields that you would want to edit in the TaskModel */
|
||||||
|
public class TaskModelForEdit extends AbstractTaskModel {
|
||||||
|
|
||||||
|
static String[] FIELD_LIST = new String[] {
|
||||||
|
NAME,
|
||||||
|
IMPORTANCE,
|
||||||
|
ESTIMATED_SECONDS,
|
||||||
|
ELAPSED_SECONDS,
|
||||||
|
DEFINITE_DUE_DATE,
|
||||||
|
PREFERRED_DUE_DATE,
|
||||||
|
HIDDEN_UNTIL,
|
||||||
|
BLOCKING_ON,
|
||||||
|
NOTIFICATIONS,
|
||||||
|
NOTIFICATION_FLAGS,
|
||||||
|
LAST_NOTIFIED,
|
||||||
|
PROGRESS_PERCENTAGE,
|
||||||
|
NOTES,
|
||||||
|
REPEAT,
|
||||||
|
CALENDAR_URI,
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- constructors
|
||||||
|
|
||||||
|
public TaskModelForEdit() {
|
||||||
|
super();
|
||||||
|
setCreationDate(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
public TaskModelForEdit(TaskIdentifier identifier, Cursor cursor) {
|
||||||
|
super(identifier, cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- getters and setters
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTaskCompleted() {
|
||||||
|
return super.isTaskCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getNotificationIntervalSeconds() {
|
||||||
|
return super.getNotificationIntervalSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNotificationIntervalSeconds(Integer intervalInSeconds) {
|
||||||
|
super.setNotificationIntervalSeconds(intervalInSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getDefiniteDueDate() {
|
||||||
|
return super.getDefiniteDueDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getEstimatedSeconds() {
|
||||||
|
return super.getEstimatedSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getElapsedSeconds() {
|
||||||
|
return super.getElapsedSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getHiddenUntil() {
|
||||||
|
return super.getHiddenUntil();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Importance getImportance() {
|
||||||
|
return super.getImportance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return super.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNotes() {
|
||||||
|
return super.getNotes();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getPreferredDueDate() {
|
||||||
|
return super.getPreferredDueDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getProgressPercentage() {
|
||||||
|
return super.getProgressPercentage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TaskIdentifier getBlockingOn() {
|
||||||
|
return super.getBlockingOn();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNotificationFlags() {
|
||||||
|
return super.getNotificationFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getLastNotificationDate() {
|
||||||
|
return super.getLastNotificationDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RepeatInfo getRepeat() {
|
||||||
|
return super.getRepeat();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCalendarUri() {
|
||||||
|
return super.getCalendarUri();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefiniteDueDate(Date definiteDueDate) {
|
||||||
|
super.setDefiniteDueDate(definiteDueDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEstimatedSeconds(Integer estimatedSeconds) {
|
||||||
|
super.setEstimatedSeconds(estimatedSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setElapsedSeconds(int elapsedSeconds) {
|
||||||
|
super.setElapsedSeconds(elapsedSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHiddenUntil(Date hiddenUntil) {
|
||||||
|
super.setHiddenUntil(hiddenUntil);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setImportance(Importance importance) {
|
||||||
|
super.setImportance(importance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setName(String name) {
|
||||||
|
super.setName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNotes(String notes) {
|
||||||
|
super.setNotes(notes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPreferredDueDate(Date preferredDueDate) {
|
||||||
|
super.setPreferredDueDate(preferredDueDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBlockingOn(TaskIdentifier blockingOn) {
|
||||||
|
super.setBlockingOn(blockingOn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNotificationFlags(int flags) {
|
||||||
|
super.setNotificationFlags(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRepeat(RepeatInfo taskRepeat) {
|
||||||
|
super.setRepeat(taskRepeat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCalendarUri(String uri) {
|
||||||
|
super.setCalendarUri(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.task;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
import com.todoroo.astrid.legacy.data.alerts.AlertController;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Fields that you would want to read or edit in the onTaskSave and onTaskComplete
|
||||||
|
* event handlers */
|
||||||
|
public class TaskModelForHandlers extends AbstractTaskModel {
|
||||||
|
|
||||||
|
static String[] FIELD_LIST = new String[] {
|
||||||
|
AbstractController.KEY_ROWID,
|
||||||
|
REPEAT,
|
||||||
|
DEFINITE_DUE_DATE,
|
||||||
|
PREFERRED_DUE_DATE,
|
||||||
|
HIDDEN_UNTIL,
|
||||||
|
PROGRESS_PERCENTAGE,
|
||||||
|
ESTIMATED_SECONDS,
|
||||||
|
LAST_NOTIFIED,
|
||||||
|
NOTIFICATIONS,
|
||||||
|
NOTIFICATION_FLAGS,
|
||||||
|
FLAGS,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method updates the task to reflect a new repeat iteration. It moves
|
||||||
|
* back the due dates and updates other task properties accordingly.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param taskController
|
||||||
|
* @param repeatInfo
|
||||||
|
*/
|
||||||
|
public void repeatTaskBy(Context context, TaskController taskController,
|
||||||
|
RepeatInfo repeatInfo) {
|
||||||
|
|
||||||
|
// move dates back
|
||||||
|
if(getDefiniteDueDate() != null)
|
||||||
|
setDefiniteDueDate(repeatInfo.shiftDate(getDefiniteDueDate()));
|
||||||
|
if(getHiddenUntil() != null)
|
||||||
|
setHiddenUntil(repeatInfo.shiftDate(getHiddenUntil()));
|
||||||
|
if(getPreferredDueDate() != null)
|
||||||
|
setPreferredDueDate(repeatInfo.shiftDate(getPreferredDueDate()));
|
||||||
|
setProgressPercentage(0);
|
||||||
|
|
||||||
|
// set elapsed time to 0... yes, we're losing data
|
||||||
|
setElapsedSeconds(0);
|
||||||
|
|
||||||
|
// if no deadlines set, create one (so users don't get confused)
|
||||||
|
if(getDefiniteDueDate() == null && getPreferredDueDate() == null)
|
||||||
|
setPreferredDueDate(repeatInfo.shiftDate(new Date()));
|
||||||
|
|
||||||
|
// shift fixed alerts
|
||||||
|
AlertController alertController = new AlertController(context);
|
||||||
|
alertController.open();
|
||||||
|
List<Date> alerts = alertController.getTaskAlerts(getTaskIdentifier());
|
||||||
|
alertController.removeAlerts(getTaskIdentifier());
|
||||||
|
for(int i = 0; i < alerts.size(); i++) {
|
||||||
|
Date newAlert = repeatInfo.shiftDate(alerts.get(i));
|
||||||
|
alertController.addAlert(getTaskIdentifier(), newAlert);
|
||||||
|
alerts.set(i, newAlert);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset periodic alerts
|
||||||
|
setLastNotificationTime(null);
|
||||||
|
alertController.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- constructors
|
||||||
|
|
||||||
|
public TaskModelForHandlers(Cursor cursor, ContentValues setValues) {
|
||||||
|
super(cursor);
|
||||||
|
this.setValues = setValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- getters and setters
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RepeatInfo getRepeat() {
|
||||||
|
return super.getRepeat();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getNotificationIntervalSeconds() {
|
||||||
|
return super.getNotificationIntervalSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTaskCompleted() {
|
||||||
|
return super.isTaskCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getDefiniteDueDate() {
|
||||||
|
return super.getDefiniteDueDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getEstimatedSeconds() {
|
||||||
|
return super.getEstimatedSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getHiddenUntil() {
|
||||||
|
return super.getHiddenUntil();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getPreferredDueDate() {
|
||||||
|
return super.getPreferredDueDate();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int getNotificationFlags() {
|
||||||
|
return super.getNotificationFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getLastNotificationDate() {
|
||||||
|
return super.getLastNotificationDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFlags() {
|
||||||
|
return super.getFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefiniteDueDate(Date definiteDueDate) {
|
||||||
|
super.setDefiniteDueDate(definiteDueDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPreferredDueDate(Date preferredDueDate) {
|
||||||
|
super.setPreferredDueDate(preferredDueDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHiddenUntil(Date hiddenUntil) {
|
||||||
|
super.setHiddenUntil(hiddenUntil);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,267 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.task;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
import com.todoroo.astrid.legacy.data.enums.Importance;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Fields that you would want to edit in the TaskModel */
|
||||||
|
public class TaskModelForList extends AbstractTaskModel {
|
||||||
|
|
||||||
|
static String[] FIELD_LIST = new String[] {
|
||||||
|
AbstractController.KEY_ROWID,
|
||||||
|
NAME,
|
||||||
|
IMPORTANCE,
|
||||||
|
ELAPSED_SECONDS,
|
||||||
|
ESTIMATED_SECONDS,
|
||||||
|
TIMER_START,
|
||||||
|
DEFINITE_DUE_DATE,
|
||||||
|
PREFERRED_DUE_DATE,
|
||||||
|
NOTIFICATIONS,
|
||||||
|
PROGRESS_PERCENTAGE,
|
||||||
|
COMPLETION_DATE,
|
||||||
|
CREATION_DATE,
|
||||||
|
HIDDEN_UNTIL,
|
||||||
|
NOTES,
|
||||||
|
REPEAT,
|
||||||
|
FLAGS,
|
||||||
|
};
|
||||||
|
|
||||||
|
// pre-load the cache for our column keys
|
||||||
|
static {
|
||||||
|
HashMap<String, Integer> indexCache = new HashMap<String, Integer>();
|
||||||
|
columnIndexCache.put(TaskModelForList.class, indexCache);
|
||||||
|
for(int i = 0; i < FIELD_LIST.length; i++)
|
||||||
|
indexCache.put(FIELD_LIST[i], i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the weighted score for this task. Smaller is more important */
|
||||||
|
public int getTaskWeight() {
|
||||||
|
int weight = 0;
|
||||||
|
|
||||||
|
// bubble tasks with timers to the top
|
||||||
|
if(getTimerStart() != null)
|
||||||
|
weight -= 10000;
|
||||||
|
|
||||||
|
// importance
|
||||||
|
weight += getImportance().ordinal() * 80;
|
||||||
|
|
||||||
|
// looming absolute deadline
|
||||||
|
if(getDefiniteDueDate() != null) {
|
||||||
|
int hoursLeft = (int) ((getDefiniteDueDate().getTime() -
|
||||||
|
System.currentTimeMillis())/1000/3600);
|
||||||
|
if(hoursLeft < 5*24)
|
||||||
|
weight += (hoursLeft - 5*24);
|
||||||
|
weight -= 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
// looming preferred deadline
|
||||||
|
if(getPreferredDueDate() != null) {
|
||||||
|
int hoursLeft = (int) ((getPreferredDueDate().getTime() -
|
||||||
|
System.currentTimeMillis())/1000/3600);
|
||||||
|
if(hoursLeft < 5*24)
|
||||||
|
weight += (hoursLeft - 5*24)/2;
|
||||||
|
weight -= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bubble completed tasks to the bottom
|
||||||
|
if(isTaskCompleted()) {
|
||||||
|
if(getCompletionDate() == null)
|
||||||
|
weight += 1e6;
|
||||||
|
else
|
||||||
|
weight = (int)Math.max(10000 + (System.currentTimeMillis() -
|
||||||
|
getCompletionDate().getTime()) / 1000, 10000);
|
||||||
|
return weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isHidden() {
|
||||||
|
return super.isHidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** map of cached display labels */
|
||||||
|
private HashMap<Integer, String> displayLabels = new HashMap<Integer, String>();
|
||||||
|
|
||||||
|
public String getCachedLabel(int key) {
|
||||||
|
return displayLabels.get(key);
|
||||||
|
}
|
||||||
|
public void putCachedLabel(int key, String value) {
|
||||||
|
displayLabels.put(key, value);
|
||||||
|
}
|
||||||
|
public void clearCache() {
|
||||||
|
displayLabels.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- constructors
|
||||||
|
|
||||||
|
public TaskModelForList(Cursor cursor) {
|
||||||
|
super(cursor);
|
||||||
|
|
||||||
|
prefetchData(FIELD_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- exposed getters and setters
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTaskCompleted() {
|
||||||
|
return super.isTaskCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTaskColorResource(Context context) {
|
||||||
|
return super.getTaskColorResource(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getElapsedSeconds() {
|
||||||
|
return super.getElapsedSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getCompletedPercentage() {
|
||||||
|
return COMPLETE_PERCENTAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getDefiniteDueDate() {
|
||||||
|
return super.getDefiniteDueDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getEstimatedSeconds() {
|
||||||
|
return super.getEstimatedSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getHiddenUntil() {
|
||||||
|
return super.getHiddenUntil();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Importance getImportance() {
|
||||||
|
return super.getImportance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return super.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getPreferredDueDate() {
|
||||||
|
return super.getPreferredDueDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getProgressPercentage() {
|
||||||
|
return super.getProgressPercentage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getTimerStart() {
|
||||||
|
return super.getTimerStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getCompletionDate() {
|
||||||
|
return super.getCompletionDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNotes() {
|
||||||
|
return super.getNotes();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getNotificationIntervalSeconds() {
|
||||||
|
return super.getNotificationIntervalSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RepeatInfo getRepeat() {
|
||||||
|
return super.getRepeat();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getCreationDate() {
|
||||||
|
return super.getCreationDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFlags() {
|
||||||
|
return super.getFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- setters
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setProgressPercentage(int progressPercentage) {
|
||||||
|
super.setProgressPercentage(progressPercentage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTimerStart(Date timerStart) {
|
||||||
|
super.setTimerStart(timerStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopTimerAndUpdateElapsedTime() {
|
||||||
|
super.stopTimerAndUpdateElapsedTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getNameField() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPreferredDueDate(Date preferredDueDate) {
|
||||||
|
super.setPreferredDueDate(preferredDueDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefiniteDueDate(Date definiteDueDate) {
|
||||||
|
super.setDefiniteDueDate(definiteDueDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setImportance(Importance importance) {
|
||||||
|
super.setImportance(importance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHiddenUntil(Date hiddenUntil) {
|
||||||
|
super.setHiddenUntil(hiddenUntil);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPostponeCount(int postponeCount) {
|
||||||
|
super.setPostponeCount(postponeCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.task;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import android.database.Cursor;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Fields that you would want to see in the TaskView activity */
|
||||||
|
public class TaskModelForNotify extends AbstractTaskModel {
|
||||||
|
|
||||||
|
static String[] FIELD_LIST = new String[] {
|
||||||
|
AbstractController.KEY_ROWID,
|
||||||
|
ESTIMATED_SECONDS,
|
||||||
|
NOTIFICATIONS,
|
||||||
|
NOTIFICATION_FLAGS,
|
||||||
|
LAST_NOTIFIED,
|
||||||
|
HIDDEN_UNTIL,
|
||||||
|
PROGRESS_PERCENTAGE,
|
||||||
|
DEFINITE_DUE_DATE,
|
||||||
|
PREFERRED_DUE_DATE,
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- constructors
|
||||||
|
|
||||||
|
public TaskModelForNotify(Cursor cursor) {
|
||||||
|
super(cursor);
|
||||||
|
|
||||||
|
prefetchData(FIELD_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- getters
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getEstimatedSeconds() {
|
||||||
|
return super.getEstimatedSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTaskCompleted() {
|
||||||
|
return super.isTaskCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getNotificationIntervalSeconds() {
|
||||||
|
return super.getNotificationIntervalSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getHiddenUntil() {
|
||||||
|
return super.getHiddenUntil();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getDefiniteDueDate() {
|
||||||
|
return super.getDefiniteDueDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getPreferredDueDate() {
|
||||||
|
return super.getPreferredDueDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNotificationFlags() {
|
||||||
|
return super.getNotificationFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getLastNotificationDate() {
|
||||||
|
return super.getLastNotificationDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- setters
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLastNotificationTime(Date date) {
|
||||||
|
super.setLastNotificationTime(date);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Francois DESLANDES
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.task;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import android.database.Cursor;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
import com.todoroo.astrid.legacy.data.enums.Importance;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Fields that you would want to see in the TaskView activity */
|
||||||
|
public class TaskModelForProvider extends AbstractTaskModel {
|
||||||
|
|
||||||
|
static String[] FIELD_LIST = new String[] {
|
||||||
|
AbstractController.KEY_ROWID,
|
||||||
|
NAME,
|
||||||
|
IMPORTANCE,
|
||||||
|
PREFERRED_DUE_DATE,
|
||||||
|
DEFINITE_DUE_DATE,
|
||||||
|
"COALESCE(" + PREFERRED_DUE_DATE + ", 0) as pdd",
|
||||||
|
"COALESCE(" + DEFINITE_DUE_DATE + ", 0) as ddd"
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- constructors
|
||||||
|
|
||||||
|
public TaskModelForProvider(Cursor cursor) {
|
||||||
|
super(cursor);
|
||||||
|
|
||||||
|
prefetchData(FIELD_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- getters
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return super.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Importance getImportance() {
|
||||||
|
return super.getImportance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getPreferredDueDate() {
|
||||||
|
return super.getPreferredDueDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getDefiniteDueDate() {
|
||||||
|
return super.getDefiniteDueDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.task;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import android.database.Cursor;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Fields that you would want to see in the TaskView activity */
|
||||||
|
public class TaskModelForReminder extends AbstractTaskModel {
|
||||||
|
|
||||||
|
static String[] FIELD_LIST = new String[] {
|
||||||
|
AbstractController.KEY_ROWID,
|
||||||
|
NAME,
|
||||||
|
NOTIFICATION_FLAGS,
|
||||||
|
HIDDEN_UNTIL,
|
||||||
|
TIMER_START,
|
||||||
|
PROGRESS_PERCENTAGE,
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- constructors
|
||||||
|
|
||||||
|
public TaskModelForReminder(Cursor cursor) {
|
||||||
|
super(cursor);
|
||||||
|
|
||||||
|
prefetchData(FIELD_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- getters
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return super.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getTimerStart() {
|
||||||
|
return super.getTimerStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTaskCompleted() {
|
||||||
|
return super.isTaskCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getHiddenUntil() {
|
||||||
|
return super.getHiddenUntil();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNotificationFlags() {
|
||||||
|
return super.getNotificationFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- setters
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLastNotificationTime(Date date) {
|
||||||
|
super.setLastNotificationTime(date);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,236 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.task;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import android.database.Cursor;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
import com.todoroo.astrid.legacy.data.enums.Importance;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Fields that you would want to synchronize in the TaskModel */
|
||||||
|
public class TaskModelForSync extends AbstractTaskModel {
|
||||||
|
|
||||||
|
static String[] FIELD_LIST = new String[] {
|
||||||
|
AbstractController.KEY_ROWID,
|
||||||
|
NAME,
|
||||||
|
IMPORTANCE,
|
||||||
|
ESTIMATED_SECONDS,
|
||||||
|
ELAPSED_SECONDS,
|
||||||
|
DEFINITE_DUE_DATE,
|
||||||
|
PREFERRED_DUE_DATE,
|
||||||
|
HIDDEN_UNTIL,
|
||||||
|
BLOCKING_ON,
|
||||||
|
PROGRESS_PERCENTAGE,
|
||||||
|
CREATION_DATE,
|
||||||
|
COMPLETION_DATE,
|
||||||
|
NOTES,
|
||||||
|
REPEAT,
|
||||||
|
LAST_NOTIFIED,
|
||||||
|
NOTIFICATIONS,
|
||||||
|
NOTIFICATION_FLAGS,
|
||||||
|
FLAGS,
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- constructors
|
||||||
|
|
||||||
|
public TaskModelForSync() {
|
||||||
|
super();
|
||||||
|
setCreationDate(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
public TaskModelForSync(Cursor cursor) {
|
||||||
|
super(cursor);
|
||||||
|
prefetchData(FIELD_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- getters and setters
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTaskCompleted() {
|
||||||
|
return super.isTaskCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getDefiniteDueDate() {
|
||||||
|
return super.getDefiniteDueDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getEstimatedSeconds() {
|
||||||
|
return super.getEstimatedSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getProgressPercentage() {
|
||||||
|
return super.getProgressPercentage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getCreationDate() {
|
||||||
|
return super.getCreationDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getCompletionDate() {
|
||||||
|
return super.getCompletionDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getElapsedSeconds() {
|
||||||
|
return super.getElapsedSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getHiddenUntil() {
|
||||||
|
return super.getHiddenUntil();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Importance getImportance() {
|
||||||
|
return super.getImportance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return super.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNotes() {
|
||||||
|
return super.getNotes();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getPreferredDueDate() {
|
||||||
|
return super.getPreferredDueDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TaskIdentifier getBlockingOn() {
|
||||||
|
return super.getBlockingOn();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RepeatInfo getRepeat() {
|
||||||
|
return super.getRepeat();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getNotificationIntervalSeconds() {
|
||||||
|
return super.getNotificationIntervalSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNotificationFlags() {
|
||||||
|
return super.getNotificationFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getLastNotificationDate() {
|
||||||
|
return super.getLastNotificationDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFlags() {
|
||||||
|
return super.getFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- setters
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefiniteDueDate(Date definiteDueDate) {
|
||||||
|
super.setDefiniteDueDate(definiteDueDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEstimatedSeconds(Integer estimatedSeconds) {
|
||||||
|
super.setEstimatedSeconds(estimatedSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setElapsedSeconds(int elapsedSeconds) {
|
||||||
|
super.setElapsedSeconds(elapsedSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHiddenUntil(Date hiddenUntil) {
|
||||||
|
super.setHiddenUntil(hiddenUntil);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setImportance(Importance importance) {
|
||||||
|
super.setImportance(importance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setName(String name) {
|
||||||
|
super.setName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNotes(String notes) {
|
||||||
|
super.setNotes(notes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPreferredDueDate(Date preferredDueDate) {
|
||||||
|
super.setPreferredDueDate(preferredDueDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBlockingOn(TaskIdentifier blockingOn) {
|
||||||
|
super.setBlockingOn(blockingOn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRepeat(RepeatInfo taskRepeat) {
|
||||||
|
super.setRepeat(taskRepeat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCompletionDate(Date completionDate) {
|
||||||
|
super.setCompletionDate(completionDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCreationDate(Date creationDate) {
|
||||||
|
super.setCreationDate(creationDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setProgressPercentage(int progressPercentage) {
|
||||||
|
super.setProgressPercentage(progressPercentage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNotificationIntervalSeconds(Integer intervalInSeconds) {
|
||||||
|
super.setNotificationIntervalSeconds(intervalInSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFlags(int flags) {
|
||||||
|
super.setFlags(flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.legacy.data.task;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import android.database.Cursor;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
import com.todoroo.astrid.legacy.data.enums.Importance;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Fields that you would want to see in the TaskView activity */
|
||||||
|
public class TaskModelForWidget extends AbstractTaskModel {
|
||||||
|
|
||||||
|
static String[] FIELD_LIST = new String[] {
|
||||||
|
AbstractController.KEY_ROWID,
|
||||||
|
NAME,
|
||||||
|
IMPORTANCE,
|
||||||
|
PREFERRED_DUE_DATE,
|
||||||
|
DEFINITE_DUE_DATE,
|
||||||
|
"COALESCE(" + PREFERRED_DUE_DATE + ", 0) as pdd",
|
||||||
|
"COALESCE(" + DEFINITE_DUE_DATE + ", 0) as ddd"
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- constructors
|
||||||
|
|
||||||
|
public TaskModelForWidget(Cursor cursor) {
|
||||||
|
super(cursor);
|
||||||
|
|
||||||
|
prefetchData(FIELD_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- getters
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return super.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Importance getImportance() {
|
||||||
|
return super.getImportance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getPreferredDueDate() {
|
||||||
|
return super.getPreferredDueDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getDefiniteDueDate() {
|
||||||
|
return super.getDefiniteDueDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,218 @@
|
|||||||
|
package com.todoroo.astrid.legacy.data.task;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.timsu.astrid.R;
|
||||||
|
import com.timsu.astrid.utilities.DateUtilities;
|
||||||
|
import com.todoroo.astrid.legacy.data.AbstractController;
|
||||||
|
import com.todoroo.astrid.legacy.data.enums.Importance;
|
||||||
|
import com.todoroo.astrid.legacy.data.enums.RepeatInterval;
|
||||||
|
|
||||||
|
public class TaskModelForXml extends AbstractTaskModel {
|
||||||
|
|
||||||
|
static String[] FIELD_LIST = new String[] {
|
||||||
|
AbstractController.KEY_ROWID,
|
||||||
|
NAME,
|
||||||
|
IMPORTANCE,
|
||||||
|
ELAPSED_SECONDS,
|
||||||
|
ESTIMATED_SECONDS,
|
||||||
|
TIMER_START,
|
||||||
|
DEFINITE_DUE_DATE,
|
||||||
|
PREFERRED_DUE_DATE,
|
||||||
|
NOTIFICATIONS,
|
||||||
|
PROGRESS_PERCENTAGE,
|
||||||
|
COMPLETION_DATE,
|
||||||
|
CREATION_DATE,
|
||||||
|
HIDDEN_UNTIL,
|
||||||
|
NOTES,
|
||||||
|
REPEAT,
|
||||||
|
FLAGS,
|
||||||
|
POSTPONE_COUNT,
|
||||||
|
BLOCKING_ON,
|
||||||
|
LAST_NOTIFIED,
|
||||||
|
NOTIFICATION_FLAGS,
|
||||||
|
CALENDAR_URI,
|
||||||
|
};
|
||||||
|
private HashMap<String, String> taskAttributesMap;
|
||||||
|
public static final String REPEAT_VALUE = "repeat_value";
|
||||||
|
public static final String REPEAT_INTERVAL = "repeat_interval";
|
||||||
|
|
||||||
|
|
||||||
|
private RepeatInterval repeatInterval = null;
|
||||||
|
private Integer repeatValue = null;
|
||||||
|
|
||||||
|
// --- constructors
|
||||||
|
|
||||||
|
public TaskModelForXml() {
|
||||||
|
super();
|
||||||
|
setCreationDate(new Date());
|
||||||
|
taskAttributesMap = new HashMap<String, String>(FIELD_LIST.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TaskModelForXml(Cursor cursor) {
|
||||||
|
super(cursor);
|
||||||
|
prefetchData(FIELD_LIST);
|
||||||
|
taskAttributesMap = new HashMap<String, String>(FIELD_LIST.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Safely add a value from a date field (in case of null values) to the
|
||||||
|
taskAttributesMap.
|
||||||
|
*/
|
||||||
|
private void safePutDate(String field, Date value) {
|
||||||
|
if (value != null) {
|
||||||
|
taskAttributesMap.put(field, DateUtilities.getIso8601String(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- getters and setters
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getCreationDate() {
|
||||||
|
return super.getCreationDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build a HashMap of task fields and associated values.
|
||||||
|
*/
|
||||||
|
public HashMap<String, String> getTaskAttributes() {
|
||||||
|
taskAttributesMap.put(AbstractController.KEY_ROWID, getTaskIdentifier().idAsString());
|
||||||
|
taskAttributesMap.put(NAME, getName());
|
||||||
|
taskAttributesMap.put(IMPORTANCE, getImportance().toString());
|
||||||
|
taskAttributesMap.put(ELAPSED_SECONDS, getElapsedSeconds().toString());
|
||||||
|
taskAttributesMap.put(ESTIMATED_SECONDS, getEstimatedSeconds().toString());
|
||||||
|
safePutDate(TIMER_START, getTimerStart());
|
||||||
|
safePutDate(DEFINITE_DUE_DATE, getDefiniteDueDate());
|
||||||
|
safePutDate(PREFERRED_DUE_DATE, getPreferredDueDate());
|
||||||
|
taskAttributesMap.put(NOTIFICATIONS, getNotificationIntervalSeconds().toString());
|
||||||
|
taskAttributesMap.put(PROGRESS_PERCENTAGE, Integer.toString(getProgressPercentage()));
|
||||||
|
safePutDate(COMPLETION_DATE, getCompletionDate());
|
||||||
|
safePutDate(CREATION_DATE, getCreationDate());
|
||||||
|
safePutDate(HIDDEN_UNTIL, getHiddenUntil());
|
||||||
|
taskAttributesMap.put(NOTES, getNotes());
|
||||||
|
RepeatInfo repeat = getRepeat();
|
||||||
|
if (repeat != null) {
|
||||||
|
taskAttributesMap.put(REPEAT_VALUE, Integer.toString(repeat.getValue()));
|
||||||
|
taskAttributesMap.put(REPEAT_INTERVAL, repeat.getInterval().toString());
|
||||||
|
}
|
||||||
|
taskAttributesMap.put(FLAGS, Integer.toString(getFlags()));
|
||||||
|
taskAttributesMap.put(POSTPONE_COUNT, getPostponeCount().toString());
|
||||||
|
taskAttributesMap.put(BLOCKING_ON, Long.toString(getBlockingOn().getId()));
|
||||||
|
safePutDate(LAST_NOTIFIED, getLastNotificationDate());
|
||||||
|
taskAttributesMap.put(NOTIFICATION_FLAGS, Integer.toString(getNotificationFlags()));
|
||||||
|
String calendarUri = getCalendarUri();
|
||||||
|
if (calendarUri != null) {
|
||||||
|
taskAttributesMap.put(CALENDAR_URI, calendarUri);
|
||||||
|
}
|
||||||
|
return taskAttributesMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- setters
|
||||||
|
|
||||||
|
public boolean setField(String field, String value) {
|
||||||
|
boolean success = true;
|
||||||
|
if(field.equals(NAME)) {
|
||||||
|
setName(value);
|
||||||
|
}
|
||||||
|
else if(field.equals(NOTES)) {
|
||||||
|
setNotes(value);
|
||||||
|
}
|
||||||
|
else if(field.equals(PROGRESS_PERCENTAGE)) {
|
||||||
|
setProgressPercentage(Integer.parseInt(value));
|
||||||
|
}
|
||||||
|
else if(field.equals(IMPORTANCE)) {
|
||||||
|
setImportance(Importance.valueOf(value));
|
||||||
|
}
|
||||||
|
else if(field.equals(ESTIMATED_SECONDS)) {
|
||||||
|
setEstimatedSeconds(Integer.parseInt(value));
|
||||||
|
}
|
||||||
|
else if(field.equals(ELAPSED_SECONDS)) {
|
||||||
|
setElapsedSeconds(Integer.parseInt(value));
|
||||||
|
}
|
||||||
|
else if(field.equals(TIMER_START)) {
|
||||||
|
setTimerStart(DateUtilities.getDateFromIso8601String(value));
|
||||||
|
}
|
||||||
|
else if(field.equals(DEFINITE_DUE_DATE)) {
|
||||||
|
setDefiniteDueDate(DateUtilities.getDateFromIso8601String(value));
|
||||||
|
}
|
||||||
|
else if(field.equals(PREFERRED_DUE_DATE)) {
|
||||||
|
setPreferredDueDate(DateUtilities.getDateFromIso8601String(value));
|
||||||
|
}
|
||||||
|
else if(field.equals(HIDDEN_UNTIL)) {
|
||||||
|
setHiddenUntil(DateUtilities.getDateFromIso8601String(value));
|
||||||
|
}
|
||||||
|
else if(field.equals(BLOCKING_ON)) {
|
||||||
|
setBlockingOn(new TaskIdentifier(Long.parseLong(value)));
|
||||||
|
}
|
||||||
|
else if(field.equals(POSTPONE_COUNT)) {
|
||||||
|
setPostponeCount(Integer.parseInt(value));
|
||||||
|
}
|
||||||
|
else if(field.equals(NOTIFICATIONS)) {
|
||||||
|
setNotificationIntervalSeconds(Integer.parseInt(value));
|
||||||
|
}
|
||||||
|
else if(field.equals(CREATION_DATE)) {
|
||||||
|
setCreationDate(DateUtilities.getDateFromIso8601String(value));
|
||||||
|
}
|
||||||
|
else if(field.equals(COMPLETION_DATE)) {
|
||||||
|
setCompletionDate(DateUtilities.getDateFromIso8601String(value));
|
||||||
|
}
|
||||||
|
else if(field.equals(NOTIFICATION_FLAGS)) {
|
||||||
|
setNotificationFlags(Integer.parseInt(value));
|
||||||
|
}
|
||||||
|
else if(field.equals(LAST_NOTIFIED)) {
|
||||||
|
setLastNotificationTime(DateUtilities.getDateFromIso8601String(value));
|
||||||
|
}
|
||||||
|
else if(field.equals(REPEAT_INTERVAL)) {
|
||||||
|
try {
|
||||||
|
setRepeatInterval(RepeatInterval.valueOf(value));
|
||||||
|
} catch (Exception e) {
|
||||||
|
RepeatInterval repeatInterval;
|
||||||
|
switch (Integer.parseInt(value)) {
|
||||||
|
case R.string.repeat_days:
|
||||||
|
repeatInterval = RepeatInterval.DAYS;
|
||||||
|
break;
|
||||||
|
case R.string.repeat_weeks:
|
||||||
|
repeatInterval = RepeatInterval.WEEKS;
|
||||||
|
break;
|
||||||
|
case R.string.repeat_months:
|
||||||
|
repeatInterval = RepeatInterval.MONTHS;
|
||||||
|
break;
|
||||||
|
case R.string.repeat_hours:
|
||||||
|
repeatInterval = RepeatInterval.HOURS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.e("XmlImport", "Unable to set repeat interval");
|
||||||
|
repeatInterval = RepeatInterval.DAYS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
setRepeatInterval(repeatInterval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(field.equals(REPEAT_VALUE)) {
|
||||||
|
setRepeatValue(Integer.parseInt(value));
|
||||||
|
}
|
||||||
|
else if(field.equals(FLAGS)) {
|
||||||
|
setFlags(Integer.parseInt(value));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRepeatInterval(RepeatInterval repeatInterval) {
|
||||||
|
this.repeatInterval = repeatInterval;
|
||||||
|
if (repeatValue != null) {
|
||||||
|
setRepeat(new RepeatInfo(repeatInterval, repeatValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRepeatValue(Integer repeatValue) {
|
||||||
|
this.repeatValue = repeatValue;
|
||||||
|
if (repeatInterval != null) {
|
||||||
|
setRepeat(new RepeatInfo(repeatInterval, repeatValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,117 @@
|
|||||||
|
package com.todoroo.astrid.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
|
||||||
|
import com.todoroo.andlib.service.Autowired;
|
||||||
|
import com.todoroo.andlib.test.utility.DateUtilities;
|
||||||
|
import com.todoroo.astrid.service.TaskService;
|
||||||
|
import com.todoroo.astrid.test.DatabaseTestCase;
|
||||||
|
import com.todoroo.astrid.utility.Preferences;
|
||||||
|
|
||||||
|
public class TaskTests extends DatabaseTestCase {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
TaskService taskService;
|
||||||
|
|
||||||
|
/** Sanity-check the constants */
|
||||||
|
public void testSanity() {
|
||||||
|
assertTrue(Task.IMPORTANCE_DO_OR_DIE < Task.IMPORTANCE_MUST_DO);
|
||||||
|
assertTrue(Task.IMPORTANCE_MUST_DO < Task.IMPORTANCE_SHOULD_DO);
|
||||||
|
assertTrue(Task.IMPORTANCE_SHOULD_DO < Task.IMPORTANCE_NONE);
|
||||||
|
|
||||||
|
ArrayList<Integer> urgencies = new ArrayList<Integer>();
|
||||||
|
urgencies.add(Task.URGENCY_NONE);
|
||||||
|
urgencies.add(Task.URGENCY_SPECIFIC_DAY);
|
||||||
|
urgencies.add(Task.URGENCY_SPECIFIC_DAY_TIME);
|
||||||
|
urgencies.add(Task.URGENCY_THIS_MONTH);
|
||||||
|
urgencies.add(Task.URGENCY_THIS_WEEK);
|
||||||
|
urgencies.add(Task.URGENCY_TODAY);
|
||||||
|
urgencies.add(Task.URGENCY_WITHIN_A_YEAR);
|
||||||
|
urgencies.add(Task.URGENCY_WITHIN_SIX_MONTHS);
|
||||||
|
urgencies.add(Task.URGENCY_WITHIN_THREE_MONTHS);
|
||||||
|
|
||||||
|
// assert no duplicates
|
||||||
|
assertEquals(new TreeSet<Integer>(urgencies).size(),
|
||||||
|
urgencies.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Check defaults */
|
||||||
|
public void checkDefaults() {
|
||||||
|
Preferences.setPreferenceDefaults();
|
||||||
|
ContentValues defaults = new Task().getDefaultValues();
|
||||||
|
assertTrue(defaults.containsKey(Task.TITLE.name));
|
||||||
|
assertTrue(defaults.containsKey(Task.DUE_DATE.name));
|
||||||
|
assertTrue(defaults.containsKey(Task.HIDDEN_UNTIL.name));
|
||||||
|
assertTrue(defaults.containsKey(Task.COMPLETION_DATE.name));
|
||||||
|
assertTrue(defaults.containsKey(Task.URGENCY.name));
|
||||||
|
assertTrue(defaults.containsKey(Task.IMPORTANCE.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Check task gets a creation date at some point */
|
||||||
|
public void checkCreationDate() {
|
||||||
|
Task task = new Task();
|
||||||
|
taskService.save(task, false);
|
||||||
|
assertTrue(task.getValue(Task.CREATION_DATE) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check various getters
|
||||||
|
*/
|
||||||
|
public void checkGetters() {
|
||||||
|
Task task = new Task();
|
||||||
|
assertFalse(task.isCompleted());
|
||||||
|
task.setValue(Task.COMPLETION_DATE, DateUtilities.now());
|
||||||
|
assertTrue(task.isCompleted());
|
||||||
|
|
||||||
|
task = new Task();
|
||||||
|
assertFalse(task.isHidden());
|
||||||
|
task.setValue(Task.HIDDEN_UNTIL, DateUtilities.now() + 1000);
|
||||||
|
assertTrue(task.isHidden());
|
||||||
|
|
||||||
|
task = new Task();
|
||||||
|
assertFalse(task.hasDueDate());
|
||||||
|
task.setValue(Task.DUE_DATE, DateUtilities.now() + 1000);
|
||||||
|
assertTrue(task.hasDueDate());
|
||||||
|
|
||||||
|
int[] colors = Task.getImportanceColors(getContext());
|
||||||
|
assertEquals(Math.abs(Task.IMPORTANCE_NONE - Task.IMPORTANCE_DO_OR_DIE + 1),
|
||||||
|
colors.length);
|
||||||
|
HashSet<Integer> set = new HashSet<Integer>();
|
||||||
|
for(int i = 0; i < colors.length; i++) {
|
||||||
|
assertFalse(set.contains(colors[i]));
|
||||||
|
set.add(colors[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkDueDateInitialization() {
|
||||||
|
assertEquals(0, Task.initializeDueDate(Task.URGENCY_NONE));
|
||||||
|
|
||||||
|
int date = Task.initializeDueDate(Task.URGENCY_THIS_MONTH);
|
||||||
|
assertTrue(date > DateUtilities.now() + 27 * 24 * 3600);
|
||||||
|
assertTrue(date < DateUtilities.now() + 32 * 24 * 3600);
|
||||||
|
|
||||||
|
date = Task.initializeDueDate(Task.URGENCY_THIS_WEEK);
|
||||||
|
assertTrue(date > DateUtilities.now() + 6 * 24 * 3600);
|
||||||
|
assertTrue(date < DateUtilities.now() + 8 * 24 * 3600);
|
||||||
|
|
||||||
|
date = Task.initializeDueDate(Task.URGENCY_TODAY);
|
||||||
|
assertTrue(date > DateUtilities.now() - 60);
|
||||||
|
assertTrue(date < DateUtilities.now() + 24 * 3600);
|
||||||
|
|
||||||
|
date = Task.initializeDueDate(Task.URGENCY_WITHIN_THREE_MONTHS);
|
||||||
|
assertTrue(date > DateUtilities.now() + 85 * 24 * 3600);
|
||||||
|
assertTrue(date < DateUtilities.now() + 95 * 24 * 3600);
|
||||||
|
|
||||||
|
date = Task.initializeDueDate(Task.URGENCY_WITHIN_SIX_MONTHS);
|
||||||
|
assertTrue(date > DateUtilities.now() + 180 * 24 * 3600);
|
||||||
|
assertTrue(date < DateUtilities.now() + 185 * 24 * 3600);
|
||||||
|
|
||||||
|
date = Task.initializeDueDate(Task.URGENCY_WITHIN_A_YEAR);
|
||||||
|
assertTrue(date > DateUtilities.now() + 364 * 24 * 3600);
|
||||||
|
assertTrue(date < DateUtilities.now() + 367 * 24 * 3600);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,425 @@
|
|||||||
|
package com.todoroo.astrid.provider;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.api.AstridContentProvider;
|
||||||
|
import com.todoroo.astrid.api.AstridContentProvider.AstridTask;
|
||||||
|
import com.todoroo.astrid.test.DatabaseTestCase;
|
||||||
|
|
||||||
|
public class ProviderTests extends DatabaseTestCase {
|
||||||
|
|
||||||
|
String[] PROJECTION = new String[] {
|
||||||
|
AstridTask.ID,
|
||||||
|
AstridTask.TITLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Test CRUD over tasks with the ALL ITEMS cursor */
|
||||||
|
public void testAllItemsCrud() {
|
||||||
|
ContentResolver resolver = getContext().getContentResolver();
|
||||||
|
|
||||||
|
// fetch all tasks, get nothing
|
||||||
|
Uri uri = AstridContentProvider.allItemsUri();
|
||||||
|
Cursor cursor = resolver.query(uri, PROJECTION, "1", null, null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// insert a task
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(AstridTask.TITLE, "mf doom?");
|
||||||
|
resolver.insert(uri, values);
|
||||||
|
|
||||||
|
// fetch all tasks, get something
|
||||||
|
cursor = resolver.query(uri, PROJECTION, "1", null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.moveToFirst();
|
||||||
|
assertEquals("mf doom?", cursor.getString(1));
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// delete a task
|
||||||
|
assertEquals(1, resolver.delete(uri, "1", null));
|
||||||
|
|
||||||
|
// fetch all tasks, get nothing
|
||||||
|
cursor = resolver.query(uri, PROJECTION, null, null, null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test selecting data */
|
||||||
|
public void testSelection() {
|
||||||
|
ContentResolver resolver = getContext().getContentResolver();
|
||||||
|
Uri uri = AstridContentProvider.allItemsUri();
|
||||||
|
|
||||||
|
// insert some tasks
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(AstridTask.TITLE, "tujiko noriko");
|
||||||
|
values.put(AstridTask.IMPORTANCE, AstridTask.IMPORTANCE_MUST_DO);
|
||||||
|
resolver.insert(uri, values);
|
||||||
|
|
||||||
|
values.clear();
|
||||||
|
values.put(AstridTask.TITLE, "miho asahi");
|
||||||
|
values.put(AstridTask.IMPORTANCE, AstridTask.IMPORTANCE_NONE);
|
||||||
|
resolver.insert(uri, values);
|
||||||
|
|
||||||
|
// fetch all tasks with various selection parameters
|
||||||
|
Cursor cursor = resolver.query(uri, PROJECTION, "1", null, null);
|
||||||
|
assertEquals(2, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
cursor = resolver.query(uri, PROJECTION, null, null, null);
|
||||||
|
assertEquals(2, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
cursor = resolver.query(uri, PROJECTION, AstridTask.IMPORTANCE + "=" +
|
||||||
|
AstridTask.IMPORTANCE_MUST_DO, null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.moveToFirst();
|
||||||
|
assertEquals("tujiko noriko", cursor.getString(1));
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
cursor = resolver.query(uri, PROJECTION, AstridTask.IMPORTANCE + "<" +
|
||||||
|
AstridTask.IMPORTANCE_MUST_DO, null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.moveToFirst();
|
||||||
|
assertEquals("miho asahi", cursor.getString(1));
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
cursor = resolver.query(uri, PROJECTION, AstridTask.IMPORTANCE + "=" +
|
||||||
|
AstridTask.IMPORTANCE_DO_OR_DIE, null, null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test selecting data with metadata */
|
||||||
|
public void testSelectionWithMetadata() {
|
||||||
|
ContentResolver resolver = getContext().getContentResolver();
|
||||||
|
Uri uri = AstridContentProvider.allItemsUri();
|
||||||
|
|
||||||
|
// insert some tasks
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(AstridTask.TITLE, "turkoglu");
|
||||||
|
values.put("suave-factor", "10");
|
||||||
|
resolver.insert(uri, values);
|
||||||
|
|
||||||
|
values.clear();
|
||||||
|
values.put(AstridTask.TITLE, "ichiro");
|
||||||
|
values.put("suave-factor", "30");
|
||||||
|
resolver.insert(uri, values);
|
||||||
|
|
||||||
|
values.clear();
|
||||||
|
values.put(AstridTask.TITLE, "oprah");
|
||||||
|
values.put("suave-factor", "-10");
|
||||||
|
resolver.insert(uri, values);
|
||||||
|
|
||||||
|
values.clear();
|
||||||
|
values.put(AstridTask.TITLE, "cruise");
|
||||||
|
values.put("suave-factor", "-10");
|
||||||
|
resolver.insert(uri, values);
|
||||||
|
|
||||||
|
values.clear();
|
||||||
|
values.put(AstridTask.TITLE, "oprah");
|
||||||
|
resolver.insert(uri, values);
|
||||||
|
|
||||||
|
String[] projection = new String[] {
|
||||||
|
AstridTask.ID,
|
||||||
|
AstridTask.TITLE,
|
||||||
|
"suave-factor"
|
||||||
|
};
|
||||||
|
|
||||||
|
// fetch all tasks with various selection parameters
|
||||||
|
Cursor cursor = resolver.query(uri, projection, "1", null, null);
|
||||||
|
assertEquals(3, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
cursor = resolver.query(uri, projection, "'suave-factor' = 30", null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.moveToFirst();
|
||||||
|
assertEquals("ichiro", cursor.getString(1));
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
cursor = resolver.query(uri, projection, "'suave-factor' < 5", null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.moveToFirst();
|
||||||
|
assertEquals("cruise", cursor.getString(1));
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
cursor = resolver.query(uri, projection, "'suave-factor' ISNULL", null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.moveToFirst();
|
||||||
|
assertEquals("oprah", cursor.getString(1));
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test updating */
|
||||||
|
public void testUpdating() {
|
||||||
|
ContentResolver resolver = getContext().getContentResolver();
|
||||||
|
Uri allItemsUri = AstridContentProvider.allItemsUri();
|
||||||
|
|
||||||
|
// insert some tasks
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(AstridTask.TITLE, "carlos silva");
|
||||||
|
values.put("suckitude", "acute");
|
||||||
|
Uri carlosUri = resolver.insert(allItemsUri, values);
|
||||||
|
|
||||||
|
values.clear();
|
||||||
|
values.put(AstridTask.TITLE, "felix hernandez");
|
||||||
|
values.put(AstridTask.URGENCY, AstridTask.URGENCY_WITHIN_A_YEAR);
|
||||||
|
resolver.insert(allItemsUri, values);
|
||||||
|
|
||||||
|
String[] projection = new String[] {
|
||||||
|
AstridTask.ID,
|
||||||
|
AstridTask.TITLE,
|
||||||
|
"suckitude"
|
||||||
|
};
|
||||||
|
|
||||||
|
// test updating with single item URI
|
||||||
|
Cursor cursor = resolver.query(allItemsUri, projection, "'suckitude' = 'carlos who?'", null, null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
values.clear();
|
||||||
|
values.put("suckitude", "carlos who?");
|
||||||
|
assertEquals(1, resolver.update(carlosUri, values, null, null));
|
||||||
|
|
||||||
|
cursor = resolver.query(allItemsUri, projection, "'suckitude' = 'carlos who?'", null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// test updating with all items uri
|
||||||
|
cursor = resolver.query(allItemsUri, PROJECTION, AstridTask.URGENCY + " = " +
|
||||||
|
AstridTask.URGENCY_NONE, null, null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
values.clear();
|
||||||
|
values.put(AstridTask.URGENCY, AstridTask.URGENCY_NONE);
|
||||||
|
assertEquals(1, resolver.update(allItemsUri, values, AstridTask.URGENCY +
|
||||||
|
"=" + AstridTask.URGENCY_WITHIN_A_YEAR, null));
|
||||||
|
|
||||||
|
cursor = resolver.query(allItemsUri, PROJECTION, AstridTask.URGENCY + " = " +
|
||||||
|
AstridTask.URGENCY_NONE, null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// test updating with group by uri
|
||||||
|
try {
|
||||||
|
Uri groupByUri = AstridContentProvider.groupByUri(AstridTask.TITLE);
|
||||||
|
resolver.update(groupByUri, values, null, null);
|
||||||
|
fail("Able to update using groupby uri");
|
||||||
|
} catch (Exception e) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test deleting */
|
||||||
|
public void testDeleting() {
|
||||||
|
ContentResolver resolver = getContext().getContentResolver();
|
||||||
|
Uri allItemsUri = AstridContentProvider.allItemsUri();
|
||||||
|
|
||||||
|
// insert some tasks
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(AstridTask.TITLE, "modest mouse");
|
||||||
|
values.put(AstridTask.IMPORTANCE, AstridTask.IMPORTANCE_DO_OR_DIE);
|
||||||
|
Uri modestMouse = resolver.insert(allItemsUri, values);
|
||||||
|
|
||||||
|
values.clear();
|
||||||
|
values.put(AstridTask.TITLE, "death cab");
|
||||||
|
values.put(AstridTask.IMPORTANCE, AstridTask.IMPORTANCE_MUST_DO);
|
||||||
|
resolver.insert(allItemsUri, values);
|
||||||
|
|
||||||
|
values.clear();
|
||||||
|
values.put(AstridTask.TITLE, "murder city devils");
|
||||||
|
values.put(AstridTask.IMPORTANCE, AstridTask.IMPORTANCE_SHOULD_DO);
|
||||||
|
resolver.insert(allItemsUri, values);
|
||||||
|
|
||||||
|
// test deleting with single URI
|
||||||
|
Cursor cursor = resolver.query(allItemsUri, PROJECTION, AstridTask.TITLE +
|
||||||
|
" = 'modest mouse'", null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
assertEquals(1, resolver.delete(modestMouse, null, null));
|
||||||
|
|
||||||
|
cursor = resolver.query(allItemsUri, PROJECTION, AstridTask.TITLE +
|
||||||
|
" = 'modest mouse'", null, null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// test updating with all items uri
|
||||||
|
cursor = resolver.query(allItemsUri, PROJECTION, AstridTask.TITLE +
|
||||||
|
" = 'murder city devils'", null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
assertEquals(1, resolver.delete(allItemsUri, AstridTask.IMPORTANCE +
|
||||||
|
"<" + AstridTask.IMPORTANCE_MUST_DO, null));
|
||||||
|
|
||||||
|
cursor = resolver.query(allItemsUri, PROJECTION, AstridTask.TITLE +
|
||||||
|
" = 'murder city devils'", null, null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// test with group by uri
|
||||||
|
try {
|
||||||
|
Uri groupByUri = AstridContentProvider.groupByUri(AstridTask.TITLE);
|
||||||
|
resolver.delete(groupByUri, null, null);
|
||||||
|
fail("Able to delete using groupby uri");
|
||||||
|
} catch (Exception e) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test CRUD over SINGLE ITEM uri */
|
||||||
|
public void testSingleItemCrud() {
|
||||||
|
ContentResolver resolver = getContext().getContentResolver();
|
||||||
|
|
||||||
|
Uri uri = AstridContentProvider.allItemsUri();
|
||||||
|
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(AstridTask.TITLE, "mf doom?");
|
||||||
|
Uri firstUri = resolver.insert(uri, values);
|
||||||
|
|
||||||
|
values.put(AstridTask.TITLE, "gm grimm!");
|
||||||
|
Uri secondUri = resolver.insert(uri, values);
|
||||||
|
assertNotSame(firstUri, secondUri);
|
||||||
|
|
||||||
|
Cursor cursor = resolver.query(uri, PROJECTION, "1", null, null);
|
||||||
|
assertEquals(2, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
cursor = resolver.query(firstUri, PROJECTION, null, null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.moveToFirst();
|
||||||
|
assertEquals("mf doom?", cursor.getString(1));
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
values.put(AstridTask.TITLE, "danger mouse.");
|
||||||
|
resolver.update(firstUri, values, null, null);
|
||||||
|
cursor = resolver.query(firstUri, PROJECTION, null, null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.moveToFirst();
|
||||||
|
assertEquals("danger mouse.", cursor.getString(1));
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
assertEquals(1, resolver.delete(firstUri, null, null));
|
||||||
|
|
||||||
|
cursor = resolver.query(uri, PROJECTION, null, null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test GROUP BY uri */
|
||||||
|
public void testGroupByCrud() {
|
||||||
|
ContentResolver resolver = getContext().getContentResolver();
|
||||||
|
Uri uri = AstridContentProvider.allItemsUri();
|
||||||
|
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(AstridTask.TITLE, "catwoman");
|
||||||
|
resolver.insert(uri, values);
|
||||||
|
|
||||||
|
values.put(AstridTask.TITLE, "the joker");
|
||||||
|
resolver.insert(uri, values);
|
||||||
|
resolver.insert(uri, values);
|
||||||
|
resolver.insert(uri, values);
|
||||||
|
|
||||||
|
values.put(AstridTask.TITLE, "deep freeze");
|
||||||
|
resolver.insert(uri, values);
|
||||||
|
resolver.insert(uri, values);
|
||||||
|
|
||||||
|
Uri groupByUri = AstridContentProvider.groupByUri(AstridTask.TITLE);
|
||||||
|
Cursor cursor = resolver.query(groupByUri, PROJECTION, null, null, AstridTask.TITLE);
|
||||||
|
assertEquals(3, cursor.getCount());
|
||||||
|
cursor.moveToFirst();
|
||||||
|
assertEquals("catwoman", cursor.getString(1));
|
||||||
|
cursor.moveToNext();
|
||||||
|
assertEquals("deep freeze", cursor.getString(1));
|
||||||
|
cursor.moveToNext();
|
||||||
|
assertEquals("the joker", cursor.getString(1));
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// test "group-by" with metadata
|
||||||
|
values.put("age", 50);
|
||||||
|
values.put("size", "large");
|
||||||
|
resolver.insert(uri, values);
|
||||||
|
values.put("age", 40);
|
||||||
|
values.put("size", "large");
|
||||||
|
resolver.insert(uri, values);
|
||||||
|
|
||||||
|
values.put("age", 20);
|
||||||
|
values.put("size", "small");
|
||||||
|
resolver.insert(uri, values);
|
||||||
|
|
||||||
|
Uri groupByAgeUri = AstridContentProvider.groupByUri("size");
|
||||||
|
cursor = resolver.query(groupByUri, PROJECTION, null, null, AstridTask.TITLE);
|
||||||
|
assertEquals(3, cursor.getCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test updating and deleting with metadata */
|
||||||
|
public void testMetadataUpdateDelete() {
|
||||||
|
ContentResolver resolver = getContext().getContentResolver();
|
||||||
|
Uri allItemsUri = AstridContentProvider.allItemsUri();
|
||||||
|
|
||||||
|
// insert some tasks
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(AstridTask.TITLE, "chicago");
|
||||||
|
values.put("pizza", "delicious");
|
||||||
|
values.put("temperature", 20);
|
||||||
|
resolver.insert(allItemsUri, values);
|
||||||
|
|
||||||
|
values.clear();
|
||||||
|
values.put(AstridTask.TITLE, "san francisco");
|
||||||
|
values.put("pizza", "meh");
|
||||||
|
values.put("temperature", 60);
|
||||||
|
resolver.insert(allItemsUri, values);
|
||||||
|
|
||||||
|
values.clear();
|
||||||
|
values.put(AstridTask.TITLE, "new york");
|
||||||
|
values.put("pizza", "yum");
|
||||||
|
values.put("temperature", 30);
|
||||||
|
resolver.insert(allItemsUri, values);
|
||||||
|
|
||||||
|
// test updating with standard URI (shouldn't work)
|
||||||
|
values.clear();
|
||||||
|
values.put("pizza", "nonexistent, the city is underwater");
|
||||||
|
assertEquals(0, resolver.update(allItemsUri, values,
|
||||||
|
"'pizza'='yum'", null));
|
||||||
|
|
||||||
|
String[] projection = new String[] {
|
||||||
|
AstridTask.ID,
|
||||||
|
AstridTask.TITLE,
|
||||||
|
"pizza",
|
||||||
|
"temperature"
|
||||||
|
};
|
||||||
|
|
||||||
|
Cursor cursor = resolver.query(allItemsUri, projection, "'pizza' = 'yum'", null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// test updating with metadata uri
|
||||||
|
Uri pizzaUri = AstridContentProvider.allItemsWithMetadataUri(new String[] {"pizza"});
|
||||||
|
assertEquals(1, resolver.update(pizzaUri, values,
|
||||||
|
"'pizza'='yum'", null));
|
||||||
|
|
||||||
|
cursor = resolver.query(allItemsUri, projection, "'pizza' = 'yum'", null, null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// test deleting with metadata uri
|
||||||
|
Uri pizzaTempUri = AstridContentProvider.allItemsWithMetadataUri(new String[] {"pizza",
|
||||||
|
"temperature"});
|
||||||
|
|
||||||
|
cursor = resolver.query(allItemsUri, projection, AstridTask.TITLE + " = 'chicago'", null, null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
// SQLITE: the deliverer of BAD NEWS
|
||||||
|
assertEquals(0, resolver.delete(pizzaTempUri, "pizza='delicious' AND temperature > 50", null));
|
||||||
|
assertEquals(1, resolver.delete(pizzaTempUri, "pizza='delicious' AND temperature < 50", null));
|
||||||
|
|
||||||
|
cursor = resolver.query(allItemsUri, projection, AstridTask.TITLE + " = 'chicago'", null, null);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
package com.todoroo.astrid.service;
|
||||||
|
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
import com.timsu.astrid.R;
|
||||||
|
import com.todoroo.andlib.service.AbstractDependencyInjector;
|
||||||
|
import com.todoroo.andlib.service.Autowired;
|
||||||
|
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||||
|
import com.todoroo.andlib.utility.DialogUtilities;
|
||||||
|
|
||||||
|
public class AstridDependencyInjectorTests extends AndroidTestCase {
|
||||||
|
|
||||||
|
protected static class Helper {
|
||||||
|
public Object getObject() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
// in case some state from other unit tests overwrote injector
|
||||||
|
DependencyInjectionService.getInstance().setInjectors(new AbstractDependencyInjector[] {
|
||||||
|
new AstridDependencyInjector()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWithString() {
|
||||||
|
Helper helper = new Helper() {
|
||||||
|
@Autowired
|
||||||
|
public String applicationName;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getObject() {
|
||||||
|
return applicationName;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
DependencyInjectionService.getInstance().inject(helper);
|
||||||
|
assertTrue(((String)helper.getObject()).length() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWithInteger() {
|
||||||
|
|
||||||
|
Helper helper = new Helper() {
|
||||||
|
@Autowired
|
||||||
|
public Integer informationDialogTitleResource;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getObject() {
|
||||||
|
return informationDialogTitleResource;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
DependencyInjectionService.getInstance().inject(helper);
|
||||||
|
assertEquals(R.string.DLG_information_title, helper.getObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWithClass() {
|
||||||
|
|
||||||
|
Helper helper = new Helper() {
|
||||||
|
@Autowired
|
||||||
|
public DialogUtilities dialogUtilities;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getObject() {
|
||||||
|
return dialogUtilities;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
DependencyInjectionService.getInstance().inject(helper);
|
||||||
|
assertTrue(helper.getObject() instanceof DialogUtilities);
|
||||||
|
|
||||||
|
Helper helper2 = new Helper() {
|
||||||
|
@Autowired
|
||||||
|
public DialogUtilities dialogUtilities;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getObject() {
|
||||||
|
return dialogUtilities;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
DependencyInjectionService.getInstance().inject(helper2);
|
||||||
|
|
||||||
|
assertEquals(helper.getObject(), helper2.getObject());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,139 @@
|
|||||||
|
package com.todoroo.astrid.service;
|
||||||
|
import com.todoroo.andlib.service.Autowired;
|
||||||
|
import com.todoroo.andlib.test.data.TodorooCursor;
|
||||||
|
import com.todoroo.andlib.test.utility.DateUtilities;
|
||||||
|
import com.todoroo.astrid.api.Filter;
|
||||||
|
import com.todoroo.astrid.dao.Database;
|
||||||
|
import com.todoroo.astrid.dao.TaskDao;
|
||||||
|
import com.todoroo.astrid.model.Task;
|
||||||
|
import com.todoroo.astrid.test.DatabaseTestCase;
|
||||||
|
|
||||||
|
|
||||||
|
public class TaskServiceTests extends DatabaseTestCase {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
TaskService taskService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
TaskDao taskDao;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Since a lot of the service-layer methods call through to the dao,
|
||||||
|
* we don't need to do a lot of extensive testing here, just various
|
||||||
|
* boundary conditions.
|
||||||
|
*/
|
||||||
|
public void testTaskDaoExposedMethods() {
|
||||||
|
Task task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "normal");
|
||||||
|
assertTrue(taskService.save(task, false));
|
||||||
|
|
||||||
|
// empty fetch w/ filter
|
||||||
|
Filter filter = new Filter("bla", "bla", "WHERE 1", null);
|
||||||
|
TodorooCursor<Task> cursor =
|
||||||
|
taskService.fetchFiltered(TaskService.idProperties(), filter);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
filter.sqlQuery = "WHERE " + Task.TITLE + " = \"bob\"";
|
||||||
|
cursor = taskService.fetchFiltered(TaskService.idProperties(), filter);
|
||||||
|
assertEquals(0, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
Task fetched = taskService.fetchById(TaskService.idProperties(), task.getId());
|
||||||
|
assertNotNull(fetched);
|
||||||
|
fetched = taskService.fetchById(TaskService.idProperties(), task.getId() + 1);
|
||||||
|
assertNull(fetched);
|
||||||
|
|
||||||
|
taskService.setComplete(task, true);
|
||||||
|
assertTrue(task.isCompleted());
|
||||||
|
|
||||||
|
fetched = taskService.fetchById(Task.PROPERTIES, task.getId());
|
||||||
|
assertTrue(fetched.isCompleted());
|
||||||
|
taskService.setComplete(task, false);
|
||||||
|
fetched = taskService.fetchById(Task.PROPERTIES, task.getId());
|
||||||
|
assertFalse(fetched.isCompleted());
|
||||||
|
assertFalse(task.isCompleted());
|
||||||
|
|
||||||
|
long id = task.getId();
|
||||||
|
taskService.delete(id);
|
||||||
|
fetched = taskService.fetchById(Task.PROPERTIES, id);
|
||||||
|
assertNull(fetched);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test cleanup
|
||||||
|
*/
|
||||||
|
public void testCleanup() throws Exception {
|
||||||
|
TodorooCursor<Task> cursor;
|
||||||
|
|
||||||
|
// save task with a name
|
||||||
|
Task task1 = new Task();
|
||||||
|
task1.setValue(Task.TITLE, "normal");
|
||||||
|
assertTrue(taskService.save(task1, false));
|
||||||
|
|
||||||
|
// save task without a name
|
||||||
|
Task task2 = new Task();
|
||||||
|
task2.setValue(Task.TITLE, "");
|
||||||
|
task2.setValue(Task.HIDDEN_UNTIL, DateUtilities.now() + 10000);
|
||||||
|
assertTrue(taskService.save(task2, false));
|
||||||
|
|
||||||
|
// save task #2 without a name
|
||||||
|
Task task3 = new Task();
|
||||||
|
task3.setValue(Task.TITLE, "");
|
||||||
|
task3.setValue(Task.DUE_DATE, DateUtilities.now() + 10000);
|
||||||
|
assertTrue(taskService.save(task3, false));
|
||||||
|
|
||||||
|
cursor = taskDao.fetch(database, Task.PROPERTIES, null, null);
|
||||||
|
assertEquals(3, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
taskService.cleanup();
|
||||||
|
|
||||||
|
cursor = taskDao.fetch(database, Task.PROPERTIES, null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the sql invoked from a filter on new task creation
|
||||||
|
*/
|
||||||
|
public void testInvokeNewTaskSql() {
|
||||||
|
TodorooCursor<Task> cursor;
|
||||||
|
Filter filter = new Filter("bla", "bla", "WHERE 1", null);
|
||||||
|
|
||||||
|
Task task = new Task();
|
||||||
|
task.setValue(Task.TITLE, "evils");
|
||||||
|
assertTrue(taskService.save(task, false));
|
||||||
|
|
||||||
|
cursor = taskDao.fetch(database, Task.PROPERTIES, null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.moveToNext();
|
||||||
|
task = new Task(cursor, Task.PROPERTIES);
|
||||||
|
assertEquals("evils", task.getValue(Task.TITLE));
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
filter.sqlForNewTasks = String.format("UPDATE %s set %s = \"good\"",
|
||||||
|
Database.TASK_TABLE, Task.TITLE);
|
||||||
|
taskService.invokeSqlForNewTask(filter, task);
|
||||||
|
|
||||||
|
cursor = taskDao.fetch(database, Task.PROPERTIES, null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.moveToNext();
|
||||||
|
task = new Task(cursor, Task.PROPERTIES);
|
||||||
|
assertEquals("good", task.getValue(Task.TITLE));
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
filter.sqlForNewTasks = String.format("UPDATE %s set %s = \"yum\" WHERE %s = $ID",
|
||||||
|
Database.TASK_TABLE, Task.TITLE, Task.ID);
|
||||||
|
taskService.invokeSqlForNewTask(filter, task);
|
||||||
|
|
||||||
|
cursor = taskDao.fetch(database, Task.PROPERTIES, null, null);
|
||||||
|
assertEquals(1, cursor.getCount());
|
||||||
|
cursor.moveToNext();
|
||||||
|
task = new Task(cursor, Task.PROPERTIES);
|
||||||
|
assertEquals("yum", task.getValue(Task.TITLE));
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,96 @@
|
|||||||
|
package com.todoroo.astrid.test;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.pm.ActivityInfo;
|
||||||
|
import android.test.ActivityInstrumentationTestCase2;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
|
import com.todoroo.andlib.service.Autowired;
|
||||||
|
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||||
|
import com.todoroo.andlib.service.TestDependencyInjector;
|
||||||
|
import com.todoroo.astrid.dao.Database;
|
||||||
|
import com.todoroo.astrid.service.AstridDependencyInjector;
|
||||||
|
import com.todoroo.astrid.test.DatabaseTestCase.AstridTestDatabase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ActivityTestCase is a helper for testing Todoroo Activities.
|
||||||
|
* <p>
|
||||||
|
* It initializes a test database before the activity is created.
|
||||||
|
*
|
||||||
|
* @author Tim Su <tim@todoroo.com>
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
*/
|
||||||
|
public class AstridActivityTestCase<T extends Activity> extends ActivityInstrumentationTestCase2<T> {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public Database database;
|
||||||
|
|
||||||
|
static {
|
||||||
|
AstridDependencyInjector.initialize();
|
||||||
|
TestDependencyInjector.initialize("db").addInjectable("database",
|
||||||
|
new AstridTestDatabase());
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstridActivityTestCase(String packageName, Class<T> activityClass) {
|
||||||
|
super(packageName, activityClass);
|
||||||
|
DependencyInjectionService.getInstance().inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
// create new test database
|
||||||
|
AstridTestDatabase.dropTables(getInstrumentation().getTargetContext());
|
||||||
|
database.openForWriting();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tearDown() throws Exception {
|
||||||
|
super.tearDown();
|
||||||
|
|
||||||
|
if(database != null)
|
||||||
|
database.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call to just tear this activity down
|
||||||
|
*/
|
||||||
|
protected void tearActivityDown() throws Exception {
|
||||||
|
super.tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call to just set this activity up
|
||||||
|
*/
|
||||||
|
protected void setActivityUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Calls various lifecycle methods, makes sure all of them work */
|
||||||
|
public void testLifecycle() throws Exception {
|
||||||
|
T activity = getActivity();
|
||||||
|
getInstrumentation().callActivityOnPause(activity);
|
||||||
|
Thread.sleep(500);
|
||||||
|
getInstrumentation().callActivityOnResume(activity);
|
||||||
|
|
||||||
|
getInstrumentation().sendPointerSync(MotionEvent.obtain(500, 500, MotionEvent.ACTION_DOWN, 10, 30, 0));
|
||||||
|
|
||||||
|
getInstrumentation().callActivityOnPause(activity);
|
||||||
|
getInstrumentation().callActivityOnStop(activity);
|
||||||
|
Thread.sleep(500);
|
||||||
|
getInstrumentation().callActivityOnRestart(activity);
|
||||||
|
getInstrumentation().callActivityOnStart(activity);
|
||||||
|
getInstrumentation().callActivityOnResume(activity);
|
||||||
|
|
||||||
|
getInstrumentation().sendPointerSync(MotionEvent.obtain(500, 500, MotionEvent.ACTION_DOWN, 10, 30, 0));
|
||||||
|
|
||||||
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||||
|
Thread.sleep(500);
|
||||||
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||||
|
Thread.sleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
package com.todoroo.astrid.test;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
|
||||||
|
import com.todoroo.andlib.service.Autowired;
|
||||||
|
import com.todoroo.andlib.service.TestDependencyInjector;
|
||||||
|
import com.todoroo.andlib.test.TodorooTestCase;
|
||||||
|
import com.todoroo.astrid.dao.Database;
|
||||||
|
import com.todoroo.astrid.dao.Database.AstridSQLiteOpenHelper;
|
||||||
|
import com.todoroo.astrid.service.AstridDependencyInjector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test case that automatically sets up and tears down a test database
|
||||||
|
*
|
||||||
|
* @author Tim Su <tim@todoroo.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DatabaseTestCase extends TodorooTestCase {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public Database database;
|
||||||
|
|
||||||
|
static {
|
||||||
|
AstridDependencyInjector.initialize();
|
||||||
|
TestDependencyInjector.initialize("db").addInjectable("database",
|
||||||
|
new AstridTestDatabase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
// create new test database
|
||||||
|
AstridTestDatabase.dropTables(getContext());
|
||||||
|
database.openForWriting();
|
||||||
|
|
||||||
|
super.setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tearDown() throws Exception {
|
||||||
|
database.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AstridTestDatabase extends Database {
|
||||||
|
|
||||||
|
private static final String NAME = "todoroo-test";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void openForWriting() {
|
||||||
|
if(helper == null)
|
||||||
|
helper = new AstridSQLiteOpenHelper(context, NAME, null, VERSION);
|
||||||
|
super.openForWriting();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void openForReading() {
|
||||||
|
if(helper == null)
|
||||||
|
helper = new AstridSQLiteOpenHelper(context, NAME, null, VERSION);
|
||||||
|
super.openForWriting();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void dropTables(Context context) {
|
||||||
|
// force drop database
|
||||||
|
SQLiteOpenHelper helper = new AstridSQLiteOpenHelper(context, NAME, null, VERSION);
|
||||||
|
helper.onUpgrade(helper.getWritableDatabase(),
|
||||||
|
0, VERSION);
|
||||||
|
helper.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package com.todoroo.astrid.upgrade;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.test.DatabaseTestCase;
|
||||||
|
|
||||||
|
public class Astrid2To3UpgradeTests extends DatabaseTestCase {
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue