Refactored application and server-side to use GCM instead of C2DM; removed and or deprecated C2DM code; removed unused code

This commit is contained in:
felipeal
2012-08-01 23:37:36 +00:00
parent 346348263d
commit 79adf622d5
23 changed files with 603 additions and 637 deletions

View File

@@ -5,5 +5,6 @@
<classpathentry kind="src" path="c2dm"/> <classpathentry kind="src" path="c2dm"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/> <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry kind="lib" path="libs/gcm.jar"/>
<classpathentry kind="output" path="bin/classes"/> <classpathentry kind="output" path="bin/classes"/>
</classpath> </classpath>

View File

@@ -0,0 +1,327 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field=1585
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field.count_dependent=1585|-1|1585
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable=1585
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable.count_dependent=1585|-1|1585
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method=1585
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method.count_dependent=1585|-1|1585
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package=1585
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package.count_dependent=1585|-1|1585
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter=1040
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter.count_dependent=1040|-1|1040
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type=1585
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type.count_dependent=1585|-1|1585
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression.count_dependent=16|-1|16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation.count_dependent=16|-1|16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant.count_dependent=16|-1|16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call.count_dependent=16|-1|16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation.count_dependent=16|-1|16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression.count_dependent=16|-1|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_binary_expression.count_dependent=16|-1|16
org.eclipse.jdt.core.formatter.alignment_for_cascading_method_invocation_with_arguments=16
org.eclipse.jdt.core.formatter.alignment_for_cascading_method_invocation_with_arguments.count_dependent=16|-1|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_enum_constants.count_dependent=0|-1|0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer.count_dependent=16|-1|16
org.eclipse.jdt.core.formatter.alignment_for_field_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_for_statement=16
org.eclipse.jdt.core.formatter.alignment_for_generic_type_arguments=16
org.eclipse.jdt.core.formatter.alignment_for_generic_type_arguments.count_dependent=16|-1|16
org.eclipse.jdt.core.formatter.alignment_for_local_variable_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields.count_dependent=16|-1|16
org.eclipse.jdt.core.formatter.alignment_for_new_anonymous_class=0
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration.count_dependent=16|-1|16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration.count_dependent=16|-1|16
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation.count_dependent=16|-1|16
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_enum_declaration.count_dependent=16|-1|16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration.count_dependent=16|-1|16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration.count_dependent=16|-1|16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration.count_dependent=16|-1|16
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=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.comment.new_lines_at_block_boundaries=true
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
org.eclipse.jdt.core.formatter.comment_new_line_at_start_of_html_paragraph=true
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.disabling_tag=@formatter\:off
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
org.eclipse.jdt.core.formatter.force_if_else_statement_brace=false
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
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_field=insert
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_method=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=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_annotation_on_type=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_label=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_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_comment_prefix=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_try=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_semicolon_in_try_resources=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_try=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_try=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_semicolon_in_try_resources=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_on_off_tags=false
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
org.eclipse.jdt.core.formatter.wrap_comment_inline_tags=false
org.eclipse.jdt.core.formatter.wrap_non_simple_local_variable_annotation=true
org.eclipse.jdt.core.formatter.wrap_non_simple_member_annotation=true
org.eclipse.jdt.core.formatter.wrap_non_simple_package_annotation=true
org.eclipse.jdt.core.formatter.wrap_non_simple_parameter_annotation=false
org.eclipse.jdt.core.formatter.wrap_non_simple_type_annotation=true
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
org.eclipse.jdt.core.formatter.wrap_prefer_two_fragments=false

View File

@@ -0,0 +1,3 @@
eclipse.preferences.version=1
formatter_profile=_my-Android
formatter_settings_version=12

View File

@@ -50,25 +50,30 @@
</intent-filter> </intent-filter>
</activity> </activity>
--> -->
<!-- In order to use the c2dm library, an
application must declare a class with the name C2DMReceiver, in its
own package, extending com.google.android.c2dm.C2DMBaseReceiver
It must also include this section in the manifest, replacing <!--
"com.google.android.apps.chrometophone" with its package name. --> Application-specific subclass of GCMBaseIntentService that will
<service android:name=".C2DMReceiver" /> handle received messages.
<!-- Only google service can send data messages for the app. If permission is not set - By default, it must be named .GCMIntentService, unless the
any other app can generate it --> application uses a custom BroadcastReceiver that redefines its name.
<receiver android:name="com.google.android.c2dm.C2DMBroadcastReceiver" -->
android:permission="com.google.android.c2dm.permission.SEND"> <service android:name=".GCMIntentService" />
<!-- Receive the actual message -->
<!--
BroadcastReceiver that will receive intents from GCM
services and handle them to the custom IntentService.
The com.google.android.c2dm.permission.SEND permission is necessary
so only GCM services can send data messages for the app.
-->
<receiver
android:name="com.google.android.gcm.GCMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter> <intent-filter>
<!-- Receives the actual messages. -->
<action android:name="com.google.android.c2dm.intent.RECEIVE" /> <action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.google.android.apps.chrometophone" /> <!-- Receives the registration id. -->
</intent-filter>
<!-- Receive the registration id -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" /> <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.google.android.apps.chrometophone" /> <category android:name="com.google.android.apps.chrometophone" />
</intent-filter> </intent-filter>

View File

@@ -1,195 +0,0 @@
/*
* Copyright 2010 Google Inc.
*
* 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.google.android.c2dm;
import java.io.IOException;
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.util.Log;
/**
* Base class for C2D message receiver. Includes constants for the
* strings used in the protocol.
*/
public abstract class C2DMBaseReceiver extends IntentService {
private static final String C2DM_RETRY = "com.google.android.c2dm.intent.RETRY";
public static final String REGISTRATION_CALLBACK_INTENT = "com.google.android.c2dm.intent.REGISTRATION";
private static final String C2DM_INTENT = "com.google.android.c2dm.intent.RECEIVE";
// Logging tag
private static final String TAG = "C2DM";
// Extras in the registration callback intents.
public static final String EXTRA_UNREGISTERED = "unregistered";
public static final String EXTRA_ERROR = "error";
public static final String EXTRA_REGISTRATION_ID = "registration_id";
public static final String ERR_SERVICE_NOT_AVAILABLE = "SERVICE_NOT_AVAILABLE";
public static final String ERR_ACCOUNT_MISSING = "ACCOUNT_MISSING";
public static final String ERR_AUTHENTICATION_FAILED = "AUTHENTICATION_FAILED";
public static final String ERR_TOO_MANY_REGISTRATIONS = "TOO_MANY_REGISTRATIONS";
public static final String ERR_INVALID_PARAMETERS = "INVALID_PARAMETERS";
public static final String ERR_INVALID_SENDER = "INVALID_SENDER";
public static final String ERR_PHONE_REGISTRATION_ERROR = "PHONE_REGISTRATION_ERROR";
// wakelock
private static final String WAKELOCK_KEY = "C2DM_LIB";
private static PowerManager.WakeLock mWakeLock;
private final String senderId;
/**
* The C2DMReceiver class must create a no-arg constructor and pass the
* sender id to be used for registration.
*/
public C2DMBaseReceiver(String senderId) {
// senderId is used as base name for threads, etc.
super(senderId);
this.senderId = senderId;
}
/**
* Called when a cloud message has been received.
*/
protected abstract void onMessage(Context context, Intent intent);
/**
* Called on registration error. Override to provide better
* error messages.
*
* This is called in the context of a Service - no dialog or UI.
*/
public abstract void onError(Context context, String errorId);
/**
* Called when a registration token has been received.
*/
public void onRegistered(Context context, String registrationId) throws IOException {
// registrationId will also be saved
}
/**
* Called when the device has been unregistered.
*/
public void onUnregistered(Context context) {
}
@Override
public final void onHandleIntent(Intent intent) {
try {
Context context = getApplicationContext();
if (intent.getAction().equals(REGISTRATION_CALLBACK_INTENT)) {
handleRegistration(context, intent);
} else if (intent.getAction().equals(C2DM_INTENT)) {
onMessage(context, intent);
} else if (intent.getAction().equals(C2DM_RETRY)) {
C2DMessaging.register(context, senderId);
}
} finally {
// Release the power lock, so phone can get back to sleep.
// The lock is reference counted by default, so multiple
// messages are ok.
// If the onMessage() needs to spawn a thread or do something else,
// it should use it's own lock.
mWakeLock.release();
}
}
/**
* Called from the broadcast receiver.
* Will process the received intent, call handleMessage(), registered(), etc.
* in background threads, with a wake lock, while keeping the service
* alive.
*/
static void runIntentInService(Context context, Intent intent) {
if (mWakeLock == null) {
// This is called from BroadcastReceiver, there is no init.
PowerManager pm =
(PowerManager) context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
WAKELOCK_KEY);
}
mWakeLock.acquire();
// Use a naming convention, similar with how permissions and intents are
// used. Alternatives are introspection or an ugly use of statics.
String receiver = context.getPackageName() + ".C2DMReceiver";
intent.setClassName(context, receiver);
context.startService(intent);
}
private void handleRegistration(final Context context, Intent intent) {
final String registrationId = intent.getStringExtra(EXTRA_REGISTRATION_ID);
String error = intent.getStringExtra(EXTRA_ERROR);
String removed = intent.getStringExtra(EXTRA_UNREGISTERED);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "dmControl: registrationId = " + registrationId +
", error = " + error + ", removed = " + removed);
}
if (removed != null) {
// Remember we are unregistered
C2DMessaging.clearRegistrationId(context);
onUnregistered(context);
return;
} else if (error != null) {
// we are not registered, can try again
C2DMessaging.clearRegistrationId(context);
// Registration failed
Log.e(TAG, "Registration error " + error);
onError(context, error);
if ("SERVICE_NOT_AVAILABLE".equals(error)) {
long backoffTimeMs = C2DMessaging.getBackoff(context);
Log.d(TAG, "Scheduling registration retry, backoff = " + backoffTimeMs);
Intent retryIntent = new Intent(C2DM_RETRY);
PendingIntent retryPIntent = PendingIntent.getBroadcast(context,
0 /*requestCode*/, retryIntent, 0 /*flags*/);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.ELAPSED_REALTIME,
backoffTimeMs, retryPIntent);
// Next retry should wait longer.
backoffTimeMs *= 2;
C2DMessaging.setBackoff(context, backoffTimeMs);
}
} else {
try {
onRegistered(context, registrationId);
C2DMessaging.setRegistrationId(context, registrationId);
} catch (IOException ex) {
Log.e(TAG, "Registration error " + ex.getMessage());
}
}
}
}

View File

@@ -1,25 +0,0 @@
/*
*/
package com.google.android.c2dm;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/**
* Helper class to handle BroadcastReciver behavior.
* - can only run for a limited amount of time - it must start a real service
* for longer activity
* - must get the power lock, must make sure it's released when all done.
*
*/
public class C2DMBroadcastReceiver extends BroadcastReceiver {
@Override
public final void onReceive(Context context, Intent intent) {
// To keep things in one place.
C2DMBaseReceiver.runIntentInService(context, intent);
setResult(Activity.RESULT_OK, null /* data */, null /* extra */);
}
}

View File

@@ -1,131 +0,0 @@
/*
* Copyright 2010 Google Inc.
*
* 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.google.android.c2dm;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
/**
* Utilities for device registration.
*
* Will keep track of the registration token in a private preference.
*/
public class C2DMessaging {
public static final String EXTRA_SENDER = "sender";
public static final String EXTRA_APPLICATION_PENDING_INTENT = "app";
public static final String REQUEST_UNREGISTRATION_INTENT = "com.google.android.c2dm.intent.UNREGISTER";
public static final String REQUEST_REGISTRATION_INTENT = "com.google.android.c2dm.intent.REGISTER";
public static final String LAST_REGISTRATION_CHANGE = "last_registration_change";
public static final String BACKOFF = "backoff";
public static final String GSF_PACKAGE = "com.google.android.gsf";
// package
static final String PREFERENCE = "com.google.android.c2dm";
private static final long DEFAULT_BACKOFF = 30000;
/**
* Initiate c2d messaging registration for the current application
*/
public static void register(Context context,
String senderId) {
Intent registrationIntent = new Intent(REQUEST_REGISTRATION_INTENT);
registrationIntent.setPackage(GSF_PACKAGE);
registrationIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT,
PendingIntent.getBroadcast(context, 0, new Intent(), 0));
registrationIntent.putExtra(EXTRA_SENDER, senderId);
context.startService(registrationIntent);
// TODO: if intent not found, notification on need to have GSF
}
/**
* Unregister the application. New messages will be blocked by server.
*/
public static void unregister(Context context) {
Intent regIntent = new Intent(REQUEST_UNREGISTRATION_INTENT);
regIntent.setPackage(GSF_PACKAGE);
regIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT, PendingIntent.getBroadcast(context,
0, new Intent(), 0));
context.startService(regIntent);
}
/**
* Return the current registration id.
*
* If result is empty, the registration has failed.
*
* @return registration id, or empty string if the registration is not complete.
*/
public static String getRegistrationId(Context context) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
String registrationId = prefs.getString("dm_registration", "");
return registrationId;
}
public static long getLastRegistrationChange(Context context) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
return prefs.getLong(LAST_REGISTRATION_CHANGE, 0);
}
static long getBackoff(Context context) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
return prefs.getLong(BACKOFF, DEFAULT_BACKOFF);
}
static void setBackoff(Context context, long backoff) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putLong(BACKOFF, backoff);
editor.commit();
}
// package
static void clearRegistrationId(Context context) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putString("dm_registration", "");
editor.putLong(LAST_REGISTRATION_CHANGE, System.currentTimeMillis());
editor.commit();
}
// package
static void setRegistrationId(Context context, String registrationId) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFERENCE,
Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putString("dm_registration", registrationId);
editor.commit();
}
}

View File

@@ -29,6 +29,8 @@ import android.content.res.Configuration;
import android.provider.Settings.Secure; import android.provider.Settings.Secure;
import android.util.Log; import android.util.Log;
import com.google.android.gcm.GCMRegistrar;
/** /**
* Register/unregister with the Chrome to Phone App Engine server. * Register/unregister with the Chrome to Phone App Engine server.
*/ */
@@ -40,7 +42,7 @@ public class DeviceRegistrar {
public static final int ERROR_STATUS = 4; public static final int ERROR_STATUS = 4;
private static final String TAG = "DeviceRegistrar"; private static final String TAG = "DeviceRegistrar";
static final String SENDER_ID = "stp.chrome@gmail.com"; static final String SENDER_ID = "206147423037";
private static final String REGISTER_PATH = "/register"; private static final String REGISTER_PATH = "/register";
private static final String UNREGISTER_PATH = "/unregister"; private static final String UNREGISTER_PATH = "/unregister";
@@ -52,12 +54,9 @@ public class DeviceRegistrar {
public void run() { public void run() {
Intent updateUIIntent = new Intent("com.google.ctp.UPDATE_UI"); Intent updateUIIntent = new Intent("com.google.ctp.UPDATE_UI");
try { try {
HttpResponse res = makeRequest(context, deviceRegistrationID, REGISTER_PATH); HttpResponse res = makeRequest(context, deviceRegistrationID, REGISTER_PATH, "gcm");
if (res.getStatusLine().getStatusCode() == 200) { if (res.getStatusLine().getStatusCode() == 200) {
SharedPreferences settings = Prefs.get(context); GCMRegistrar.setRegisteredOnServer(context, true);
SharedPreferences.Editor editor = settings.edit();
editor.putString("deviceRegistrationID", deviceRegistrationID);
editor.commit();
updateUIIntent.putExtra(STATUS_EXTRA, REGISTERED_STATUS); updateUIIntent.putExtra(STATUS_EXTRA, REGISTERED_STATUS);
} else if (res.getStatusLine().getStatusCode() == 400) { } else if (res.getStatusLine().getStatusCode() == 400) {
updateUIIntent.putExtra(STATUS_EXTRA, AUTH_ERROR_STATUS); updateUIIntent.putExtra(STATUS_EXTRA, AUTH_ERROR_STATUS);
@@ -82,24 +81,32 @@ public class DeviceRegistrar {
} }
public static void unregisterWithServer(final Context context, public static void unregisterWithServer(final Context context,
final String deviceRegistrationID) { final String deviceRegistrationID, final String deviceType) {
new Thread(new Runnable() { new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
Intent updateUIIntent = new Intent("com.google.ctp.UPDATE_UI"); Intent updateUIIntent = new Intent("com.google.ctp.UPDATE_UI");
try { try {
HttpResponse res = makeRequest(context, deviceRegistrationID, UNREGISTER_PATH); HttpResponse res = makeRequest(context, deviceRegistrationID, UNREGISTER_PATH, deviceType);
if (res.getStatusLine().getStatusCode() != 200) { if (res.getStatusLine().getStatusCode() != 200) {
Log.w(TAG, "Unregistration error " + Log.w(TAG, "Unregistration error " +
String.valueOf(res.getStatusLine().getStatusCode())); String.valueOf(res.getStatusLine().getStatusCode()));
} else {
GCMRegistrar.setRegisteredOnServer(context, false);
} }
} catch (Exception e) { } catch (Exception e) {
Log.w(TAG, "Unregistration error " + e.getMessage()); Log.w(TAG, "Unregistration error " + e.getMessage());
} finally { } finally {
SharedPreferences settings = Prefs.get(context); SharedPreferences settings = Prefs.get(context);
SharedPreferences.Editor editor = settings.edit(); SharedPreferences.Editor editor = settings.edit();
editor.remove("deviceRegistrationID"); if (deviceType.equals("gcm")) {
editor.remove("accountName"); editor.remove("accountName");
} else {
// this is an update from C2DM to GCM - keep the account,
// but remove the old regId (the new one will be stored
// on GCM's library preferences)
editor.remove("deviceRegistrationID");
}
editor.commit(); editor.commit();
updateUIIntent.putExtra(STATUS_EXTRA, UNREGISTERED_STATUS); updateUIIntent.putExtra(STATUS_EXTRA, UNREGISTERED_STATUS);
} }
@@ -111,9 +118,8 @@ public class DeviceRegistrar {
} }
private static HttpResponse makeRequest(Context context, String deviceRegistrationID, private static HttpResponse makeRequest(Context context, String deviceRegistrationID,
String urlPath) throws Exception { String urlPath, String deviceType) throws Exception {
SharedPreferences settings = Prefs.get(context); String accountName = getAccountName(context);
String accountName = settings.getString("accountName", null);
List<NameValuePair> params = new ArrayList<NameValuePair>(); List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("devregid", deviceRegistrationID)); params.add(new BasicNameValuePair("devregid", deviceRegistrationID));
@@ -126,10 +132,18 @@ public class DeviceRegistrar {
// TODO: Allow device name to be configured // TODO: Allow device name to be configured
params.add(new BasicNameValuePair("deviceName", isTablet(context) ? "Tablet" : "Phone")); params.add(new BasicNameValuePair("deviceName", isTablet(context) ? "Tablet" : "Phone"));
params.add(new BasicNameValuePair("deviceType", deviceType));
AppEngineClient client = new AppEngineClient(context, accountName); AppEngineClient client = new AppEngineClient(context, accountName);
return client.makeRequest(urlPath, params); return client.makeRequest(urlPath, params);
} }
static String getAccountName(Context context) {
SharedPreferences settings = Prefs.get(context);
String accountName = settings.getString("accountName", null);
return accountName;
}
static boolean isTablet (Context context) { static boolean isTablet (Context context) {
// TODO: This hacky stuff goes away when we allow users to target devices // TODO: This hacky stuff goes away when we allow users to target devices
int xlargeBit = 4; // Configuration.SCREENLAYOUT_SIZE_XLARGE; // upgrade to HC SDK to get this int xlargeBit = 4; // Configuration.SCREENLAYOUT_SIZE_XLARGE; // upgrade to HC SDK to get this

View File

@@ -26,10 +26,11 @@ import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import com.google.android.c2dm.C2DMBaseReceiver; import com.google.android.gcm.GCMBaseIntentService;
public class C2DMReceiver extends C2DMBaseReceiver { public class GCMIntentService extends GCMBaseIntentService {
public C2DMReceiver() {
public GCMIntentService() {
super(DeviceRegistrar.SENDER_ID); super(DeviceRegistrar.SENDER_ID);
} }
@@ -39,10 +40,8 @@ public class C2DMReceiver extends C2DMBaseReceiver {
} }
@Override @Override
public void onUnregistered(Context context) { public void onUnregistered(Context context, String registration) {
SharedPreferences prefs = Prefs.get(context); DeviceRegistrar.unregisterWithServer(context, registration, "gcm");
String deviceRegistrationID = prefs.getString("deviceRegistrationID", null);
DeviceRegistrar.unregisterWithServer(context, deviceRegistrationID);
} }
@Override @Override
@@ -98,4 +97,5 @@ public class C2DMReceiver extends C2DMBaseReceiver {
} }
} }
} }
} }

View File

@@ -1,7 +1,5 @@
package com.google.android.apps.chrometophone; package com.google.android.apps.chrometophone;
import java.util.Calendar;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
@@ -21,8 +19,12 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter; import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListView; import android.widget.ExpandableListView;
import android.widget.TextView;
import android.widget.ExpandableListView.OnChildClickListener; import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.TextView;
import com.google.android.gcm.GCMRegistrar;
import java.util.Calendar;
/** /**
* Activity that shows the history of links received. * Activity that shows the history of links received.
@@ -42,10 +44,32 @@ public class HistoryActivity extends Activity implements OnChildClickListener {
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// Run the setup first if necessary
SharedPreferences prefs = Prefs.get(this); SharedPreferences prefs = Prefs.get(this);
if (prefs.getString("deviceRegistrationID", null) == null) { String c2dmRegId = prefs.getString("deviceRegistrationID", null);
if (c2dmRegId != null) {
// this is an update from the version that uses C2DM: must
// unregister and register again using GCM
DeviceRegistrar.unregisterWithServer(this, c2dmRegId, "ac2dm");
GCMRegistrar.register(this, DeviceRegistrar.SENDER_ID);
} else {
// Run the setup first if necessary
String gcmRegId = GCMRegistrar.getRegistrationId(this);
if (gcmRegId.equals("")) {
String accountName = DeviceRegistrar.getAccountName(this);
if (accountName == null) {
// first time app is run
startActivity(new Intent(this, SetupActivity.class)); startActivity(new Intent(this, SetupActivity.class));
} else {
// app was converted from C2DM to GCM, but process didn't
// complete
GCMRegistrar.register(this, DeviceRegistrar.SENDER_ID);
}
} else {
// check if the regId must be sent to the server
if (!GCMRegistrar.isRegisteredOnServer(this)) {
DeviceRegistrar.registerWithServer(this, gcmRegId);
}
}
} }
setContentView(R.layout.history); setContentView(R.layout.history);
@@ -102,6 +126,7 @@ public class HistoryActivity extends Activity implements OnChildClickListener {
} }
} }
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
int childPosition, long id) { int childPosition, long id) {
mSelectedLink = mListAdapter.getLinkAtPosition(groupPosition, childPosition); mSelectedLink = mListAdapter.getLinkAtPosition(groupPosition, childPosition);
@@ -200,14 +225,17 @@ public class HistoryActivity extends Activity implements OnChildClickListener {
} }
} }
@Override
public Object getChild(int groupPosition, int childPosition) { public Object getChild(int groupPosition, int childPosition) {
return null; return null;
} }
@Override
public long getChildId(int groupPosition, int childPosition) { public long getChildId(int groupPosition, int childPosition) {
return moveCursorPosition(groupPosition, childPosition); return moveCursorPosition(groupPosition, childPosition);
} }
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) { View convertView, ViewGroup parent) {
HistoryItemView itemView; HistoryItemView itemView;
@@ -231,22 +259,27 @@ public class HistoryActivity extends Activity implements OnChildClickListener {
return itemView; return itemView;
} }
@Override
public int getChildrenCount(int groupPosition) { public int getChildrenCount(int groupPosition) {
return mChildCounts[groupPosition]; return mChildCounts[groupPosition];
} }
@Override
public Object getGroup(int groupPosition) { public Object getGroup(int groupPosition) {
return null; return null;
} }
@Override
public int getGroupCount() { public int getGroupCount() {
return DateBinSorter.NUM_BINS; return DateBinSorter.NUM_BINS;
} }
@Override
public long getGroupId(int groupPosition) { public long getGroupId(int groupPosition) {
return groupPosition; return groupPosition;
} }
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
ViewGroup parent) { ViewGroup parent) {
TextView item; TextView item;
@@ -261,10 +294,12 @@ public class HistoryActivity extends Activity implements OnChildClickListener {
return item; return item;
} }
@Override
public boolean hasStableIds() { public boolean hasStableIds() {
return true; return true;
} }
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) { public boolean isChildSelectable(int groupPosition, int childPosition) {
return true; return true;
} }

View File

@@ -15,8 +15,6 @@
*/ */
package com.google.android.apps.chrometophone; package com.google.android.apps.chrometophone;
import java.util.ArrayList;
import android.accounts.Account; import android.accounts.Account;
import android.accounts.AccountManager; import android.accounts.AccountManager;
import android.app.Activity; import android.app.Activity;
@@ -39,10 +37,12 @@ import android.widget.ListView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.RadioButton; import android.widget.RadioButton;
import android.widget.RadioGroup; import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.RadioGroup.OnCheckedChangeListener; import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.TextView;
import com.google.android.c2dm.C2DMessaging; import com.google.android.gcm.GCMRegistrar;
import java.util.ArrayList;
/** /**
* Setup activity - takes user through the setup. * Setup activity - takes user through the setup.
@@ -76,11 +76,11 @@ public class SetupActivity extends Activity {
super.onResume(); super.onResume();
if (mPendingAuth) { if (mPendingAuth) {
mPendingAuth = false; mPendingAuth = false;
String regId = C2DMessaging.getRegistrationId(this); String regId = GCMRegistrar.getRegistrationId(this);
if (regId != null && !"".equals(regId)) { if (!regId.equals("")) {
DeviceRegistrar.registerWithServer(this, regId); DeviceRegistrar.registerWithServer(this, regId);
} else { } else {
C2DMessaging.register(this, DeviceRegistrar.SENDER_ID); GCMRegistrar.register(this, DeviceRegistrar.SENDER_ID);
} }
} }
} }
@@ -155,6 +155,7 @@ public class SetupActivity extends Activity {
Button exitButton = (Button) findViewById(R.id.exit); Button exitButton = (Button) findViewById(R.id.exit);
exitButton.setOnClickListener(new OnClickListener() { exitButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) { public void onClick(View v) {
finish(); finish();
} }
@@ -162,6 +163,7 @@ public class SetupActivity extends Activity {
Button nextButton = (Button) findViewById(R.id.next); Button nextButton = (Button) findViewById(R.id.next);
nextButton.setOnClickListener(new OnClickListener() { nextButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) { public void onClick(View v) {
setScreenContent(R.layout.select_account); setScreenContent(R.layout.select_account);
} }
@@ -171,6 +173,7 @@ public class SetupActivity extends Activity {
private void setSelectAccountScreenContent() { private void setSelectAccountScreenContent() {
final Button backButton = (Button) findViewById(R.id.back); final Button backButton = (Button) findViewById(R.id.back);
backButton.setOnClickListener(new OnClickListener() { backButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) { public void onClick(View v) {
setScreenContent(R.layout.intro); setScreenContent(R.layout.intro);
} }
@@ -178,6 +181,7 @@ public class SetupActivity extends Activity {
final Button nextButton = (Button) findViewById(R.id.next); final Button nextButton = (Button) findViewById(R.id.next);
nextButton.setOnClickListener(new OnClickListener() { nextButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) { public void onClick(View v) {
ListView listView = (ListView) findViewById(R.id.select_account); ListView listView = (ListView) findViewById(R.id.select_account);
mAccountSelectedPosition = listView.getCheckedItemPosition(); mAccountSelectedPosition = listView.getCheckedItemPosition();
@@ -208,6 +212,7 @@ public class SetupActivity extends Activity {
private void setSelectLaunchModeScreenContent() { private void setSelectLaunchModeScreenContent() {
Button backButton = (Button) findViewById(R.id.back); Button backButton = (Button) findViewById(R.id.back);
backButton.setOnClickListener(new OnClickListener() { backButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) { public void onClick(View v) {
setScreenContent(R.layout.select_account); setScreenContent(R.layout.select_account);
} }
@@ -215,6 +220,7 @@ public class SetupActivity extends Activity {
Button nextButton = (Button) findViewById(R.id.next); Button nextButton = (Button) findViewById(R.id.next);
nextButton.setOnClickListener(new OnClickListener() { nextButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) { public void onClick(View v) {
storeLaunchModePreference(); storeLaunchModePreference();
setScreenContent(R.layout.setup_complete); setScreenContent(R.layout.setup_complete);
@@ -230,6 +236,7 @@ public class SetupActivity extends Activity {
Button backButton = (Button) findViewById(R.id.back); Button backButton = (Button) findViewById(R.id.back);
backButton.setOnClickListener(new OnClickListener() { backButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) { public void onClick(View v) {
setScreenContent(R.layout.select_launch_mode); setScreenContent(R.layout.select_launch_mode);
} }
@@ -238,6 +245,7 @@ public class SetupActivity extends Activity {
final Context context = this; final Context context = this;
Button finishButton = (Button) findViewById(R.id.finish); Button finishButton = (Button) findViewById(R.id.finish);
finishButton.setOnClickListener(new OnClickListener() { finishButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) { public void onClick(View v) {
SharedPreferences prefs = Prefs.get(context); SharedPreferences prefs = Prefs.get(context);
SharedPreferences.Editor editor = prefs.edit(); SharedPreferences.Editor editor = prefs.edit();
@@ -258,6 +266,7 @@ public class SetupActivity extends Activity {
RadioGroup launchMode = (RadioGroup) findViewById(R.id.launch_mode_radio); RadioGroup launchMode = (RadioGroup) findViewById(R.id.launch_mode_radio);
launchMode.setOnCheckedChangeListener(new OnCheckedChangeListener() { launchMode.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) { public void onCheckedChanged(RadioGroup group, int checkedId) {
storeLaunchModePreference(); storeLaunchModePreference();
} }); } });
@@ -265,6 +274,7 @@ public class SetupActivity extends Activity {
Button disconnectButton = (Button) findViewById(R.id.disconnect); Button disconnectButton = (Button) findViewById(R.id.disconnect);
disconnectButton.setOnClickListener(new OnClickListener() { disconnectButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) { public void onClick(View v) {
unregister(); unregister();
} }
@@ -302,7 +312,7 @@ public class SetupActivity extends Activity {
editor.putString("accountName", account); editor.putString("accountName", account);
editor.commit(); editor.commit();
C2DMessaging.register(this, DeviceRegistrar.SENDER_ID); GCMRegistrar.register(this, DeviceRegistrar.SENDER_ID);
} }
private void unregister() { private void unregister() {
@@ -314,7 +324,7 @@ public class SetupActivity extends Activity {
Button disconnectButton = (Button) findViewById(R.id.disconnect); Button disconnectButton = (Button) findViewById(R.id.disconnect);
disconnectButton.setEnabled(false); disconnectButton.setEnabled(false);
C2DMessaging.unregister(this); GCMRegistrar.unregister(this);
} }
private String[] getGoogleAccounts() { private String[] getGoogleAccounts() {

View File

@@ -4,5 +4,7 @@
<classpathentry kind="src" path="c2dm"/> <classpathentry kind="src" path="c2dm"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="com.google.appengine.eclipse.core.GAE_CONTAINER"/> <classpathentry kind="con" path="com.google.appengine.eclipse.core.GAE_CONTAINER"/>
<classpathentry kind="lib" path="war/WEB-INF/lib/gcm-server.jar"/>
<classpathentry kind="lib" path="war/WEB-INF/lib/json_simple-1.1.jar"/>
<classpathentry kind="output" path="war/WEB-INF/classes"/> <classpathentry kind="output" path="war/WEB-INF/classes"/>
</classpath> </classpath>

View File

@@ -35,11 +35,16 @@ import javax.jdo.PersistenceManagerFactory;
*/ */
public class C2DMConfigLoader { public class C2DMConfigLoader {
private static final String TOKEN_FILE = "/dataMessagingToken.txt"; private static final String TOKEN_FILE = "/dataMessagingToken.txt";
private static final String API_KEY_FILE = "/dataMessagingApiKey.txt";
private final PersistenceManagerFactory PMF; private final PersistenceManagerFactory PMF;
private static final Logger log = Logger.getLogger(C2DMConfigLoader.class.getName()); private static final Logger log = Logger.getLogger(C2DMConfigLoader.class.getName());
private static final int C2DM_TOKEN = 1;
private static final int GCM_API_KEY = 2;
String currentToken; String currentToken;
String c2dmUrl; String c2dmUrl;
String currentApiKey;
C2DMConfigLoader(PersistenceManagerFactory pmf) { C2DMConfigLoader(PersistenceManagerFactory pmf) {
this.PMF = pmf; this.PMF = pmf;
@@ -56,7 +61,7 @@ public class C2DMConfigLoader {
currentToken = token; currentToken = token;
PersistenceManager pm = PMF.getPersistenceManager(); PersistenceManager pm = PMF.getPersistenceManager();
try { try {
getDataMessagingConfig(pm).setAuthToken(token); getDataMessagingConfig(pm, TOKEN_FILE, C2DM_TOKEN).setAuthToken(token);
} finally { } finally {
pm.close(); pm.close();
} }
@@ -76,30 +81,37 @@ public class C2DMConfigLoader {
*/ */
public String getToken() { public String getToken() {
if (currentToken == null) { if (currentToken == null) {
currentToken = getDataMessagingConfig().getAuthToken(); currentToken = getDataMessagingConfig(TOKEN_FILE, C2DM_TOKEN).getAuthToken();
} }
return currentToken; return currentToken;
} }
public String getGcmApiKey() {
if (currentApiKey == null) {
currentApiKey = getDataMessagingConfig(API_KEY_FILE, GCM_API_KEY).getAuthToken();
}
return currentApiKey;
}
public String getC2DMUrl() { public String getC2DMUrl() {
if (c2dmUrl == null) { if (c2dmUrl == null) {
c2dmUrl = getDataMessagingConfig().getC2DMUrl(); c2dmUrl = getDataMessagingConfig(TOKEN_FILE, C2DM_TOKEN).getC2DMUrl();
} }
return c2dmUrl; return c2dmUrl;
} }
public C2DMConfig getDataMessagingConfig() { private C2DMConfig getDataMessagingConfig(String file, int index) {
PersistenceManager pm = PMF.getPersistenceManager(); PersistenceManager pm = PMF.getPersistenceManager();
try { try {
C2DMConfig dynamicConfig = getDataMessagingConfig(pm); C2DMConfig dynamicConfig = getDataMessagingConfig(pm, file, index);
return dynamicConfig; return dynamicConfig;
} finally { } finally {
pm.close(); pm.close();
} }
} }
public static C2DMConfig getDataMessagingConfig(PersistenceManager pm) { private C2DMConfig getDataMessagingConfig(PersistenceManager pm, String file, int index) {
Key key = KeyFactory.createKey(C2DMConfig.class.getSimpleName(), 1); Key key = KeyFactory.createKey(C2DMConfig.class.getSimpleName(), index);
C2DMConfig dmConfig = null; C2DMConfig dmConfig = null;
try { try {
dmConfig = pm.getObjectById(C2DMConfig.class, key); dmConfig = pm.getObjectById(C2DMConfig.class, key);
@@ -109,7 +121,7 @@ public class C2DMConfigLoader {
dmConfig.setKey(key); dmConfig.setKey(key);
// Must be in classpath, before sending. Do not checkin ! // Must be in classpath, before sending. Do not checkin !
try { try {
InputStream is = C2DMConfigLoader.class.getClassLoader().getResourceAsStream(TOKEN_FILE); InputStream is = C2DMConfigLoader.class.getClassLoader().getResourceAsStream(file);
String token; String token;
if (is != null) { if (is != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is)); BufferedReader reader = new BufferedReader(new InputStreamReader(is));

View File

@@ -1,87 +0,0 @@
/*
* Copyright 2010 Google Inc.
*
* 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.google.android.c2dm.server;
import java.io.IOException;
import java.util.Map;
import java.util.logging.Logger;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* A task that sends tickles to device clients. This will be invoked by
* AppEngine cron to retry failed requests.
*
* You must configure war/WEB-INF/queue.xml and the web.xml entries.
*/
@SuppressWarnings("serial")
public class C2DMRetryServlet extends HttpServlet {
private static final Logger log = Logger.getLogger(C2DMRetryServlet.class.getName());
public static final String URI = "/tasks/c2dm";
public static final String RETRY_COUNT = "X-AppEngine-TaskRetryCount";
static int MAX_RETRY = 3;
/**
* Only admin can make this request.
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
String registrationId = req.getParameter(C2DMessaging.PARAM_REGISTRATION_ID);
String retryCount = req.getHeader(RETRY_COUNT);
if (retryCount != null) {
int retryCnt = Integer.parseInt(retryCount);
if (retryCnt > MAX_RETRY) {
log.severe("Too many retries, drop message for :" + registrationId);
resp.setStatus(200);
return; // will not try again.
}
}
@SuppressWarnings("unchecked")
Map<String, String[]> params = req.getParameterMap();
String collapse = req.getParameter(C2DMessaging.PARAM_COLLAPSE_KEY);
boolean delayWhenIdle =
null != req.getParameter(C2DMessaging.PARAM_DELAY_WHILE_IDLE);
try {
// Send doesn't retry !!
// We use the queue exponential backoff for retries.
boolean sentOk = C2DMessaging.get(getServletContext())
.sendNoRetry(registrationId, collapse, params, delayWhenIdle);
log.info("Retry result " + sentOk + " " + registrationId);
if (sentOk) {
resp.setStatus(200);
resp.getOutputStream().write("OK".getBytes());
} else {
resp.setStatus(500); // retry this task
}
} catch (IOException ex) {
resp.setStatus(200);
resp.getOutputStream().write(("Non-retriable error:" +
ex.toString()).getBytes());
}
}
}

View File

@@ -16,11 +16,14 @@
package com.google.android.c2dm.server; package com.google.android.c2dm.server;
import com.google.android.gcm.server.Message;
import com.google.android.gcm.server.Result;
import com.google.android.gcm.server.Sender;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.net.URLEncoder; import java.net.URLEncoder;
@@ -34,13 +37,6 @@ import javax.jdo.PersistenceManagerFactory;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskHandle;
import com.google.appengine.api.taskqueue.TaskOptions;
/**
*/
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class C2DMessaging { public class C2DMessaging {
private static final String UPDATE_CLIENT_AUTH = "Update-Client-Auth"; private static final String UPDATE_CLIENT_AUTH = "Update-Client-Auth";
@@ -110,9 +106,14 @@ public class C2DMessaging {
pmfFactory); pmfFactory);
} }
return pmfFactory; return pmfFactory;
} }
/**
* This method is deprecated because C2DM has been replaced by GCM, and it
* provides a library with similar functionality.
*/
@Deprecated
public boolean sendNoRetry(String registrationId, public boolean sendNoRetry(String registrationId,
String collapse, String collapse,
Map<String, String[]> params, Map<String, String[]> params,
@@ -220,51 +221,11 @@ public class C2DMessaging {
} }
/** /**
* Helper method to send a message, with 2 parameters. * This method is deprecated because C2DM has been replaced by GCM, and it
* * provides a library with similar functionality.
* Permanent errors will result in IOException.
* Retriable errors will cause the message to be scheduled for retry.
*/ */
public void sendWithRetry(String token, String collapseKey, @Deprecated
String name1, String value1, String name2, String value2, public Object sendNoRetry(String token, String collapseKey,
String name3, String value3)
throws IOException {
Map<String, String[]> params = new HashMap<String, String[]>();
if (value1 != null) params.put("data." + name1, new String[] {value1});
if (value2 != null) params.put("data." + name2, new String[] {value2});
if (value3 != null) params.put("data." + name3, new String[] {value3});
boolean sentOk = sendNoRetry(token, collapseKey, params, true);
if (!sentOk) {
retry(token, collapseKey, params, true);
}
}
public boolean sendNoRetry(String token, String collapseKey,
String name1, String value1, String name2, String value2,
String name3, String value3) {
Map<String, String[]> params = new HashMap<String, String[]>();
if (value1 != null) params.put("data." + name1, new String[] {value1});
if (value2 != null) params.put("data." + name2, new String[] {value2});
if (value3 != null) params.put("data." + name3, new String[] {value3});
try {
return sendNoRetry(token, collapseKey, params, true);
} catch (IOException ex) {
return false;
}
}
private static final ThreadLocal<IOException> C2DM_EXCEPTION =
new ThreadLocal<IOException>();
public static IOException getC2dmException() {
return C2DM_EXCEPTION.get();
}
public boolean sendNoRetry(String token, String collapseKey,
String... nameValues) { String... nameValues) {
Map<String, String[]> params = new HashMap<String, String[]>(); Map<String, String[]> params = new HashMap<String, String[]>();
@@ -281,42 +242,25 @@ public class C2DMessaging {
} }
try { try {
C2DM_EXCEPTION.remove();
return sendNoRetry(token, collapseKey, params, true); return sendNoRetry(token, collapseKey, params, true);
} catch (IOException ex) { } catch (IOException ex) {
// save exception in a thread-local object so it can be cheked for return ex;
// unregistration later
C2DM_EXCEPTION.set(ex);
return false;
} }
} }
private void retry(String token, String collapseKey, public Result send(Message message, String regId) {
Map<String, String[]> params, boolean delayWhileIdle) { String key = serverConfig.getGcmApiKey();
Queue dmQueue = QueueFactory.getQueue("c2dm"); Sender sender = new Sender(key);
try { try {
TaskOptions url = // TODO: should use AppEngine's queue mechanism to retry, otherwise the
TaskOptions.Builder.withUrl(C2DMRetryServlet.URI) // request might time out
.param(C2DMessaging.PARAM_REGISTRATION_ID, token) Result result = sender.send(message, regId, 2 /* number of tries */);
.param(C2DMessaging.PARAM_COLLAPSE_KEY, collapseKey); log.fine("Result: " + result);
if (delayWhileIdle) { return result;
url.param(PARAM_DELAY_WHILE_IDLE, "1"); } catch (IOException e) {
log.log(Level.SEVERE, "Error sending " + message + " to " + regId, e);
return null;
} }
for (String key: params.keySet()) {
String[] values = params.get(key);
url.param(key, URLEncoder.encode(values[0], UTF8));
}
// Task queue implements the exponential backoff
long jitter = (int) Math.random() * DATAMESSAGING_MAX_JITTER_MSEC;
url.countdownMillis(jitter);
TaskHandle add = dmQueue.add(url);
} catch (UnsupportedEncodingException e) {
// Ignore - UTF8 should be supported
log.log(Level.SEVERE, "Unexpected error", e);
}
} }
} }

Binary file not shown.

Binary file not shown.

View File

@@ -23,7 +23,9 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.logging.Level;
import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager; import javax.jdo.PersistenceManager;
import javax.jdo.Query; import javax.jdo.Query;
import javax.jdo.annotations.IdentityType; import javax.jdo.annotations.IdentityType;
@@ -173,4 +175,14 @@ public class DeviceInfo {
return result; return result;
} }
public static DeviceInfo getDeviceInfo(PersistenceManager pm, String regId) {
Query query = pm.newQuery(DeviceInfo.class);
query.setFilter("deviceRegistrationID == '" + regId + "'");
@SuppressWarnings("unchecked")
List<DeviceInfo> result = (List<DeviceInfo>) query.execute();
DeviceInfo deviceInfo = (result == null || result.isEmpty()) ? null : result.get(0);
query.closeAll();
return deviceInfo;
}
} }

View File

@@ -237,4 +237,17 @@ public class RequestInfo {
} }
} }
public void updateRegistration(String regId, String canonicalRegId) {
if (ctx == null) {
return;
}
log.fine("Updating regId " + regId + " to canonical " + canonicalRegId);
PersistenceManager pm = C2DMessaging.getPMF(ctx).getPersistenceManager();
DeviceInfo device = DeviceInfo.getDeviceInfo(pm, regId);
device.setDeviceRegistrationID(canonicalRegId);
pm.currentTransaction().begin();
pm.makePersistent(device);
pm.currentTransaction().commit();
}
} }

View File

@@ -17,6 +17,11 @@
package com.google.android.chrometophone.server; package com.google.android.chrometophone.server;
import com.google.android.c2dm.server.C2DMessaging; import com.google.android.c2dm.server.C2DMessaging;
import com.google.android.gcm.server.Constants;
import com.google.android.gcm.server.Message;
import com.google.android.gcm.server.Message.Builder;
import com.google.android.gcm.server.Result;
import com.google.android.gcm.server.Sender;
import com.google.appengine.api.channel.ChannelMessage; import com.google.appengine.api.channel.ChannelMessage;
import com.google.appengine.api.channel.ChannelServiceFactory; import com.google.appengine.api.channel.ChannelServiceFactory;
@@ -86,18 +91,18 @@ public class SendServlet extends HttpServlet {
// Send push message to phone // Send push message to phone
C2DMessaging push = C2DMessaging.get(getServletContext()); C2DMessaging push = C2DMessaging.get(getServletContext());
boolean res = false; Object res = null;
String collapseKey = "" + url.hashCode(); String collapseKey = "" + url.hashCode();
boolean reqDebug = "1".equals(reqInfo.getParameter("debug")); boolean reqDebug = "1".equals(reqInfo.getParameter("debug"));
int ac2dmCnt = 0; int deviceCount = 0;
Iterator<DeviceInfo> iterator = reqInfo.devices.iterator(); Iterator<DeviceInfo> iterator = reqInfo.devices.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
DeviceInfo deviceInfo = iterator.next(); DeviceInfo deviceInfo = iterator.next();
if ("ac2dm".equals(deviceInfo.getType())) { if (!DeviceInfo.TYPE_CHROME.equals(deviceInfo.getType())) {
ac2dmCnt++; deviceCount++;
} }
if (deviceNames != null) { if (deviceNames != null) {
boolean found = false; boolean found = false;
@@ -117,28 +122,57 @@ public class SendServlet extends HttpServlet {
if (deviceInfo.getType().equals(DeviceInfo.TYPE_CHROME)) { if (deviceInfo.getType().equals(DeviceInfo.TYPE_CHROME)) {
res = doSendViaBrowserChannel(url, deviceInfo); res = doSendViaBrowserChannel(url, deviceInfo);
} else { } else {
res = doSendViaC2dm(url, title, sel, push, collapseKey, res = doSendViaGoogleCloud(url, title, sel, push, collapseKey,
deviceInfo, reqDebug); deviceInfo, reqDebug, deviceInfo.getType());
} }
if (res) { if (res == null) {
log.info("Link sent to phone! collapse_key:" + collapseKey); log.info("Link sent to phone! collapse_key:" + collapseKey);
ok = true; ok = true;
} else { } else {
// C2DM error
if (res instanceof IOException) {
IOException ex = (IOException) res;
log.warning("Error: Unable to send link to device: " + log.warning("Error: Unable to send link to device: " +
deviceInfo.getDeviceRegistrationID()); deviceInfo.getDeviceRegistrationID());
IOException ex = C2DMessaging.getC2dmException(); String error = "" + ex.getMessage();
if (ex != null) { if (error.equals(Constants.ERROR_NOT_REGISTERED) || error.equals(Constants.ERROR_INVALID_REGISTRATION)) {
if ("InvalidRegistration".equals(ex.getMessage())) {
// Prune device, it no longer works // Prune device, it no longer works
reqInfo.deleteRegistration(deviceInfo.getDeviceRegistrationID(), reqInfo.deleteRegistration(deviceInfo.getDeviceRegistrationID(),
deviceInfo.getType()); deviceInfo.getType());
iterator.remove(); iterator.remove();
ac2dmCnt--; deviceCount--;
} else { } else {
throw ex; throw ex;
} }
} }
// GCM result.
if (res instanceof Result) {
Result result = (Result) res;
String regId = deviceInfo.getDeviceRegistrationID();
if (result.getMessageId() != null) {
log.info("Link sent to phone! collapse_key:" + collapseKey);
ok = true;
String canonicalRegId = result.getCanonicalRegistrationId();
if (canonicalRegId != null) {
// same device has more than on registration id: update it
log.finest("canonicalRegId " + canonicalRegId);
reqInfo.updateRegistration(regId, canonicalRegId);
}
} else {
String error = result.getErrorCodeName();
if (error.equals(Constants.ERROR_NOT_REGISTERED) || error.equals(Constants.ERROR_INVALID_REGISTRATION)) {
// Prune device, it no longer works
reqInfo.deleteRegistration(regId, deviceInfo.getType());
iterator.remove();
deviceCount--;
} else {
log.severe("Error sending message to device " + regId
+ ": " + error);
throw new IOException(error);
}
}
}
} }
} }
@@ -149,7 +183,7 @@ public class SendServlet extends HttpServlet {
// Show the 'no devices' if only the browser is registered. // Show the 'no devices' if only the browser is registered.
// We should also clarify that 'error status' mean no matching // We should also clarify that 'error status' mean no matching
// device found ( when the extension allow specifying the destination ) // device found ( when the extension allow specifying the destination )
if (ac2dmCnt == 0 && "ac2dm".equals(deviceType)) { if (deviceCount == 0 && !DeviceInfo.TYPE_CHROME.equals(deviceType)) {
log.warning("No device registered for " + reqInfo.userName); log.warning("No device registered for " + reqInfo.userName);
return DEVICE_NOT_REGISTERED_STATUS; return DEVICE_NOT_REGISTERED_STATUS;
} else { } else {
@@ -158,8 +192,8 @@ public class SendServlet extends HttpServlet {
} }
} }
private boolean doSendViaC2dm(String url, String title, String sel, C2DMessaging push, private Object doSendViaGoogleCloud(String url, String title, String sel, C2DMessaging push,
String collapseKey, DeviceInfo deviceInfo, boolean reqDebug) { String collapseKey, DeviceInfo deviceInfo, boolean reqDebug, String deviceType) {
// Trim title, sel if needed. // Trim title, sel if needed.
if (url.length() + title.length() + sel.length() > 1000) { if (url.length() + title.length() + sel.length() > 1000) {
@@ -177,13 +211,28 @@ public class SendServlet extends HttpServlet {
} }
} }
boolean res; String regId = deviceInfo.getDeviceRegistrationID();
res = push.sendNoRetry(deviceInfo.getDeviceRegistrationID(), String debug = (deviceInfo.getDebug()) || reqDebug ? "1" : null;
Object res;
if (deviceType.equals(DeviceInfo.TYPE_AC2DM)) {
res = push.sendNoRetry(regId,
collapseKey, collapseKey,
"url", url, "url", url,
"title", title, "title", title,
"sel", sel, "sel", sel,
"debug", deviceInfo.getDebug() || reqDebug ? "1" : null); "debug", debug);
} else {
Builder builder = new Message.Builder()
.collapseKey(collapseKey)
.addData("url", url)
.addData("title", title)
.addData("sel", sel);
if (debug != null) {
builder.addData("debug", debug);
}
Message message = builder.build();
res = push.send(message, regId);
}
return res; return res;
} }

View File

@@ -43,7 +43,6 @@ public class UnregisterServlet extends HttpServlet {
return; return;
} }
// TODO: make sure new app passes deviceType
String deviceType = reqInfo.getParameter("deviceType"); String deviceType = reqInfo.getParameter("deviceType");
if (deviceType == null) { if (deviceType == null) {
deviceType = "ac2dm"; deviceType = "ac2dm";

View File

@@ -55,13 +55,6 @@
</servlet-class> </servlet-class>
</servlet> </servlet>
<servlet>
<servlet-name>dataMessagingServlet</servlet-name>
<servlet-class>
com.google.android.c2dm.server.C2DMRetryServlet
</servlet-class>
</servlet>
<servlet> <servlet>
<servlet-name>SenderServlet</servlet-name> <servlet-name>SenderServlet</servlet-name>
<servlet-class>com.google.android.chrometophone.server.SenderServlet <servlet-class>com.google.android.chrometophone.server.SenderServlet
@@ -130,20 +123,6 @@
<url-pattern>/admin/convertStats</url-pattern> <url-pattern>/admin/convertStats</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet-mapping>
<servlet-name>dataMessagingServlet</servlet-name>
<url-pattern>/tasks/c2dm</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>tasks</web-resource-name>
<url-pattern>/tasks/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<security-constraint> <security-constraint>
<web-resource-collection> <web-resource-collection>
<web-resource-name>admin</web-resource-name> <web-resource-name>admin</web-resource-name>

View File

@@ -174,4 +174,3 @@ function closeBrowserChannel() {
socketCloseRequested = true; socketCloseRequested = true;
if (socket) socket.close(); if (socket) socket.close();
} }