forked from upstream-mirrors/OpenTracks
Merge heads
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
#Fri Oct 21 20:06:28 BRST 2011
|
||||
#Tue Jul 17 10:23:26 PDT 2012
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
@@ -76,29 +76,66 @@ org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
||||
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=0
|
||||
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=48
|
||||
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=48
|
||||
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=48
|
||||
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
|
||||
@@ -138,12 +175,14 @@ 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.format_guardian_clause_on_one_line=true
|
||||
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
|
||||
@@ -210,6 +249,7 @@ org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_re
|
||||
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
|
||||
@@ -340,7 +380,7 @@ 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=true
|
||||
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=100
|
||||
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
|
||||
@@ -348,10 +388,22 @@ 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.sort_local_variable_annotations=false
|
||||
org.eclipse.jdt.core.formatter.sort_member_annotations=false
|
||||
org.eclipse.jdt.core.formatter.sort_package_annotations=false
|
||||
org.eclipse.jdt.core.formatter.sort_parameter_annotations=false
|
||||
org.eclipse.jdt.core.formatter.sort_type_annotations=false
|
||||
org.eclipse.jdt.core.formatter.tabulation.char=space
|
||||
org.eclipse.jdt.core.formatter.tabulation.size=2
|
||||
org.eclipse.jdt.core.formatter.use_on_off_tags=false
|
||||
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
||||
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
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#Thu Jul 21 03:04:13 BRT 2011
|
||||
#Tue Jul 17 10:22:06 PDT 2012
|
||||
eclipse.preferences.version=1
|
||||
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
|
||||
formatter_profile=_MyTracks
|
||||
formatter_settings_version=12
|
||||
formatter_profile=_My Tracks
|
||||
formatter_settings_version=13
|
||||
org.eclipse.jdt.ui.ignorelowercasenames=true
|
||||
org.eclipse.jdt.ui.importorder=com;android;java;javax;org;
|
||||
org.eclipse.jdt.ui.ondemandthreshold=99
|
||||
|
||||
@@ -16,7 +16,7 @@ limitations under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="47"
|
||||
android:versionCode="48"
|
||||
android:versionName="2.0"
|
||||
package="com.google.android.maps.mytracks" >
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -30,7 +30,7 @@
|
||||
other activity while watching live performance statistics. My Tracks makes it easy to archive
|
||||
your training history with Google Maps, Google Fusion Tables, and Google Docs, and share your
|
||||
activities with friends and the world.</string><string name="help_my_tracks_question" translation_description="In the 'Help' page, the question on what is My Tracks.">What is My Tracks?</string><string name="help_saved_files_answer" translation_description="In the 'Help' page, the answer on saved files.">You can use Google Earth or similar applications to visualize and edit GPS tracks.</string><string name="help_saved_files_question" translation_description="In the 'Help' page, the question on saved files.">What can I do with tracks after saving them to the SD card or sharing such files with friends?</string><string name="help_send_track_answer" translation_description="In the 'Help' page, the answer on sending a track. %1$s url. E.g., 'maps.google.com'. %2$s url. E.g., 'google.com/fusiontables'. %3$s url. E.g., 'docs.google.com'.">You can send a track to Google Maps, Google Fusion Tables, and Google Docs. Tracks sent to
|
||||
Google Maps are at %1$s, \\"My Places\\". Tracks sent to Google Fusion Tables are at %2$s. Tracks
|
||||
Google Maps are at %1$s, \"My Places\". Tracks sent to Google Fusion Tables are at %2$s. Tracks
|
||||
sent to Google Docs are at %3$s.</string><string name="help_send_track_question" translation_description="In the 'Help' page, the question on sending a track.">Where can I send a track?</string><string name="help_share_friends_answer" translation_description="In the 'Help' page, the answer on sharing with friends.">You can share a track as a link to Google Maps. Your track will first get uploaded to Google
|
||||
Maps.</string><string name="help_share_friends_question" translation_description="In the 'Help' page, the question on sharing with friends.">How do I share a track with friends?</string><string name="help_share_visibility_answer" translation_description="In the 'Help' page, the answer on share visibility.">By default, tracks sent to Google Maps are unlisted, tracks sent to Google Fusion Tables are
|
||||
public, and tracks sent to Google Docs are private. For Google Maps, you can change the
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright 2011 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.apps.mytracks.content;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.MAX_LOCATION_AGE_MS;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.database.ContentObserver;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
/**
|
||||
* Data source on the phone.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class DataSource {
|
||||
|
||||
private static final int NETWORK_PROVIDER_MIN_TIME = 5 * 60 * 1000; // 5 minutes
|
||||
private static final String TAG = DataSource.class.getSimpleName();
|
||||
|
||||
private final Context context;
|
||||
private final ContentResolver contentResolver;
|
||||
private final LocationManager locationManager;
|
||||
private final SensorManager sensorManager;
|
||||
private final SharedPreferences sharedPreferences;
|
||||
|
||||
public DataSource(Context context) {
|
||||
this.context = context;
|
||||
contentResolver = context.getContentResolver();
|
||||
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
|
||||
sharedPreferences = context.getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a content observer.
|
||||
*
|
||||
* @param uri the uri
|
||||
* @param observer the observer
|
||||
*/
|
||||
public void registerContentObserver(Uri uri, ContentObserver observer) {
|
||||
contentResolver.registerContentObserver(uri, false, observer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a content observer.
|
||||
*
|
||||
* @param observer the observer
|
||||
*/
|
||||
public void unregisterContentObserver(ContentObserver observer) {
|
||||
contentResolver.unregisterContentObserver(observer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a location listener.
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
public void registerLocationListener(LocationListener listener) {
|
||||
// Check if the GPS provider exists
|
||||
if (locationManager.getProvider(LocationManager.GPS_PROVIDER) == null) {
|
||||
listener.onProviderDisabled(LocationManager.GPS_PROVIDER);
|
||||
unregisterLocationListener(listener);
|
||||
return;
|
||||
}
|
||||
|
||||
// Listen for GPS location
|
||||
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);
|
||||
|
||||
// Update the listener with the current provider state
|
||||
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
|
||||
listener.onProviderEnabled(LocationManager.GPS_PROVIDER);
|
||||
} else {
|
||||
listener.onProviderDisabled(LocationManager.GPS_PROVIDER);
|
||||
}
|
||||
|
||||
// Listen for network location
|
||||
try {
|
||||
locationManager.requestLocationUpdates(
|
||||
LocationManager.NETWORK_PROVIDER, NETWORK_PROVIDER_MIN_TIME, 0, listener);
|
||||
} catch (RuntimeException e) {
|
||||
// Network location is optional, so just log the exception
|
||||
Log.w(TAG, "Could not register for network location.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a location listener.
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
public void unregisterLocationListener(LocationListener listener) {
|
||||
locationManager.removeUpdates(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last known location.
|
||||
*/
|
||||
public Location getLastKnownLocation() {
|
||||
Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
|
||||
if (!isLocationRecent(location)) {
|
||||
// Try network location
|
||||
location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
|
||||
int id = isLocationRecent(location)
|
||||
? R.string.my_location_approximate_location : R.string.my_location_no_location;
|
||||
Toast.makeText(context, id, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the location is recent.
|
||||
*
|
||||
* @param location the location
|
||||
*/
|
||||
private boolean isLocationRecent(Location location) {
|
||||
if (location == null) {
|
||||
return false;
|
||||
}
|
||||
return location.getTime() > System.currentTimeMillis() - MAX_LOCATION_AGE_MS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a compass listener.
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
public void registerCompassListener(SensorEventListener listener) {
|
||||
Sensor compass = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
|
||||
if (compass == null) {
|
||||
Log.d(TAG, "No compass sensor.");
|
||||
return;
|
||||
}
|
||||
sensorManager.registerListener(listener, compass, SensorManager.SENSOR_DELAY_UI);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a compass listener.
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
public void unregisterCompassListener(SensorEventListener listener) {
|
||||
sensorManager.unregisterListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a shared preference change listener.
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
|
||||
sharedPreferences.registerOnSharedPreferenceChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a shared preference change listener.
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
public void unregisterOnSharedPreferenceChangeListener(
|
||||
OnSharedPreferenceChangeListener listener) {
|
||||
sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2011 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.apps.mytracks.content;
|
||||
|
||||
import android.location.Location;
|
||||
|
||||
/**
|
||||
* Listener to be invoked when {@link DataSource} changes.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public interface DataSourceListener {
|
||||
|
||||
/**
|
||||
* Notifies when the tracks table is updated.
|
||||
*/
|
||||
public void notifyTracksTableUpdated();
|
||||
|
||||
/**
|
||||
* Notifies when the waypoints table is updated.
|
||||
*/
|
||||
public void notifyWaypointsTableUpdated();
|
||||
|
||||
/**
|
||||
* Notifies when the track points table is updated.
|
||||
*/
|
||||
public void notifyTrackPointsTableUpdated();
|
||||
|
||||
/**
|
||||
* Notifies when the current location changes.
|
||||
*
|
||||
* @param location the location
|
||||
*/
|
||||
public void notifyLocationChanged(Location location);
|
||||
|
||||
|
||||
/**
|
||||
* Notifies when the location provider enabled status changes.
|
||||
*
|
||||
* @param enabled true if enabled, false if not
|
||||
*/
|
||||
public void notifyLocationProviderEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Notifies when the location provider availability status changes.
|
||||
*
|
||||
* @param available true if available, false if not
|
||||
*/
|
||||
public void notifyLocationProviderAvailable(boolean available);
|
||||
|
||||
/**
|
||||
* Notifies when the compass heading changes.
|
||||
*
|
||||
* @param heading the new heading
|
||||
*/
|
||||
public void notifyHeadingChanged(float heading);
|
||||
|
||||
/**
|
||||
* Notifies when a preference changes.
|
||||
*
|
||||
* @param key the preference key
|
||||
*/
|
||||
public void notifyPreferenceChanged(String key);
|
||||
}
|
||||
@@ -1,16 +1,29 @@
|
||||
/*
|
||||
* Copyright 2011 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.apps.mytracks.content;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.database.ContentObserver;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
@@ -23,243 +36,281 @@ import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* External data source manager, which converts system-level events into My Tracks data events.
|
||||
*
|
||||
* Data source manager. Creates observers/listeners and manages their
|
||||
* registration with {@link DataSource}. The observers/listeners calls
|
||||
* {@link DataSourceListener} when data changes.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
class DataSourceManager {
|
||||
public class DataSourceManager {
|
||||
|
||||
/** Single interface for receiving system events that were registered for. */
|
||||
interface DataSourceListener {
|
||||
void notifyTrackUpdated();
|
||||
void notifyWaypointUpdated();
|
||||
void notifyPointsUpdated();
|
||||
void notifyPreferenceChanged(String key);
|
||||
void notifyLocationProviderEnabled(boolean enabled);
|
||||
void notifyLocationProviderAvailable(boolean available);
|
||||
void notifyLocationChanged(Location loc);
|
||||
void notifyHeadingChanged(float heading);
|
||||
}
|
||||
/**
|
||||
* Observer when the tracks table is updated.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
private class TracksTableObserver extends ContentObserver {
|
||||
|
||||
private final DataSourceListener listener;
|
||||
|
||||
/** Observer for when the tracks table is updated. */
|
||||
private class TrackObserver extends ContentObserver {
|
||||
public TrackObserver() {
|
||||
super(contentHandler);
|
||||
public TracksTableObserver() {
|
||||
super(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
listener.notifyTrackUpdated();
|
||||
dataSourceListener.notifyTracksTableUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
/** Observer for when the waypoints table is updated. */
|
||||
private class WaypointObserver extends ContentObserver {
|
||||
public WaypointObserver() {
|
||||
super(contentHandler);
|
||||
/**
|
||||
* Observer when the waypoints table is updated.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
private class WaypointsTableObserver extends ContentObserver {
|
||||
|
||||
public WaypointsTableObserver() {
|
||||
super(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
listener.notifyWaypointUpdated();
|
||||
dataSourceListener.notifyWaypointsTableUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
/** Observer for when the points table is updated. */
|
||||
private class PointObserver extends ContentObserver {
|
||||
public PointObserver() {
|
||||
super(contentHandler);
|
||||
/**
|
||||
* Observer when the track points table is updated.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
private class TrackPointsTableObserver extends ContentObserver {
|
||||
|
||||
public TrackPointsTableObserver() {
|
||||
super(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
listener.notifyPointsUpdated();
|
||||
dataSourceListener.notifyTrackPointsTableUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
/** Listener for when preferences change. */
|
||||
private class HubSharedPreferenceListener implements OnSharedPreferenceChangeListener {
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
listener.notifyPreferenceChanged(key);
|
||||
}
|
||||
}
|
||||
|
||||
/** Listener for the current location (independent from track data). */
|
||||
private class CurrentLocationListener implements
|
||||
LocationListener {
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
if (!LocationManager.GPS_PROVIDER.equals(provider)) return;
|
||||
|
||||
listener.notifyLocationProviderAvailable(status == LocationProvider.AVAILABLE);
|
||||
}
|
||||
/**
|
||||
* Listener for location changes.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
private class CurrentLocationListener implements LocationListener {
|
||||
|
||||
@Override
|
||||
public void onProviderEnabled(String provider) {
|
||||
if (!LocationManager.GPS_PROVIDER.equals(provider)) return;
|
||||
|
||||
listener.notifyLocationProviderEnabled(true);
|
||||
public void onLocationChanged(Location location) {
|
||||
dataSourceListener.notifyLocationChanged(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(String provider) {
|
||||
if (!LocationManager.GPS_PROVIDER.equals(provider)) return;
|
||||
|
||||
listener.notifyLocationProviderEnabled(false);
|
||||
if (!LocationManager.GPS_PROVIDER.equals(provider)) {
|
||||
return;
|
||||
}
|
||||
dataSourceListener.notifyLocationProviderEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(Location location) {
|
||||
listener.notifyLocationChanged(location);
|
||||
public void onProviderEnabled(String provider) {
|
||||
if (!LocationManager.GPS_PROVIDER.equals(provider)) {
|
||||
return;
|
||||
}
|
||||
dataSourceListener.notifyLocationProviderEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
if (!LocationManager.GPS_PROVIDER.equals(provider)) {
|
||||
return;
|
||||
}
|
||||
dataSourceListener.notifyLocationProviderAvailable(status == LocationProvider.AVAILABLE);
|
||||
}
|
||||
}
|
||||
|
||||
/** Listener for compass readings. */
|
||||
private class CompassListener implements
|
||||
SensorEventListener {
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
listener.notifyHeadingChanged(event.values[0]);
|
||||
}
|
||||
/**
|
||||
* Listener for compass changes.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
private class CompassListener implements SensorEventListener {
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
dataSourceListener.notifyHeadingChanged(event.values[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Wrapper for registering internal listeners. */
|
||||
private final DataSourcesWrapper dataSources;
|
||||
/**
|
||||
* Listener for preference changes.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
private class PreferenceListener implements OnSharedPreferenceChangeListener {
|
||||
|
||||
// Internal listeners (to receive data from the system)
|
||||
private final Set<ListenerDataType> registeredListeners =
|
||||
EnumSet.noneOf(ListenerDataType.class);
|
||||
private final Handler contentHandler;
|
||||
private final ContentObserver pointObserver;
|
||||
private final ContentObserver waypointObserver;
|
||||
private final ContentObserver trackObserver;
|
||||
private final LocationListener locationListener;
|
||||
private final OnSharedPreferenceChangeListener preferenceListener;
|
||||
private final SensorEventListener compassListener;
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
dataSourceListener.notifyPreferenceChanged(key);
|
||||
}
|
||||
}
|
||||
|
||||
DataSourceManager(DataSourceListener listener, DataSourcesWrapper dataSources) {
|
||||
this.listener = listener;
|
||||
this.dataSources = dataSources;
|
||||
private final DataSource dataSource;
|
||||
private final DataSourceListener dataSourceListener;
|
||||
|
||||
contentHandler = new Handler();
|
||||
pointObserver = new PointObserver();
|
||||
waypointObserver = new WaypointObserver();
|
||||
trackObserver = new TrackObserver();
|
||||
// Registered listeners
|
||||
private final Set<TrackDataType> registeredListeners = EnumSet.noneOf(TrackDataType.class);
|
||||
|
||||
private final Handler handler;
|
||||
private final TracksTableObserver tracksTableObserver;
|
||||
private final WaypointsTableObserver waypointsTableObserver;
|
||||
private final TrackPointsTableObserver trackPointsTableObserver;
|
||||
private final CurrentLocationListener currentLocationListener;
|
||||
private final CompassListener compassListener;
|
||||
private final PreferenceListener preferenceListener;
|
||||
|
||||
public DataSourceManager(DataSource dataSource, DataSourceListener dataSourceListener) {
|
||||
this.dataSource = dataSource;
|
||||
this.dataSourceListener = dataSourceListener;
|
||||
|
||||
handler = new Handler();
|
||||
tracksTableObserver = new TracksTableObserver();
|
||||
waypointsTableObserver = new WaypointsTableObserver();
|
||||
trackPointsTableObserver = new TrackPointsTableObserver();
|
||||
currentLocationListener = new CurrentLocationListener();
|
||||
compassListener = new CompassListener();
|
||||
locationListener = new CurrentLocationListener();
|
||||
preferenceListener = new HubSharedPreferenceListener();
|
||||
preferenceListener = new PreferenceListener();
|
||||
}
|
||||
|
||||
/** Updates the internal (sensor, position, etc) listeners. */
|
||||
void updateAllListeners(EnumSet<ListenerDataType> externallyNeededListeners) {
|
||||
EnumSet<ListenerDataType> neededListeners = EnumSet.copyOf(externallyNeededListeners);
|
||||
/**
|
||||
* Updates listeners with data source.
|
||||
*
|
||||
* @param listeners the listeners
|
||||
*/
|
||||
public void updateListeners(EnumSet<TrackDataType> listeners) {
|
||||
EnumSet<TrackDataType> neededListeners = EnumSet.copyOf(listeners);
|
||||
|
||||
// Special case - map sampled-out points type to points type since they
|
||||
// correspond to the same internal listener.
|
||||
if (neededListeners.contains(ListenerDataType.SAMPLED_OUT_POINT_UPDATES)) {
|
||||
neededListeners.remove(ListenerDataType.SAMPLED_OUT_POINT_UPDATES);
|
||||
neededListeners.add(ListenerDataType.POINT_UPDATES);
|
||||
/*
|
||||
* Map SAMPLED_OUT_POINT_UPDATES to POINT_UPDATES since they correspond to
|
||||
* the same internal listener
|
||||
*/
|
||||
if (neededListeners.contains(TrackDataType.SAMPLED_OUT_TRACK_POINTS)) {
|
||||
neededListeners.remove(TrackDataType.SAMPLED_OUT_TRACK_POINTS);
|
||||
neededListeners.add(TrackDataType.TRACK_POINTS_TABLE);
|
||||
}
|
||||
|
||||
Log.d(TAG, "Updating internal listeners to types " + neededListeners);
|
||||
Log.d(TAG, "Updating listeners " + neededListeners);
|
||||
|
||||
// Unnecessary = registered - needed
|
||||
Set<ListenerDataType> unnecessaryListeners = EnumSet.copyOf(registeredListeners);
|
||||
Set<TrackDataType> unnecessaryListeners = EnumSet.copyOf(registeredListeners);
|
||||
unnecessaryListeners.removeAll(neededListeners);
|
||||
|
||||
// Missing = needed - registered
|
||||
Set<ListenerDataType> missingListeners = EnumSet.copyOf(neededListeners);
|
||||
Set<TrackDataType> missingListeners = EnumSet.copyOf(neededListeners);
|
||||
missingListeners.removeAll(registeredListeners);
|
||||
|
||||
// Remove all unnecessary listeners.
|
||||
for (ListenerDataType type : unnecessaryListeners) {
|
||||
unregisterListener(type);
|
||||
// Remove unnecessary listeners
|
||||
for (TrackDataType trackDataType : unnecessaryListeners) {
|
||||
unregisterListener(trackDataType);
|
||||
}
|
||||
|
||||
// Add all missing listeners.
|
||||
for (ListenerDataType type : missingListeners) {
|
||||
registerListener(type);
|
||||
// Add missing listeners
|
||||
for (TrackDataType trackDataType : missingListeners) {
|
||||
registerListener(trackDataType);
|
||||
}
|
||||
|
||||
// Now all needed types are registered.
|
||||
// Update registered listeners
|
||||
registeredListeners.clear();
|
||||
registeredListeners.addAll(neededListeners);
|
||||
}
|
||||
|
||||
private void registerListener(ListenerDataType type) {
|
||||
switch (type) {
|
||||
case COMPASS_UPDATES: {
|
||||
// Listen to compass
|
||||
Sensor compass = dataSources.getSensor(Sensor.TYPE_ORIENTATION);
|
||||
if (compass != null) {
|
||||
Log.d(TAG, "TrackDataHub: Now registering sensor listener.");
|
||||
dataSources.registerSensorListener(compassListener, compass, SensorManager.SENSOR_DELAY_UI);
|
||||
}
|
||||
/**
|
||||
* Registers a listener with data source.
|
||||
*
|
||||
* @param trackDataType the listener data type
|
||||
*/
|
||||
private void registerListener(TrackDataType trackDataType) {
|
||||
switch (trackDataType) {
|
||||
case SELECTED_TRACK:
|
||||
// Do nothing
|
||||
break;
|
||||
}
|
||||
case LOCATION_UPDATES:
|
||||
dataSources.requestLocationUpdates(locationListener);
|
||||
case TRACKS_TABLE:
|
||||
dataSource.registerContentObserver(TracksColumns.CONTENT_URI, tracksTableObserver);
|
||||
break;
|
||||
case POINT_UPDATES:
|
||||
dataSources.registerContentObserver(
|
||||
TrackPointsColumns.CONTENT_URI, false, pointObserver);
|
||||
case WAYPOINTS_TABLE:
|
||||
dataSource.registerContentObserver(WaypointsColumns.CONTENT_URI, waypointsTableObserver);
|
||||
break;
|
||||
case TRACK_UPDATES:
|
||||
dataSources.registerContentObserver(TracksColumns.CONTENT_URI, false, trackObserver);
|
||||
case TRACK_POINTS_TABLE:
|
||||
dataSource.registerContentObserver(
|
||||
TrackPointsColumns.CONTENT_URI, trackPointsTableObserver);
|
||||
break;
|
||||
case WAYPOINT_UPDATES:
|
||||
dataSources.registerContentObserver(
|
||||
WaypointsColumns.CONTENT_URI, false, waypointObserver);
|
||||
case SAMPLED_OUT_TRACK_POINTS:
|
||||
// Do nothing. SAMPLED_OUT_POINT_UPDATES is mapped to POINT_UPDATES.
|
||||
break;
|
||||
case DISPLAY_PREFERENCES:
|
||||
dataSources.registerOnSharedPreferenceChangeListener(preferenceListener);
|
||||
case LOCATION:
|
||||
dataSource.registerLocationListener(currentLocationListener);
|
||||
break;
|
||||
case COMPASS:
|
||||
dataSource.registerCompassListener(compassListener);
|
||||
break;
|
||||
case PREFERENCE:
|
||||
dataSource.registerOnSharedPreferenceChangeListener(preferenceListener);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case SAMPLED_OUT_POINT_UPDATES:
|
||||
throw new IllegalArgumentException("Should have been mapped to point updates");
|
||||
}
|
||||
}
|
||||
|
||||
private void unregisterListener(ListenerDataType type) {
|
||||
switch (type) {
|
||||
case COMPASS_UPDATES:
|
||||
dataSources.unregisterSensorListener(compassListener);
|
||||
/**
|
||||
* Unregisters a listener with data source.
|
||||
*
|
||||
* @param trackDataType listener data type
|
||||
*/
|
||||
private void unregisterListener(TrackDataType trackDataType) {
|
||||
switch (trackDataType) {
|
||||
case SELECTED_TRACK:
|
||||
// Do nothing
|
||||
break;
|
||||
case LOCATION_UPDATES:
|
||||
dataSources.removeLocationUpdates(locationListener);
|
||||
case TRACKS_TABLE:
|
||||
dataSource.unregisterContentObserver(tracksTableObserver);
|
||||
break;
|
||||
case POINT_UPDATES:
|
||||
dataSources.unregisterContentObserver(pointObserver);
|
||||
case WAYPOINTS_TABLE:
|
||||
dataSource.unregisterContentObserver(waypointsTableObserver);
|
||||
break;
|
||||
case TRACK_UPDATES:
|
||||
dataSources.unregisterContentObserver(trackObserver);
|
||||
case TRACK_POINTS_TABLE:
|
||||
dataSource.unregisterContentObserver(trackPointsTableObserver);
|
||||
break;
|
||||
case WAYPOINT_UPDATES:
|
||||
dataSources.unregisterContentObserver(waypointObserver);
|
||||
case SAMPLED_OUT_TRACK_POINTS:
|
||||
// Do nothing. SAMPLED_OUT_POINT_UPDATES is mapped to POINT_UPDATES.
|
||||
break;
|
||||
case DISPLAY_PREFERENCES:
|
||||
dataSources.unregisterOnSharedPreferenceChangeListener(preferenceListener);
|
||||
case LOCATION:
|
||||
dataSource.unregisterLocationListener(currentLocationListener);
|
||||
break;
|
||||
case COMPASS:
|
||||
dataSource.unregisterCompassListener(compassListener);
|
||||
break;
|
||||
case PREFERENCE:
|
||||
dataSource.unregisterOnSharedPreferenceChangeListener(preferenceListener);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case SAMPLED_OUT_POINT_UPDATES:
|
||||
throw new IllegalArgumentException("Should have been mapped to point updates");
|
||||
}
|
||||
}
|
||||
|
||||
/** Unregisters all internal (sensor, position, etc.) listeners. */
|
||||
void unregisterAllListeners() {
|
||||
dataSources.removeLocationUpdates(locationListener);
|
||||
dataSources.unregisterSensorListener(compassListener);
|
||||
dataSources.unregisterContentObserver(trackObserver);
|
||||
dataSources.unregisterContentObserver(waypointObserver);
|
||||
dataSources.unregisterContentObserver(pointObserver);
|
||||
dataSources.unregisterOnSharedPreferenceChangeListener(preferenceListener);
|
||||
/**
|
||||
* Unregisters all listeners with data source.
|
||||
*/
|
||||
public void unregisterAllListeners() {
|
||||
for (TrackDataType trackDataType : TrackDataType.values()) {
|
||||
unregisterListener(trackDataType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 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.apps.mytracks.content;
|
||||
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.database.ContentObserver;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.net.Uri;
|
||||
|
||||
/**
|
||||
* Interface for abstracting registration of external data source listeners.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
interface DataSourcesWrapper {
|
||||
// Preferences
|
||||
void registerOnSharedPreferenceChangeListener(
|
||||
OnSharedPreferenceChangeListener listener);
|
||||
void unregisterOnSharedPreferenceChangeListener(
|
||||
OnSharedPreferenceChangeListener listener);
|
||||
|
||||
// Content provider
|
||||
void registerContentObserver(Uri contentUri, boolean descendents,
|
||||
ContentObserver observer);
|
||||
void unregisterContentObserver(ContentObserver observer);
|
||||
|
||||
// Sensors
|
||||
Sensor getSensor(int type);
|
||||
void registerSensorListener(SensorEventListener listener,
|
||||
Sensor sensor, int sensorDelay);
|
||||
void unregisterSensorListener(SensorEventListener listener);
|
||||
|
||||
// Location
|
||||
boolean isLocationProviderEnabled(String provider);
|
||||
void requestLocationUpdates(LocationListener listener);
|
||||
void removeLocationUpdates(LocationListener listener);
|
||||
Location getLastKnownLocation();
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 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.apps.mytracks.content;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.MAX_LOCATION_AGE_MS;
|
||||
import static com.google.android.apps.mytracks.Constants.MAX_NETWORK_AGE_MS;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.database.ContentObserver;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
import android.location.LocationProvider;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
/**
|
||||
* Real implementation of the data sources, which talks to system services.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
class DataSourcesWrapperImpl implements DataSourcesWrapper {
|
||||
// System services
|
||||
private final SensorManager sensorManager;
|
||||
private final LocationManager locationManager;
|
||||
private final ContentResolver contentResolver;
|
||||
private final SharedPreferences sharedPreferences;
|
||||
private final Context context;
|
||||
|
||||
DataSourcesWrapperImpl(Context context, SharedPreferences sharedPreferences) {
|
||||
this.context = context;
|
||||
this.sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
|
||||
this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
this.contentResolver = context.getContentResolver();
|
||||
this.sharedPreferences = sharedPreferences;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerOnSharedPreferenceChangeListener(
|
||||
OnSharedPreferenceChangeListener listener) {
|
||||
sharedPreferences.registerOnSharedPreferenceChangeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterOnSharedPreferenceChangeListener(
|
||||
OnSharedPreferenceChangeListener listener) {
|
||||
sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerContentObserver(Uri contentUri, boolean descendents,
|
||||
ContentObserver observer) {
|
||||
contentResolver.registerContentObserver(contentUri, descendents, observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterContentObserver(ContentObserver observer) {
|
||||
contentResolver.unregisterContentObserver(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sensor getSensor(int type) {
|
||||
return sensorManager.getDefaultSensor(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSensorListener(SensorEventListener listener,
|
||||
Sensor sensor, int sensorDelay) {
|
||||
sensorManager.registerListener(listener, sensor, sensorDelay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterSensorListener(SensorEventListener listener) {
|
||||
sensorManager.unregisterListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLocationProviderEnabled(String provider) {
|
||||
return locationManager.isProviderEnabled(provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestLocationUpdates(LocationListener listener) {
|
||||
// Check if the provider exists.
|
||||
LocationProvider gpsProvider = locationManager.getProvider(LocationManager.GPS_PROVIDER);
|
||||
if (gpsProvider == null) {
|
||||
listener.onProviderDisabled(LocationManager.GPS_PROVIDER);
|
||||
locationManager.removeUpdates(listener);
|
||||
return;
|
||||
}
|
||||
|
||||
// Listen to GPS location.
|
||||
String providerName = gpsProvider.getName();
|
||||
Log.d(Constants.TAG, "TrackDataHub: Using location provider " + providerName);
|
||||
locationManager.requestLocationUpdates(providerName,
|
||||
0 /*minTime*/, 0 /*minDist*/, listener);
|
||||
|
||||
// Give an initial update on provider state.
|
||||
if (locationManager.isProviderEnabled(providerName)) {
|
||||
listener.onProviderEnabled(providerName);
|
||||
} else {
|
||||
listener.onProviderDisabled(providerName);
|
||||
}
|
||||
|
||||
// Listen to network location
|
||||
try {
|
||||
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
|
||||
1000 * 60 * 5 /*minTime*/, 0 /*minDist*/, listener);
|
||||
} catch (RuntimeException e) {
|
||||
// If anything at all goes wrong with getting a cell location do not
|
||||
// abort. Cell location is not essential to this app.
|
||||
Log.w(Constants.TAG, "Could not register network location listener.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLastKnownLocation() {
|
||||
// TODO: Let's look at more advanced algorithms to determine the best
|
||||
// current location.
|
||||
|
||||
Location loc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
|
||||
final long now = System.currentTimeMillis();
|
||||
if (loc == null || loc.getTime() < now - MAX_LOCATION_AGE_MS) {
|
||||
// We don't have a recent GPS fix, just use cell towers if available
|
||||
loc = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
|
||||
|
||||
int toastResId = R.string.my_location_approximate_location;
|
||||
if (loc == null || loc.getTime() < now - MAX_NETWORK_AGE_MS) {
|
||||
// We don't have a recent cell tower location, let the user know:
|
||||
toastResId = R.string.my_location_no_location;
|
||||
}
|
||||
|
||||
// Let the user know we have only an approximate location:
|
||||
Toast.makeText(context, toastResId, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
return loc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLocationUpdates(LocationListener listener) {
|
||||
locationManager.removeUpdates(listener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2011 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.apps.mytracks.content;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* State for a registered {@link TrackDataListener}.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class ListenerState {
|
||||
|
||||
private TrackDataListener trackDataListener;
|
||||
private EnumSet<TrackDataType> trackDataTypes;
|
||||
|
||||
private long lastTrackId;
|
||||
private long lastPointId;
|
||||
private int lastSamplingFrequency;
|
||||
private int numberOfLoadedPoints;
|
||||
|
||||
public ListenerState(
|
||||
TrackDataListener trackDataListener, EnumSet<TrackDataType> trackDataTypes) {
|
||||
this.trackDataListener = trackDataListener;
|
||||
this.trackDataTypes = trackDataTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link TrackDataListener}.
|
||||
*/
|
||||
public TrackDataListener getTrackDataListener() {
|
||||
return trackDataListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the track data types.
|
||||
*/
|
||||
public EnumSet<TrackDataType> getTrackDataTypes() {
|
||||
return trackDataTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last track id.
|
||||
*/
|
||||
public long getLastTrackId() {
|
||||
return lastTrackId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last point id.
|
||||
*/
|
||||
public long getLastPointId() {
|
||||
return lastPointId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last sampling frequency.
|
||||
*/
|
||||
public int getLastSamplingFrequency() {
|
||||
return lastSamplingFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of loaded points.
|
||||
*/
|
||||
public int getNumberOfLoadedPoints() {
|
||||
return numberOfLoadedPoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the listener state.
|
||||
*
|
||||
* @param trackId track id
|
||||
* @param pointId point id
|
||||
* @param samplingFrequency sampling frequency
|
||||
* @param loadedPoints number of loaded points
|
||||
*/
|
||||
public void setState(long trackId, long pointId, int samplingFrequency, int loadedPoints) {
|
||||
lastTrackId = trackId;
|
||||
lastPointId = pointId;
|
||||
lastSamplingFrequency = samplingFrequency;
|
||||
numberOfLoadedPoints = loadedPoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets state.
|
||||
*/
|
||||
public void resetState() {
|
||||
setState(0L, 0L, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.google.android.apps.mytracks.content;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
@@ -38,64 +37,58 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* A provider that handles recorded (GPS) tracks and their track points.
|
||||
*
|
||||
* A {@link ContentProvider} that handles access to track points, tracks, and
|
||||
* waypoints tables.
|
||||
*
|
||||
* @author Leif Hendrik Wilden
|
||||
*/
|
||||
public class MyTracksProvider extends ContentProvider {
|
||||
|
||||
private static final String TAG = MyTracksProvider.class.getSimpleName();
|
||||
private static final String DATABASE_NAME = "mytracks.db";
|
||||
private static final int DATABASE_VERSION = 20;
|
||||
private static final int TRACKPOINTS = 1;
|
||||
private static final int TRACKPOINTS_ID = 2;
|
||||
private static final int TRACKS = 3;
|
||||
private static final int TRACKS_ID = 4;
|
||||
private static final int WAYPOINTS = 5;
|
||||
private static final int WAYPOINTS_ID = 6;
|
||||
private static final String TAG = MyTracksProvider.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* Helper which creates or upgrades the database if necessary.
|
||||
* Database helper for creating and upgrading the databasae.
|
||||
*/
|
||||
private static class DatabaseHelper extends SQLiteOpenHelper {
|
||||
|
||||
|
||||
public DatabaseHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
db.execSQL(TrackPointsColumns.CREATE_TABLE);
|
||||
db.execSQL(TracksColumns.CREATE_TABLE);
|
||||
db.execSQL(WaypointsColumns.CREATE_TABLE);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion);
|
||||
if (oldVersion < 17) {
|
||||
// Delete the old data
|
||||
Log.w(TAG, "Delete all old data");
|
||||
Log.w(TAG, "Deleting all old data.");
|
||||
db.execSQL("DROP TABLE IF EXISTS " + TrackPointsColumns.TABLE_NAME);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + TracksColumns.TABLE_NAME);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + WaypointsColumns.TABLE_NAME);
|
||||
onCreate(db);
|
||||
} else {
|
||||
// Incremental updates go here. For each DB version, add a corresponding if clause.
|
||||
|
||||
// Track points sensor column
|
||||
// Incremental upgrades. One if statement per DB version.
|
||||
|
||||
// Add track points SENSOR column
|
||||
if (oldVersion <= 17) {
|
||||
Log.w(TAG, "Upgrade DB: Adding sensor column.");
|
||||
db.execSQL("ALTER TABLE " + TrackPointsColumns.TABLE_NAME + " ADD "
|
||||
+ TrackPointsColumns.SENSOR + " BLOB");
|
||||
}
|
||||
// Tracks table id column
|
||||
// Add tracks TABLEID column
|
||||
if (oldVersion <= 18) {
|
||||
Log.w(TAG, "Upgrade DB: Adding tableid column.");
|
||||
db.execSQL("ALTER TABLE " + TracksColumns.TABLE_NAME + " ADD " + TracksColumns.TABLEID
|
||||
+ " STRING");
|
||||
}
|
||||
// Tracks table icon column
|
||||
// Add tracks ICON column
|
||||
if (oldVersion <= 19) {
|
||||
Log.w(TAG, "Upgrade DB: Adding icon column.");
|
||||
db.execSQL(
|
||||
@@ -105,30 +98,32 @@ public class MyTracksProvider extends ContentProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private final UriMatcher urlMatcher;
|
||||
/**
|
||||
* Types of url.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
private enum UrlType {
|
||||
TRACKPOINTS, TRACKPOINTS_ID, TRACKS, TRACKS_ID, WAYPOINTS, WAYPOINTS_ID
|
||||
}
|
||||
|
||||
private final UriMatcher uriMatcher;
|
||||
private SQLiteDatabase db;
|
||||
|
||||
public MyTracksProvider() {
|
||||
urlMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
||||
urlMatcher.addURI(MyTracksProviderUtils.AUTHORITY,
|
||||
"trackpoints", TRACKPOINTS);
|
||||
urlMatcher.addURI(MyTracksProviderUtils.AUTHORITY,
|
||||
"trackpoints/#", TRACKPOINTS_ID);
|
||||
urlMatcher.addURI(MyTracksProviderUtils.AUTHORITY, "tracks", TRACKS);
|
||||
urlMatcher.addURI(MyTracksProviderUtils.AUTHORITY, "tracks/#", TRACKS_ID);
|
||||
urlMatcher.addURI(MyTracksProviderUtils.AUTHORITY, "waypoints", WAYPOINTS);
|
||||
urlMatcher.addURI(MyTracksProviderUtils.AUTHORITY,
|
||||
"waypoints/#", WAYPOINTS_ID);
|
||||
}
|
||||
|
||||
private boolean canAccess() {
|
||||
if (Binder.getCallingPid() == Process.myPid()) {
|
||||
return true;
|
||||
} else {
|
||||
return PreferencesUtils.getBoolean(
|
||||
getContext(), R.string.allow_access_key, PreferencesUtils.ALLOW_ACCESS_DEFAULT);
|
||||
}
|
||||
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
||||
uriMatcher.addURI(MyTracksProviderUtils.AUTHORITY, TrackPointsColumns.TABLE_NAME,
|
||||
UrlType.TRACKPOINTS.ordinal());
|
||||
uriMatcher.addURI(MyTracksProviderUtils.AUTHORITY, TrackPointsColumns.TABLE_NAME + "/#",
|
||||
UrlType.TRACKPOINTS_ID.ordinal());
|
||||
uriMatcher.addURI(
|
||||
MyTracksProviderUtils.AUTHORITY, TracksColumns.TABLE_NAME, UrlType.TRACKS.ordinal());
|
||||
uriMatcher.addURI(MyTracksProviderUtils.AUTHORITY, TracksColumns.TABLE_NAME + "/#",
|
||||
UrlType.TRACKS_ID.ordinal());
|
||||
uriMatcher.addURI(
|
||||
MyTracksProviderUtils.AUTHORITY, WaypointsColumns.TABLE_NAME, UrlType.WAYPOINTS.ordinal());
|
||||
uriMatcher.addURI(MyTracksProviderUtils.AUTHORITY, WaypointsColumns.TABLE_NAME + "/#",
|
||||
UrlType.WAYPOINTS_ID.ordinal());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -136,11 +131,11 @@ public class MyTracksProvider extends ContentProvider {
|
||||
if (!canAccess()) {
|
||||
return false;
|
||||
}
|
||||
DatabaseHelper dbHelper = new DatabaseHelper(getContext());
|
||||
DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
|
||||
try {
|
||||
db = dbHelper.getWritableDatabase();
|
||||
db = databaseHelper.getWritableDatabase();
|
||||
} catch (SQLiteException e) {
|
||||
Log.e(TAG, "Unable to open database for writing", e);
|
||||
Log.e(TAG, "Unable to open database for writing.", e);
|
||||
}
|
||||
return db != null;
|
||||
}
|
||||
@@ -152,7 +147,7 @@ public class MyTracksProvider extends ContentProvider {
|
||||
}
|
||||
String table;
|
||||
boolean shouldVacuum = false;
|
||||
switch (urlMatcher.match(url)) {
|
||||
switch (getUrlType(url)) {
|
||||
case TRACKPOINTS:
|
||||
table = TrackPointsColumns.TABLE_NAME;
|
||||
break;
|
||||
@@ -166,17 +161,23 @@ public class MyTracksProvider extends ContentProvider {
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown URL " + url);
|
||||
}
|
||||
|
||||
Log.w(MyTracksProvider.TAG, "provider delete in " + table + "!");
|
||||
int count = db.delete(table, where, selectionArgs);
|
||||
|
||||
Log.w(MyTracksProvider.TAG, "Deleting table " + table);
|
||||
int count;
|
||||
try {
|
||||
db.beginTransaction();
|
||||
count = db.delete(table, where, selectionArgs);
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
getContext().getContentResolver().notifyChange(url, null, true);
|
||||
|
||||
|
||||
if (shouldVacuum) {
|
||||
// If a potentially large amount of data was deleted, we want to reclaim its space.
|
||||
Log.i(TAG, "Vacuuming the database");
|
||||
// If a potentially large amount of data was deleted, reclaim its space.
|
||||
Log.i(TAG, "Vacuuming the database.");
|
||||
db.execSQL("VACUUM");
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -185,7 +186,7 @@ public class MyTracksProvider extends ContentProvider {
|
||||
if (!canAccess()) {
|
||||
return null;
|
||||
}
|
||||
switch (urlMatcher.match(url)) {
|
||||
switch (getUrlType(url)) {
|
||||
case TRACKPOINTS:
|
||||
return TrackPointsColumns.CONTENT_TYPE;
|
||||
case TRACKPOINTS_ID:
|
||||
@@ -208,197 +209,240 @@ public class MyTracksProvider extends ContentProvider {
|
||||
if (!canAccess()) {
|
||||
return null;
|
||||
}
|
||||
Log.d(MyTracksProvider.TAG, "MyTracksProvider.insert");
|
||||
ContentValues values;
|
||||
if (initialValues != null) {
|
||||
values = initialValues;
|
||||
} else {
|
||||
values = new ContentValues();
|
||||
if (initialValues == null) {
|
||||
initialValues = new ContentValues();
|
||||
}
|
||||
|
||||
int urlMatchType = urlMatcher.match(url);
|
||||
return insertType(url, urlMatchType, values);
|
||||
}
|
||||
|
||||
private Uri insertType(Uri url, int urlMatchType, ContentValues values) {
|
||||
switch (urlMatchType) {
|
||||
case TRACKPOINTS:
|
||||
return insertTrackPoint(url, values);
|
||||
case TRACKS:
|
||||
return insertTrack(url, values);
|
||||
case WAYPOINTS:
|
||||
return insertWaypoint(url, values);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown URL " + url);
|
||||
Uri result = null;
|
||||
try {
|
||||
db.beginTransaction();
|
||||
result = insertContentValues(url, getUrlType(url), initialValues);
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int bulkInsert(Uri url, ContentValues[] valuesBulk) {
|
||||
if (!canAccess()) {
|
||||
return 0;
|
||||
}
|
||||
Log.d(MyTracksProvider.TAG, "MyTracksProvider.bulkInsert");
|
||||
int numInserted = 0;
|
||||
try {
|
||||
// Use a transaction in order to make the insertions run as a single batch
|
||||
db.beginTransaction();
|
||||
|
||||
int urlMatch = urlMatcher.match(url);
|
||||
|
||||
UrlType urlType = getUrlType(url);
|
||||
for (numInserted = 0; numInserted < valuesBulk.length; numInserted++) {
|
||||
ContentValues values = valuesBulk[numInserted];
|
||||
if (values == null) { values = new ContentValues(); }
|
||||
|
||||
insertType(url, urlMatch, values);
|
||||
ContentValues contentValues = valuesBulk[numInserted];
|
||||
if (contentValues == null) {
|
||||
contentValues = new ContentValues();
|
||||
}
|
||||
insertContentValues(url, urlType, contentValues);
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
return numInserted;
|
||||
}
|
||||
|
||||
private Uri insertTrackPoint(Uri url, ContentValues values) {
|
||||
boolean hasLat = values.containsKey(TrackPointsColumns.LATITUDE);
|
||||
boolean hasLong = values.containsKey(TrackPointsColumns.LONGITUDE);
|
||||
boolean hasTime = values.containsKey(TrackPointsColumns.TIME);
|
||||
if (!hasLat || !hasLong || !hasTime) {
|
||||
throw new IllegalArgumentException(
|
||||
"Latitude, longitude, and time values are required.");
|
||||
}
|
||||
long rowId = db.insert(TrackPointsColumns.TABLE_NAME, TrackPointsColumns._ID, values);
|
||||
if (rowId >= 0) {
|
||||
Uri uri = ContentUris.appendId(
|
||||
TrackPointsColumns.CONTENT_URI.buildUpon(), rowId).build();
|
||||
getContext().getContentResolver().notifyChange(url, null, true);
|
||||
return uri;
|
||||
}
|
||||
throw new SQLiteException("Failed to insert row into " + url);
|
||||
}
|
||||
|
||||
private Uri insertTrack(Uri url, ContentValues values) {
|
||||
boolean hasStartTime = values.containsKey(TracksColumns.STARTTIME);
|
||||
boolean hasStartId = values.containsKey(TracksColumns.STARTID);
|
||||
if (!hasStartTime || !hasStartId) {
|
||||
throw new IllegalArgumentException(
|
||||
"Both start time and start id values are required.");
|
||||
}
|
||||
long rowId = db.insert(TracksColumns.TABLE_NAME, TracksColumns._ID, values);
|
||||
if (rowId > 0) {
|
||||
Uri uri = ContentUris.appendId(
|
||||
TracksColumns.CONTENT_URI.buildUpon(), rowId).build();
|
||||
getContext().getContentResolver().notifyChange(url, null, true);
|
||||
return uri;
|
||||
}
|
||||
throw new SQLException("Failed to insert row into " + url);
|
||||
}
|
||||
|
||||
private Uri insertWaypoint(Uri url, ContentValues values) {
|
||||
long rowId = db.insert(WaypointsColumns.TABLE_NAME, WaypointsColumns._ID, values);
|
||||
if (rowId > 0) {
|
||||
Uri uri = ContentUris.appendId(
|
||||
WaypointsColumns.CONTENT_URI.buildUpon(), rowId).build();
|
||||
getContext().getContentResolver().notifyChange(url, null, true);
|
||||
return uri;
|
||||
}
|
||||
throw new SQLException("Failed to insert row into " + url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(
|
||||
Uri url, String[] projection, String selection, String[] selectionArgs,
|
||||
String sort) {
|
||||
Uri url, String[] projection, String selection, String[] selectionArgs, String sort) {
|
||||
if (!canAccess()) {
|
||||
return null;
|
||||
}
|
||||
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
||||
int match = urlMatcher.match(url);
|
||||
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
|
||||
String sortOrder = null;
|
||||
if (match == TRACKPOINTS) {
|
||||
qb.setTables(TrackPointsColumns.TABLE_NAME);
|
||||
if (sort != null) {
|
||||
sortOrder = sort;
|
||||
} else {
|
||||
sortOrder = TrackPointsColumns.DEFAULT_SORT_ORDER;
|
||||
}
|
||||
} else if (match == TRACKPOINTS_ID) {
|
||||
qb.setTables(TrackPointsColumns.TABLE_NAME);
|
||||
qb.appendWhere("_id=" + url.getPathSegments().get(1));
|
||||
} else if (match == TRACKS) {
|
||||
qb.setTables(TracksColumns.TABLE_NAME);
|
||||
if (sort != null) {
|
||||
sortOrder = sort;
|
||||
} else {
|
||||
sortOrder = TracksColumns.DEFAULT_SORT_ORDER;
|
||||
}
|
||||
} else if (match == TRACKS_ID) {
|
||||
qb.setTables(TracksColumns.TABLE_NAME);
|
||||
qb.appendWhere("_id=" + url.getPathSegments().get(1));
|
||||
} else if (match == WAYPOINTS) {
|
||||
qb.setTables(WaypointsColumns.TABLE_NAME);
|
||||
if (sort != null) {
|
||||
sortOrder = sort;
|
||||
} else {
|
||||
sortOrder = WaypointsColumns.DEFAULT_SORT_ORDER;
|
||||
}
|
||||
} else if (match == WAYPOINTS_ID) {
|
||||
qb.setTables(WaypointsColumns.TABLE_NAME);
|
||||
qb.appendWhere("_id=" + url.getPathSegments().get(1));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown URL " + url);
|
||||
switch (getUrlType(url)) {
|
||||
case TRACKPOINTS:
|
||||
queryBuilder.setTables(TrackPointsColumns.TABLE_NAME);
|
||||
sortOrder = sort != null ? sort : TrackPointsColumns.DEFAULT_SORT_ORDER;
|
||||
break;
|
||||
case TRACKPOINTS_ID:
|
||||
queryBuilder.setTables(TrackPointsColumns.TABLE_NAME);
|
||||
queryBuilder.appendWhere("_id=" + url.getPathSegments().get(1));
|
||||
break;
|
||||
case TRACKS:
|
||||
queryBuilder.setTables(TracksColumns.TABLE_NAME);
|
||||
sortOrder = sort != null ? sort : TracksColumns.DEFAULT_SORT_ORDER;
|
||||
break;
|
||||
case TRACKS_ID:
|
||||
queryBuilder.setTables(TracksColumns.TABLE_NAME);
|
||||
queryBuilder.appendWhere("_id=" + url.getPathSegments().get(1));
|
||||
break;
|
||||
case WAYPOINTS:
|
||||
queryBuilder.setTables(WaypointsColumns.TABLE_NAME);
|
||||
sortOrder = sort != null ? sort : WaypointsColumns.DEFAULT_SORT_ORDER;
|
||||
break;
|
||||
case WAYPOINTS_ID:
|
||||
queryBuilder.setTables(WaypointsColumns.TABLE_NAME);
|
||||
queryBuilder.appendWhere("_id=" + url.getPathSegments().get(1));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown url " + url);
|
||||
}
|
||||
Log.i(Constants.TAG, "Build query: "
|
||||
+ qb.buildQuery(projection, selection, selectionArgs, null, null, sortOrder, null));
|
||||
|
||||
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null,
|
||||
sortOrder);
|
||||
c.setNotificationUri(getContext().getContentResolver(), url);
|
||||
return c;
|
||||
Cursor cursor = queryBuilder.query(
|
||||
db, projection, selection, selectionArgs, null, null, sortOrder);
|
||||
cursor.setNotificationUri(getContext().getContentResolver(), url);
|
||||
return cursor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(Uri url, ContentValues values, String where,
|
||||
String[] selectionArgs) {
|
||||
public int update(Uri url, ContentValues values, String where, String[] selectionArgs) {
|
||||
if (!canAccess()) {
|
||||
return 0;
|
||||
}
|
||||
String table;
|
||||
String whereClause;
|
||||
switch (getUrlType(url)) {
|
||||
case TRACKPOINTS:
|
||||
table = TrackPointsColumns.TABLE_NAME;
|
||||
whereClause = where;
|
||||
break;
|
||||
case TRACKPOINTS_ID:
|
||||
table = TrackPointsColumns.TABLE_NAME;
|
||||
whereClause = TrackPointsColumns._ID + "=" + url.getPathSegments().get(1);
|
||||
if (!TextUtils.isEmpty(where)) {
|
||||
whereClause += " AND (" + where + ")";
|
||||
}
|
||||
break;
|
||||
case TRACKS:
|
||||
table = TracksColumns.TABLE_NAME;
|
||||
whereClause = where;
|
||||
break;
|
||||
case TRACKS_ID:
|
||||
table = TracksColumns.TABLE_NAME;
|
||||
whereClause = TracksColumns._ID + "=" + url.getPathSegments().get(1);
|
||||
if (!TextUtils.isEmpty(where)) {
|
||||
whereClause += " AND (" + where + ")";
|
||||
}
|
||||
break;
|
||||
case WAYPOINTS:
|
||||
table = WaypointsColumns.TABLE_NAME;
|
||||
whereClause = where;
|
||||
break;
|
||||
case WAYPOINTS_ID:
|
||||
table = WaypointsColumns.TABLE_NAME;
|
||||
whereClause = WaypointsColumns._ID + "=" + url.getPathSegments().get(1);
|
||||
if (!TextUtils.isEmpty(where)) {
|
||||
whereClause += " AND (" + where + ")";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown url " + url);
|
||||
}
|
||||
int count;
|
||||
int match = urlMatcher.match(url);
|
||||
if (match == TRACKPOINTS) {
|
||||
count = db.update(TrackPointsColumns.TABLE_NAME, values, where, selectionArgs);
|
||||
} else if (match == TRACKPOINTS_ID) {
|
||||
String segment = url.getPathSegments().get(1);
|
||||
count = db.update(TrackPointsColumns.TABLE_NAME, values, "_id=" + segment
|
||||
+ (!TextUtils.isEmpty(where)
|
||||
? " AND (" + where + ')'
|
||||
: ""),
|
||||
selectionArgs);
|
||||
} else if (match == TRACKS) {
|
||||
count = db.update(TracksColumns.TABLE_NAME, values, where, selectionArgs);
|
||||
} else if (match == TRACKS_ID) {
|
||||
String segment = url.getPathSegments().get(1);
|
||||
count = db.update(TracksColumns.TABLE_NAME, values, "_id=" + segment
|
||||
+ (!TextUtils.isEmpty(where)
|
||||
? " AND (" + where + ')'
|
||||
: ""),
|
||||
selectionArgs);
|
||||
} else if (match == WAYPOINTS) {
|
||||
count = db.update(WaypointsColumns.TABLE_NAME, values, where, selectionArgs);
|
||||
} else if (match == WAYPOINTS_ID) {
|
||||
String segment = url.getPathSegments().get(1);
|
||||
count = db.update(WaypointsColumns.TABLE_NAME, values, "_id=" + segment
|
||||
+ (!TextUtils.isEmpty(where)
|
||||
? " AND (" + where + ')'
|
||||
: ""),
|
||||
selectionArgs);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown URL " + url);
|
||||
try {
|
||||
db.beginTransaction();
|
||||
count = db.update(table, values, whereClause, selectionArgs);
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
getContext().getContentResolver().notifyChange(url, null, true);
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the caller can access the content provider.
|
||||
*/
|
||||
private boolean canAccess() {
|
||||
if (Binder.getCallingPid() == Process.myPid()) {
|
||||
return true;
|
||||
} else {
|
||||
return PreferencesUtils.getBoolean(
|
||||
getContext(), R.string.allow_access_key, PreferencesUtils.ALLOW_ACCESS_DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link UrlType} for a url.
|
||||
*
|
||||
* @param url the url
|
||||
*/
|
||||
private UrlType getUrlType(Uri url) {
|
||||
return UrlType.values()[uriMatcher.match(url)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a content based on the url type.
|
||||
*
|
||||
* @param url the content url
|
||||
* @param urlType the url type
|
||||
* @param contentValues the content values
|
||||
*/
|
||||
private Uri insertContentValues(Uri url, UrlType urlType, ContentValues contentValues) {
|
||||
switch (urlType) {
|
||||
case TRACKPOINTS:
|
||||
return insertTrackPoint(url, contentValues);
|
||||
case TRACKS:
|
||||
return insertTrack(url, contentValues);
|
||||
case WAYPOINTS:
|
||||
return insertWaypoint(url, contentValues);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown url " + url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a track point.
|
||||
*
|
||||
* @param url the content url
|
||||
* @param values the content values
|
||||
*/
|
||||
private Uri insertTrackPoint(Uri url, ContentValues values) {
|
||||
boolean hasLatitude = values.containsKey(TrackPointsColumns.LATITUDE);
|
||||
boolean hasLongitude = values.containsKey(TrackPointsColumns.LONGITUDE);
|
||||
boolean hasTime = values.containsKey(TrackPointsColumns.TIME);
|
||||
if (!hasLatitude || !hasLongitude || !hasTime) {
|
||||
throw new IllegalArgumentException("Latitude, longitude, and time values are required.");
|
||||
}
|
||||
long rowId = db.insert(TrackPointsColumns.TABLE_NAME, TrackPointsColumns._ID, values);
|
||||
if (rowId >= 0) {
|
||||
Uri uri = ContentUris.appendId(TrackPointsColumns.CONTENT_URI.buildUpon(), rowId).build();
|
||||
getContext().getContentResolver().notifyChange(url, null, true);
|
||||
return uri;
|
||||
}
|
||||
throw new SQLiteException("Failed to insert a track point " + url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a track.
|
||||
*
|
||||
* @param url the content url
|
||||
* @param contentValues the content values
|
||||
*/
|
||||
private Uri insertTrack(Uri url, ContentValues contentValues) {
|
||||
boolean hasStartTime = contentValues.containsKey(TracksColumns.STARTTIME);
|
||||
boolean hasStartId = contentValues.containsKey(TracksColumns.STARTID);
|
||||
if (!hasStartTime || !hasStartId) {
|
||||
throw new IllegalArgumentException("Both start time and start id values are required.");
|
||||
}
|
||||
long rowId = db.insert(TracksColumns.TABLE_NAME, TracksColumns._ID, contentValues);
|
||||
if (rowId >= 0) {
|
||||
Uri uri = ContentUris.appendId(TracksColumns.CONTENT_URI.buildUpon(), rowId).build();
|
||||
getContext().getContentResolver().notifyChange(url, null, true);
|
||||
return uri;
|
||||
}
|
||||
throw new SQLException("Failed to insert a track " + url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a waypoint.
|
||||
*
|
||||
* @param url the content url
|
||||
* @param contentValues the content values
|
||||
*/
|
||||
private Uri insertWaypoint(Uri url, ContentValues contentValues) {
|
||||
long rowId = db.insert(WaypointsColumns.TABLE_NAME, WaypointsColumns._ID, contentValues);
|
||||
if (rowId >= 0) {
|
||||
Uri uri = ContentUris.appendId(WaypointsColumns.CONTENT_URI.buildUpon(), rowId).build();
|
||||
getContext().getContentResolver().notifyChange(url, null, true);
|
||||
return uri;
|
||||
}
|
||||
throw new SQLException("Failed to insert a waypoint " + url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,18 +21,14 @@ import static com.google.android.apps.mytracks.Constants.MAX_NETWORK_AGE_MS;
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
import static com.google.android.apps.mytracks.Constants.TARGET_DISPLAYED_TRACK_POINTS;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.content.DataSourceManager.DataSourceListener;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.DoubleBufferedLocationFactory;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
|
||||
import com.google.android.apps.mytracks.content.TrackDataListener.ProviderState;
|
||||
import com.google.android.apps.mytracks.content.TrackDataListeners.ListenerRegistration;
|
||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.hardware.GeomagneticField;
|
||||
import android.location.Location;
|
||||
@@ -60,54 +56,23 @@ public class TrackDataHub {
|
||||
// Overridable constants
|
||||
private final int targetNumPoints;
|
||||
|
||||
/** Types of data that we can expose. */
|
||||
public static enum ListenerDataType {
|
||||
/** Listen to when the selected track changes. */
|
||||
SELECTED_TRACK_CHANGED,
|
||||
|
||||
/** Listen to when the tracks change. */
|
||||
TRACK_UPDATES,
|
||||
|
||||
/** Listen to when the waypoints change. */
|
||||
WAYPOINT_UPDATES,
|
||||
|
||||
/** Listen to when the current track points change. */
|
||||
POINT_UPDATES,
|
||||
|
||||
/**
|
||||
* Listen to sampled-out points.
|
||||
* Listening to this without listening to {@link #POINT_UPDATES}
|
||||
* makes no sense and may yield unexpected results.
|
||||
*/
|
||||
SAMPLED_OUT_POINT_UPDATES,
|
||||
|
||||
/** Listen to updates to the current location. */
|
||||
LOCATION_UPDATES,
|
||||
|
||||
/** Listen to updates to the current heading. */
|
||||
COMPASS_UPDATES,
|
||||
|
||||
/** Listens to changes in display preferences. */
|
||||
DISPLAY_PREFERENCES;
|
||||
}
|
||||
|
||||
/** Listener which receives events from the system. */
|
||||
private class HubDataSourceListener implements DataSourceListener {
|
||||
@Override
|
||||
public void notifyTrackUpdated() {
|
||||
TrackDataHub.this.notifyTrackUpdated(getListenersFor(ListenerDataType.TRACK_UPDATES));
|
||||
public void notifyTracksTableUpdated() {
|
||||
TrackDataHub.this.notifyTrackUpdated(getListenersFor(TrackDataType.TRACKS_TABLE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyWaypointUpdated() {
|
||||
TrackDataHub.this.notifyWaypointUpdated(getListenersFor(ListenerDataType.WAYPOINT_UPDATES));
|
||||
public void notifyWaypointsTableUpdated() {
|
||||
TrackDataHub.this.notifyWaypointUpdated(getListenersFor(TrackDataType.WAYPOINTS_TABLE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyPointsUpdated() {
|
||||
public void notifyTrackPointsTableUpdated() {
|
||||
TrackDataHub.this.notifyPointsUpdated(true, 0, 0,
|
||||
getListenersFor(ListenerDataType.POINT_UPDATES),
|
||||
getListenersFor(ListenerDataType.SAMPLED_OUT_POINT_UPDATES));
|
||||
getListenersFor(TrackDataType.TRACK_POINTS_TABLE),
|
||||
getListenersFor(TrackDataType.SAMPLED_OUT_TRACK_POINTS));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -130,21 +95,20 @@ public class TrackDataHub {
|
||||
@Override
|
||||
public void notifyLocationChanged(Location loc) {
|
||||
TrackDataHub.this.notifyLocationChanged(loc,
|
||||
getListenersFor(ListenerDataType.LOCATION_UPDATES));
|
||||
getListenersFor(TrackDataType.LOCATION));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyHeadingChanged(float heading) {
|
||||
lastSeenMagneticHeading = heading;
|
||||
maybeUpdateDeclination();
|
||||
TrackDataHub.this.notifyHeadingChanged(getListenersFor(ListenerDataType.COMPASS_UPDATES));
|
||||
TrackDataHub.this.notifyHeadingChanged(getListenersFor(TrackDataType.COMPASS));
|
||||
}
|
||||
}
|
||||
|
||||
// Application services
|
||||
private final Context context;
|
||||
private final MyTracksProviderUtils providerUtils;
|
||||
private final SharedPreferences preferences;
|
||||
|
||||
// Get content notifications on the main thread, send listener callbacks in another.
|
||||
// This ensures listener calls are serialized.
|
||||
@@ -152,12 +116,9 @@ public class TrackDataHub {
|
||||
private Handler listenerHandler;
|
||||
|
||||
/** Manager for external listeners (those from activities). */
|
||||
private final TrackDataListeners dataListeners;
|
||||
private final TrackDataManager trackDataManager;
|
||||
|
||||
/** Wrapper for interacting with system data managers. */
|
||||
private DataSourcesWrapper dataSources;
|
||||
|
||||
/** Manager for system data listener registrations. */
|
||||
private DataSource dataSource;
|
||||
private DataSourceManager dataSourceManager;
|
||||
|
||||
/** Condensed listener for system data listener events. */
|
||||
@@ -193,24 +154,19 @@ public class TrackDataHub {
|
||||
* Builds a new {@link TrackDataHub} instance.
|
||||
*/
|
||||
public synchronized static TrackDataHub newInstance(Context context) {
|
||||
SharedPreferences preferences = context.getSharedPreferences(
|
||||
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||
MyTracksProviderUtils providerUtils = MyTracksProviderUtils.Factory.get(context);
|
||||
return new TrackDataHub(context,
|
||||
new TrackDataListeners(),
|
||||
preferences, providerUtils,
|
||||
TARGET_DISPLAYED_TRACK_POINTS);
|
||||
return new TrackDataHub(
|
||||
context, new TrackDataManager(), providerUtils, TARGET_DISPLAYED_TRACK_POINTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection constructor.
|
||||
*/
|
||||
// @VisibleForTesting
|
||||
TrackDataHub(Context ctx, TrackDataListeners listeners, SharedPreferences preferences,
|
||||
MyTracksProviderUtils providerUtils, int targetNumPoints) {
|
||||
TrackDataHub(Context ctx, TrackDataManager trackDataManager, MyTracksProviderUtils providerUtils,
|
||||
int targetNumPoints) {
|
||||
this.context = ctx;
|
||||
this.dataListeners = listeners;
|
||||
this.preferences = preferences;
|
||||
this.trackDataManager = trackDataManager;
|
||||
this.providerUtils = providerUtils;
|
||||
this.targetNumPoints = targetNumPoints;
|
||||
this.locationFactory = new DoubleBufferedLocationFactory();
|
||||
@@ -233,12 +189,12 @@ public class TrackDataHub {
|
||||
listenerHandlerThread = new HandlerThread("trackDataContentThread");
|
||||
listenerHandlerThread.start();
|
||||
listenerHandler = new Handler(listenerHandlerThread.getLooper());
|
||||
dataSources = newDataSources();
|
||||
dataSourceManager = new DataSourceManager(dataSourceListener, dataSources);
|
||||
dataSource = newDataSource();
|
||||
dataSourceManager = new DataSourceManager(dataSource, dataSourceListener);
|
||||
|
||||
// This may or may not register internal listeners, depending on whether
|
||||
// we already had external listeners.
|
||||
dataSourceManager.updateAllListeners(getNeededListenerTypes());
|
||||
dataSourceManager.updateListeners(getNeededListenerTypes());
|
||||
loadSharedPreferences();
|
||||
|
||||
// If there were listeners already registered, make sure they become up-to-date.
|
||||
@@ -246,8 +202,8 @@ public class TrackDataHub {
|
||||
}
|
||||
|
||||
// @VisibleForTesting
|
||||
protected DataSourcesWrapper newDataSources() {
|
||||
return new DataSourcesWrapperImpl(context, preferences);
|
||||
protected DataSource newDataSource() {
|
||||
return new DataSource(context);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -267,7 +223,7 @@ public class TrackDataHub {
|
||||
|
||||
started = false;
|
||||
|
||||
dataSources = null;
|
||||
dataSource = null;
|
||||
dataSourceManager = null;
|
||||
listenerHandlerThread = null;
|
||||
listenerHandler = null;
|
||||
@@ -343,9 +299,9 @@ public class TrackDataHub {
|
||||
}
|
||||
Log.i(TAG, "Forcing location update");
|
||||
|
||||
Location loc = dataSources.getLastKnownLocation();
|
||||
Location loc = dataSource.getLastKnownLocation();
|
||||
if (loc != null) {
|
||||
notifyLocationChanged(loc, getListenersFor(ListenerDataType.LOCATION_UPDATES));
|
||||
notifyLocationChanged(loc, getListenersFor(TrackDataType.LOCATION));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,30 +371,31 @@ public class TrackDataHub {
|
||||
}
|
||||
|
||||
public void registerTrackDataListener(
|
||||
TrackDataListener listener, EnumSet<ListenerDataType> dataTypes) {
|
||||
synchronized (dataListeners) {
|
||||
ListenerRegistration registration =
|
||||
dataListeners.registerTrackDataListener(listener, dataTypes);
|
||||
TrackDataListener listener, EnumSet<TrackDataType> dataTypes) {
|
||||
synchronized (trackDataManager) {
|
||||
ListenerState listenerState = trackDataManager.registerListener(listener, dataTypes);
|
||||
|
||||
// Don't load any data or start internal listeners if start() hasn't been
|
||||
// called. When it is called, we'll do both things.
|
||||
if (!isStarted()) return;
|
||||
if (!isStarted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadNewDataForListener(registration);
|
||||
loadNewDataForListener(listenerState);
|
||||
|
||||
dataSourceManager.updateAllListeners(getNeededListenerTypes());
|
||||
dataSourceManager.updateListeners(getNeededListenerTypes());
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterTrackDataListener(TrackDataListener listener) {
|
||||
synchronized (dataListeners) {
|
||||
dataListeners.unregisterTrackDataListener(listener);
|
||||
synchronized (trackDataManager) {
|
||||
trackDataManager.unregisterListener(listener);
|
||||
|
||||
// Don't load any data or start internal listeners if start() hasn't been
|
||||
// called. When it is called, we'll do both things.
|
||||
if (!isStarted()) return;
|
||||
|
||||
dataSourceManager.updateAllListeners(getNeededListenerTypes());
|
||||
dataSourceManager.updateListeners(getNeededListenerTypes());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,33 +403,32 @@ public class TrackDataHub {
|
||||
* Reloads all track data received so far into the specified listeners.
|
||||
*/
|
||||
public void reloadDataForListener(TrackDataListener listener) {
|
||||
ListenerRegistration registration;
|
||||
synchronized (dataListeners) {
|
||||
registration = dataListeners.getRegistration(listener);
|
||||
registration.resetState();
|
||||
loadNewDataForListener(registration);
|
||||
synchronized (trackDataManager) {
|
||||
ListenerState listenerState = trackDataManager.getListenerState(listener);
|
||||
listenerState.resetState();
|
||||
loadNewDataForListener(listenerState);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads all track data received so far into the specified listeners.
|
||||
*
|
||||
* Assumes it's called from a block that synchronizes on {@link #dataListeners}.
|
||||
* Assumes it's called from a block that synchronizes on {@link #trackDataManager}.
|
||||
*/
|
||||
private void loadNewDataForListener(final ListenerRegistration registration) {
|
||||
private void loadNewDataForListener(final ListenerState listenerState) {
|
||||
if (!isStarted()) {
|
||||
Log.w(TAG, "Not started, not reloading");
|
||||
return;
|
||||
}
|
||||
if (registration == null) {
|
||||
Log.w(TAG, "Not reloading for null registration");
|
||||
if (listenerState == null) {
|
||||
Log.w(TAG, "Not reloading for null listener state");
|
||||
return;
|
||||
}
|
||||
|
||||
// If a listener happens to be added after this method but before the Runnable below is
|
||||
// executed, it will have triggered a separate call to load data only up to the point this
|
||||
// listener got to. This is ensured by being synchronized on listeners.
|
||||
final boolean isOnlyListener = (dataListeners.getNumListeners() == 1);
|
||||
final boolean isOnlyListener = (trackDataManager.getNumberOfListeners() == 1);
|
||||
|
||||
runInListenerThread(new Runnable() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -480,30 +436,31 @@ public class TrackDataHub {
|
||||
public void run() {
|
||||
// Reload everything if either it's a different track, or the track has been resampled
|
||||
// (this also covers the case of a new registration).
|
||||
boolean reloadAll = registration.lastTrackId != selectedTrackId ||
|
||||
registration.lastSamplingFrequency != lastSamplingFrequency;
|
||||
Log.d(TAG, "Doing a " + (reloadAll ? "full" : "partial") + " reload for " + registration);
|
||||
boolean reloadAll = listenerState.getLastTrackId() != selectedTrackId ||
|
||||
listenerState.getLastSamplingFrequency() != lastSamplingFrequency;
|
||||
Log.d(TAG, "Doing a " + (reloadAll ? "full" : "partial") + " reload for " + listenerState);
|
||||
|
||||
TrackDataListener listener = registration.listener;
|
||||
TrackDataListener listener = listenerState.getTrackDataListener();
|
||||
Set<TrackDataListener> listenerSet = Collections.singleton(listener);
|
||||
|
||||
if (registration.isInterestedIn(ListenerDataType.DISPLAY_PREFERENCES)) {
|
||||
EnumSet<TrackDataType> trackDataTypes = listenerState.getTrackDataTypes();
|
||||
|
||||
if (trackDataTypes.contains(TrackDataType.PREFERENCE)) {
|
||||
reloadAll |= listener.onUnitsChanged(metricUnits);
|
||||
reloadAll |= listener.onReportSpeedChanged(reportSpeed);
|
||||
}
|
||||
|
||||
if (reloadAll && registration.isInterestedIn(ListenerDataType.SELECTED_TRACK_CHANGED)) {
|
||||
if (reloadAll && trackDataTypes.contains(TrackDataType.SELECTED_TRACK)) {
|
||||
notifySelectedTrackChanged(selectedTrackId, listenerSet);
|
||||
}
|
||||
|
||||
if (registration.isInterestedIn(ListenerDataType.TRACK_UPDATES)) {
|
||||
if (trackDataTypes.contains(TrackDataType.TRACKS_TABLE)) {
|
||||
notifyTrackUpdated(listenerSet);
|
||||
}
|
||||
|
||||
boolean interestedInPoints =
|
||||
registration.isInterestedIn(ListenerDataType.POINT_UPDATES);
|
||||
boolean interestedInSampledOutPoints =
|
||||
registration.isInterestedIn(ListenerDataType.SAMPLED_OUT_POINT_UPDATES);
|
||||
boolean interestedInPoints = trackDataTypes.contains(TrackDataType.TRACK_POINTS_TABLE);
|
||||
boolean interestedInSampledOutPoints = trackDataTypes.contains(
|
||||
TrackDataType.SAMPLED_OUT_TRACK_POINTS);
|
||||
if (interestedInPoints || interestedInSampledOutPoints) {
|
||||
long minPointId = 0;
|
||||
int previousNumPoints = 0;
|
||||
@@ -513,8 +470,8 @@ public class TrackDataHub {
|
||||
notifyPointsCleared(listenerSet);
|
||||
} else {
|
||||
// Send only new points
|
||||
minPointId = registration.lastPointId + 1;
|
||||
previousNumPoints = registration.numLoadedPoints;
|
||||
minPointId = listenerState.getLastPointId() + 1;
|
||||
previousNumPoints = listenerState.getNumberOfLoadedPoints();
|
||||
}
|
||||
|
||||
// If this is the only listener we have registered, keep the state that we serve to it as
|
||||
@@ -530,11 +487,11 @@ public class TrackDataHub {
|
||||
interestedInSampledOutPoints ? listenerSet : Collections.EMPTY_SET);
|
||||
}
|
||||
|
||||
if (registration.isInterestedIn(ListenerDataType.WAYPOINT_UPDATES)) {
|
||||
if (trackDataTypes.contains(TrackDataType.WAYPOINTS_TABLE)) {
|
||||
notifyWaypointUpdated(listenerSet);
|
||||
}
|
||||
|
||||
if (registration.isInterestedIn(ListenerDataType.LOCATION_UPDATES)) {
|
||||
if (trackDataTypes.contains(TrackDataType.LOCATION)) {
|
||||
if (lastSeenLocation != null) {
|
||||
notifyLocationChanged(lastSeenLocation, true, listenerSet);
|
||||
} else {
|
||||
@@ -542,7 +499,7 @@ public class TrackDataHub {
|
||||
}
|
||||
}
|
||||
|
||||
if (registration.isInterestedIn(ListenerDataType.COMPASS_UPDATES)) {
|
||||
if (trackDataTypes.contains(TrackDataType.COMPASS)) {
|
||||
notifyHeadingChanged(listenerSet);
|
||||
}
|
||||
}
|
||||
@@ -557,8 +514,8 @@ public class TrackDataHub {
|
||||
Log.w(TAG, "Not started, not reloading");
|
||||
return;
|
||||
}
|
||||
synchronized (dataListeners) {
|
||||
if (!dataListeners.hasListeners()) {
|
||||
synchronized (trackDataManager) {
|
||||
if (trackDataManager.getNumberOfListeners() == 0) {
|
||||
Log.d(TAG, "No listeners, not reloading");
|
||||
return;
|
||||
}
|
||||
@@ -569,33 +526,33 @@ public class TrackDataHub {
|
||||
public void run() {
|
||||
// Ignore the return values here, we're already sending the full data set anyway
|
||||
for (TrackDataListener listener :
|
||||
getListenersFor(ListenerDataType.DISPLAY_PREFERENCES)) {
|
||||
getListenersFor(TrackDataType.PREFERENCE)) {
|
||||
listener.onUnitsChanged(metricUnits);
|
||||
listener.onReportSpeedChanged(reportSpeed);
|
||||
}
|
||||
|
||||
notifySelectedTrackChanged(selectedTrackId,
|
||||
getListenersFor(ListenerDataType.SELECTED_TRACK_CHANGED));
|
||||
getListenersFor(TrackDataType.SELECTED_TRACK));
|
||||
|
||||
notifyTrackUpdated(getListenersFor(ListenerDataType.TRACK_UPDATES));
|
||||
notifyTrackUpdated(getListenersFor(TrackDataType.TRACKS_TABLE));
|
||||
|
||||
Set<TrackDataListener> pointListeners =
|
||||
getListenersFor(ListenerDataType.POINT_UPDATES);
|
||||
getListenersFor(TrackDataType.TRACK_POINTS_TABLE);
|
||||
Set<TrackDataListener> sampledOutPointListeners =
|
||||
getListenersFor(ListenerDataType.SAMPLED_OUT_POINT_UPDATES);
|
||||
getListenersFor(TrackDataType.SAMPLED_OUT_TRACK_POINTS);
|
||||
notifyPointsCleared(pointListeners);
|
||||
notifyPointsUpdated(true, 0, 0, pointListeners, sampledOutPointListeners);
|
||||
|
||||
notifyWaypointUpdated(getListenersFor(ListenerDataType.WAYPOINT_UPDATES));
|
||||
notifyWaypointUpdated(getListenersFor(TrackDataType.WAYPOINTS_TABLE));
|
||||
|
||||
if (lastSeenLocation != null) {
|
||||
notifyLocationChanged(lastSeenLocation, true,
|
||||
getListenersFor(ListenerDataType.LOCATION_UPDATES));
|
||||
getListenersFor(TrackDataType.LOCATION));
|
||||
} else {
|
||||
notifyFixType();
|
||||
}
|
||||
|
||||
notifyHeadingChanged(getListenersFor(ListenerDataType.COMPASS_UPDATES));
|
||||
notifyHeadingChanged(getListenersFor(TrackDataType.COMPASS));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -630,12 +587,12 @@ public class TrackDataHub {
|
||||
@Override
|
||||
public void run() {
|
||||
Set<TrackDataListener> displayListeners =
|
||||
getListenersFor(ListenerDataType.DISPLAY_PREFERENCES);
|
||||
getListenersFor(TrackDataType.PREFERENCE);
|
||||
|
||||
for (TrackDataListener listener : displayListeners) {
|
||||
// TODO: Do the reloading just once for all interested listeners
|
||||
if (listener.onReportSpeedChanged(reportSpeed)) {
|
||||
synchronized (dataListeners) {
|
||||
synchronized (trackDataManager) {
|
||||
reloadDataForListener(listener);
|
||||
}
|
||||
}
|
||||
@@ -651,11 +608,11 @@ public class TrackDataHub {
|
||||
runInListenerThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Set<TrackDataListener> displayListeners = getListenersFor(ListenerDataType.DISPLAY_PREFERENCES);
|
||||
Set<TrackDataListener> displayListeners = getListenersFor(TrackDataType.PREFERENCE);
|
||||
|
||||
for (TrackDataListener listener : displayListeners) {
|
||||
if (listener.onUnitsChanged(metricUnits)) {
|
||||
synchronized (dataListeners) {
|
||||
synchronized (trackDataManager) {
|
||||
reloadDataForListener(listener);
|
||||
}
|
||||
}
|
||||
@@ -683,7 +640,7 @@ public class TrackDataHub {
|
||||
// Notify to everyone.
|
||||
Log.d(TAG, "Notifying fix type: " + state);
|
||||
for (TrackDataListener listener :
|
||||
getListenersFor(ListenerDataType.LOCATION_UPDATES)) {
|
||||
getListenersFor(TrackDataType.LOCATION)) {
|
||||
listener.onProviderStateChange(state);
|
||||
}
|
||||
}
|
||||
@@ -945,9 +902,9 @@ public class TrackDataHub {
|
||||
|
||||
Log.i(TAG, "Resampling point set after " + numLoadedPoints + " points.");
|
||||
resetState();
|
||||
synchronized (dataListeners) {
|
||||
sampledListeners = getListenersFor(ListenerDataType.POINT_UPDATES);
|
||||
sampledOutListeners = getListenersFor(ListenerDataType.SAMPLED_OUT_POINT_UPDATES);
|
||||
synchronized (trackDataManager) {
|
||||
sampledListeners = getListenersFor(TrackDataType.TRACK_POINTS_TABLE);
|
||||
sampledOutListeners = getListenersFor(TrackDataType.SAMPLED_OUT_TRACK_POINTS);
|
||||
}
|
||||
maxPointId = -1;
|
||||
minPointId = 0;
|
||||
@@ -1030,12 +987,10 @@ public class TrackDataHub {
|
||||
listener.onNewTrackPointsDone();
|
||||
|
||||
// Update the listener state
|
||||
ListenerRegistration registration = dataListeners.getRegistration(listener);
|
||||
if (registration != null) {
|
||||
registration.lastTrackId = currentSelectedTrackId;
|
||||
registration.lastPointId = localLastSeenLocationId;
|
||||
registration.lastSamplingFrequency = pointSamplingFrequency;
|
||||
registration.numLoadedPoints = localNumLoadedPoints;
|
||||
ListenerState listenerState = trackDataManager.getListenerState(listener);
|
||||
if (listenerState != null) {
|
||||
listenerState.setState(currentSelectedTrackId, localLastSeenLocationId,
|
||||
pointSamplingFrequency, localNumLoadedPoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1089,17 +1044,17 @@ public class TrackDataHub {
|
||||
listenerHandler.post(runnable);
|
||||
}
|
||||
|
||||
private Set<TrackDataListener> getListenersFor(ListenerDataType type) {
|
||||
synchronized (dataListeners) {
|
||||
return dataListeners.getListenersFor(type);
|
||||
private Set<TrackDataListener> getListenersFor(TrackDataType type) {
|
||||
synchronized (trackDataManager) {
|
||||
return trackDataManager.getListeners(type);
|
||||
}
|
||||
}
|
||||
|
||||
private EnumSet<ListenerDataType> getNeededListenerTypes() {
|
||||
EnumSet<ListenerDataType> neededTypes = dataListeners.getAllRegisteredTypes();
|
||||
private EnumSet<TrackDataType> getNeededListenerTypes() {
|
||||
EnumSet<TrackDataType> neededTypes = trackDataManager.getRegisteredTrackDataTypes();
|
||||
|
||||
// We always want preference updates.
|
||||
neededTypes.add(ListenerDataType.DISPLAY_PREFERENCES);
|
||||
neededTypes.add(TrackDataType.PREFERENCE);
|
||||
|
||||
return neededTypes;
|
||||
}
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 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.apps.mytracks.content;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Manager for the external data listeners and their listening types.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
class TrackDataListeners {
|
||||
|
||||
/** Internal representation of a listener's registration. */
|
||||
static class ListenerRegistration {
|
||||
final TrackDataListener listener;
|
||||
final EnumSet<ListenerDataType> types;
|
||||
|
||||
// State that was last notified to the listener, for resuming after a pause.
|
||||
long lastTrackId;
|
||||
long lastPointId;
|
||||
int lastSamplingFrequency;
|
||||
int numLoadedPoints;
|
||||
|
||||
public ListenerRegistration(TrackDataListener listener,
|
||||
EnumSet<ListenerDataType> types) {
|
||||
this.listener = listener;
|
||||
this.types = types;
|
||||
}
|
||||
|
||||
public boolean isInterestedIn(ListenerDataType type) {
|
||||
return types.contains(type);
|
||||
}
|
||||
|
||||
public void resetState() {
|
||||
lastTrackId = 0L;
|
||||
lastPointId = 0L;
|
||||
lastSamplingFrequency = 0;
|
||||
numLoadedPoints = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ListenerRegistration [listener=" + listener + ", types=" + types
|
||||
+ ", lastTrackId=" + lastTrackId + ", lastPointId=" + lastPointId
|
||||
+ ", lastSamplingFrequency=" + lastSamplingFrequency
|
||||
+ ", numLoadedPoints=" + numLoadedPoints + "]";
|
||||
}
|
||||
}
|
||||
|
||||
/** Map of external listener to its registration details. */
|
||||
private final Map<TrackDataListener, ListenerRegistration> registeredListeners =
|
||||
new HashMap<TrackDataListener, ListenerRegistration>();
|
||||
|
||||
/** Map of data type to external listeners interested in it. */
|
||||
private final Map<ListenerDataType, Set<TrackDataListener>> listenerSetsPerType =
|
||||
new EnumMap<ListenerDataType, Set<TrackDataListener>>(ListenerDataType.class);
|
||||
|
||||
public TrackDataListeners() {
|
||||
// Create sets for all data types at startup.
|
||||
for (ListenerDataType type : ListenerDataType.values()) {
|
||||
listenerSetsPerType.put(type, new LinkedHashSet<TrackDataListener>());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a listener to send data to.
|
||||
* It is ok to call this method before {@link TrackDataHub#start}, and in that case
|
||||
* the data will only be passed to listeners when {@link TrackDataHub#start} is called.
|
||||
*
|
||||
* @param listener the listener to register
|
||||
* @param dataTypes the type of data that the listener is interested in
|
||||
*/
|
||||
public ListenerRegistration registerTrackDataListener(final TrackDataListener listener, EnumSet<ListenerDataType> dataTypes) {
|
||||
Log.d(TAG, "Registered track data listener: " + listener);
|
||||
if (registeredListeners.containsKey(listener)) {
|
||||
throw new IllegalStateException("Listener already registered");
|
||||
}
|
||||
|
||||
ListenerRegistration registration = new ListenerRegistration(listener, dataTypes);
|
||||
registeredListeners.put(listener, registration);
|
||||
|
||||
for (ListenerDataType type : dataTypes) {
|
||||
// This is guaranteed not to be null.
|
||||
Set<TrackDataListener> typeSet = listenerSetsPerType.get(type);
|
||||
typeSet.add(listener);
|
||||
}
|
||||
|
||||
return registration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a listener to send data to.
|
||||
*
|
||||
* @param listener the listener to unregister
|
||||
*/
|
||||
public void unregisterTrackDataListener(TrackDataListener listener) {
|
||||
Log.d(TAG, "Unregistered track data listener: " + listener);
|
||||
// Remove and keep the corresponding registration.
|
||||
ListenerRegistration match = registeredListeners.remove(listener);
|
||||
if (match == null) {
|
||||
Log.w(TAG, "Tried to unregister listener which is not registered.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove it from the per-type sets
|
||||
for (ListenerDataType type : match.types) {
|
||||
listenerSetsPerType.get(type).remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public ListenerRegistration getRegistration(TrackDataListener listener) {
|
||||
return registeredListeners.get(listener);
|
||||
}
|
||||
|
||||
public Set<TrackDataListener> getListenersFor(ListenerDataType type) {
|
||||
return listenerSetsPerType.get(type);
|
||||
}
|
||||
|
||||
public EnumSet<ListenerDataType> getAllRegisteredTypes() {
|
||||
EnumSet<ListenerDataType> listeners = EnumSet.noneOf(ListenerDataType.class);
|
||||
for (ListenerRegistration registration : this.registeredListeners.values()) {
|
||||
listeners.addAll(registration.types);
|
||||
}
|
||||
return listeners;
|
||||
}
|
||||
|
||||
public boolean hasListeners() {
|
||||
return !registeredListeners.isEmpty();
|
||||
}
|
||||
|
||||
public int getNumListeners() {
|
||||
return registeredListeners.size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2011 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.apps.mytracks.content;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Manages register/unregister {@link TrackDataListener} and keeping the state
|
||||
* for each registered listener.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class TrackDataManager {
|
||||
|
||||
// Map of listener to its state
|
||||
private final Map<TrackDataListener, ListenerState>
|
||||
listenerToStateMap = new HashMap<TrackDataListener, ListenerState>();
|
||||
|
||||
// Map of track data type to listeners
|
||||
private final Map<TrackDataType, Set<TrackDataListener>>
|
||||
typeToListenersMap = new EnumMap<TrackDataType, Set<TrackDataListener>>(TrackDataType.class);
|
||||
|
||||
public TrackDataManager() {
|
||||
for (TrackDataType trackDataType : TrackDataType.values()) {
|
||||
typeToListenersMap.put(trackDataType, new LinkedHashSet<TrackDataListener>());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a listener.
|
||||
*
|
||||
* @param listener the listener
|
||||
* @param trackDataTypes the track data types the listener is interested
|
||||
*/
|
||||
public ListenerState registerListener(
|
||||
TrackDataListener listener, EnumSet<TrackDataType> trackDataTypes) {
|
||||
if (listenerToStateMap.containsKey(listener)) {
|
||||
throw new IllegalStateException("Listener is already registered");
|
||||
}
|
||||
|
||||
ListenerState listenerState = new ListenerState(listener, trackDataTypes);
|
||||
listenerToStateMap.put(listener, listenerState);
|
||||
|
||||
for (TrackDataType trackDataType : trackDataTypes) {
|
||||
typeToListenersMap.get(trackDataType).add(listener);
|
||||
}
|
||||
|
||||
return listenerState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a listener.
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
public void unregisterListener(TrackDataListener listener) {
|
||||
ListenerState removed = listenerToStateMap.remove(listener);
|
||||
if (removed == null) {
|
||||
Log.w(TAG, "Tried to unregister a listener that is not registered.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the listener from the typeToListenersMap
|
||||
for (TrackDataType trackDataType : removed.getTrackDataTypes()) {
|
||||
typeToListenersMap.get(trackDataType).remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of {@link TrackDataListener}.
|
||||
*/
|
||||
public int getNumberOfListeners() {
|
||||
return listenerToStateMap.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the track listener state.
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
public ListenerState getListenerState(TrackDataListener listener) {
|
||||
return listenerToStateMap.get(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the listeners for a {@link TrackDataType}.
|
||||
*
|
||||
* @param type the type
|
||||
*/
|
||||
public Set<TrackDataListener> getListeners(TrackDataType type) {
|
||||
return typeToListenersMap.get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the registered {@link TrackDataType}.
|
||||
*/
|
||||
public EnumSet<TrackDataType> getRegisteredTrackDataTypes() {
|
||||
EnumSet<TrackDataType> types = EnumSet.noneOf(TrackDataType.class);
|
||||
for (ListenerState registration : this.listenerToStateMap.values()) {
|
||||
types.addAll(registration.getTrackDataTypes());
|
||||
}
|
||||
return types;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2011 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.apps.mytracks.content;
|
||||
|
||||
/**
|
||||
* Types of track data.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public enum TrackDataType {
|
||||
|
||||
SELECTED_TRACK, // selected track changes
|
||||
TRACKS_TABLE, // tracks table changes
|
||||
WAYPOINTS_TABLE, // waypoints table changes
|
||||
TRACK_POINTS_TABLE, // track points table changes
|
||||
SAMPLED_OUT_TRACK_POINTS, // sampled-out track points changes
|
||||
LOCATION, // location changes
|
||||
COMPASS, // compass changes
|
||||
PREFERENCE; // preference changes
|
||||
}
|
||||
@@ -19,12 +19,12 @@ package com.google.android.apps.mytracks.fragments;
|
||||
import com.google.android.apps.mytracks.ChartView;
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.MyTracksApplication;
|
||||
import com.google.android.apps.mytracks.content.TrackDataType;
|
||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TrackDataHub;
|
||||
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
|
||||
import com.google.android.apps.mytracks.content.TrackDataListener;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.stats.DoubleBuffer;
|
||||
@@ -360,12 +360,12 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
private synchronized void resumeTrackDataHub() {
|
||||
trackDataHub = ((MyTracksApplication) getActivity().getApplication()).getTrackDataHub();
|
||||
trackDataHub.registerTrackDataListener(this, EnumSet.of(
|
||||
ListenerDataType.SELECTED_TRACK_CHANGED,
|
||||
ListenerDataType.TRACK_UPDATES,
|
||||
ListenerDataType.WAYPOINT_UPDATES,
|
||||
ListenerDataType.POINT_UPDATES,
|
||||
ListenerDataType.SAMPLED_OUT_POINT_UPDATES,
|
||||
ListenerDataType.DISPLAY_PREFERENCES));
|
||||
TrackDataType.SELECTED_TRACK,
|
||||
TrackDataType.TRACKS_TABLE,
|
||||
TrackDataType.WAYPOINTS_TABLE,
|
||||
TrackDataType.TRACK_POINTS_TABLE,
|
||||
TrackDataType.SAMPLED_OUT_TRACK_POINTS,
|
||||
TrackDataType.PREFERENCE));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,11 +19,11 @@ package com.google.android.apps.mytracks.fragments;
|
||||
import com.google.android.apps.mytracks.MapOverlay;
|
||||
import com.google.android.apps.mytracks.MyTracksApplication;
|
||||
import com.google.android.apps.mytracks.TrackDetailActivity;
|
||||
import com.google.android.apps.mytracks.content.TrackDataType;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TrackDataHub;
|
||||
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
|
||||
import com.google.android.apps.mytracks.content.TrackDataListener;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
@@ -420,11 +420,11 @@ public class MapFragment extends Fragment
|
||||
private synchronized void resumeTrackDataHub() {
|
||||
trackDataHub = ((MyTracksApplication) getActivity().getApplication()).getTrackDataHub();
|
||||
trackDataHub.registerTrackDataListener(this, EnumSet.of(
|
||||
ListenerDataType.SELECTED_TRACK_CHANGED,
|
||||
ListenerDataType.WAYPOINT_UPDATES,
|
||||
ListenerDataType.POINT_UPDATES,
|
||||
ListenerDataType.LOCATION_UPDATES,
|
||||
ListenerDataType.COMPASS_UPDATES));
|
||||
TrackDataType.SELECTED_TRACK,
|
||||
TrackDataType.WAYPOINTS_TABLE,
|
||||
TrackDataType.TRACK_POINTS_TABLE,
|
||||
TrackDataType.LOCATION,
|
||||
TrackDataType.COMPASS));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
package com.google.android.apps.mytracks.fragments;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracksApplication;
|
||||
import com.google.android.apps.mytracks.content.TrackDataType;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TrackDataHub;
|
||||
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
|
||||
import com.google.android.apps.mytracks.content.TrackDataListener;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
@@ -257,10 +257,10 @@ public class StatsFragment extends Fragment implements TrackDataListener {
|
||||
private synchronized void resumeTrackDataHub() {
|
||||
trackDataHub = ((MyTracksApplication) getActivity().getApplication()).getTrackDataHub();
|
||||
trackDataHub.registerTrackDataListener(this, EnumSet.of(
|
||||
ListenerDataType.SELECTED_TRACK_CHANGED,
|
||||
ListenerDataType.TRACK_UPDATES,
|
||||
ListenerDataType.LOCATION_UPDATES,
|
||||
ListenerDataType.DISPLAY_PREFERENCES));
|
||||
TrackDataType.SELECTED_TRACK,
|
||||
TrackDataType.TRACKS_TABLE,
|
||||
TrackDataType.LOCATION,
|
||||
TrackDataType.PREFERENCE));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,11 +27,9 @@ import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
|
||||
import com.google.android.apps.mytracks.content.WaypointCreationRequest.WaypointType;
|
||||
import com.google.android.apps.mytracks.content.WaypointsColumns;
|
||||
import com.google.android.apps.mytracks.services.sensors.SensorManager;
|
||||
import com.google.android.apps.mytracks.services.sensors.SensorManagerFactory;
|
||||
import com.google.android.apps.mytracks.services.tasks.PeriodicTaskExecutor;
|
||||
@@ -49,7 +47,6 @@ import com.google.common.annotations.VisibleForTesting;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
@@ -836,35 +833,17 @@ public class TrackRecordingService extends Service {
|
||||
int pointId = Integer.parseInt(pointUri.getLastPathSegment());
|
||||
|
||||
// Update the current track:
|
||||
if (lastRecordedLocation != null
|
||||
&& lastRecordedLocation.getLatitude() < 90) {
|
||||
ContentValues values = new ContentValues();
|
||||
TripStatistics stats = statsBuilder.getStatistics();
|
||||
if (lastRecordedLocation != null && lastRecordedLocation.getLatitude() < 90) {
|
||||
TripStatistics tripStatistics = statsBuilder.getStatistics();
|
||||
tripStatistics.setStopTime(System.currentTimeMillis());
|
||||
|
||||
if (recordingTrack.getStartId() < 0) {
|
||||
values.put(TracksColumns.STARTID, pointId);
|
||||
recordingTrack.setStartId(pointId);
|
||||
}
|
||||
values.put(TracksColumns.STOPID, pointId);
|
||||
values.put(TracksColumns.STOPTIME, System.currentTimeMillis());
|
||||
values.put(TracksColumns.NUMPOINTS,
|
||||
recordingTrack.getNumberOfPoints() + 1);
|
||||
values.put(TracksColumns.MINLAT, stats.getBottom());
|
||||
values.put(TracksColumns.MAXLAT, stats.getTop());
|
||||
values.put(TracksColumns.MINLON, stats.getLeft());
|
||||
values.put(TracksColumns.MAXLON, stats.getRight());
|
||||
values.put(TracksColumns.TOTALDISTANCE, stats.getTotalDistance());
|
||||
values.put(TracksColumns.TOTALTIME, stats.getTotalTime());
|
||||
values.put(TracksColumns.MOVINGTIME, stats.getMovingTime());
|
||||
values.put(TracksColumns.AVGSPEED, stats.getAverageSpeed());
|
||||
values.put(TracksColumns.AVGMOVINGSPEED, stats.getAverageMovingSpeed());
|
||||
values.put(TracksColumns.MAXSPEED, stats.getMaxSpeed());
|
||||
values.put(TracksColumns.MINELEVATION, stats.getMinElevation());
|
||||
values.put(TracksColumns.MAXELEVATION, stats.getMaxElevation());
|
||||
values.put(TracksColumns.ELEVATIONGAIN, stats.getTotalElevationGain());
|
||||
values.put(TracksColumns.MINGRADE, stats.getMinGrade());
|
||||
values.put(TracksColumns.MAXGRADE, stats.getMaxGrade());
|
||||
getContentResolver().update(TracksColumns.CONTENT_URI,
|
||||
values, "_id=" + recordingTrack.getId(), null);
|
||||
recordingTrack.setStopId(pointId);
|
||||
recordingTrack.setNumberOfPoints(recordingTrack.getNumberOfPoints() + 1);
|
||||
recordingTrack.setTripStatistics(tripStatistics);
|
||||
providerUtils.updateTrack(recordingTrack);
|
||||
updateCurrentWaypoint();
|
||||
}
|
||||
} catch (SQLiteException e) {
|
||||
@@ -882,30 +861,14 @@ public class TrackRecordingService extends Service {
|
||||
|
||||
private void updateCurrentWaypoint() {
|
||||
if (currentWaypointId >= 0) {
|
||||
ContentValues values = new ContentValues();
|
||||
TripStatistics waypointStats = waypointStatsBuilder.getStatistics();
|
||||
values.put(WaypointsColumns.STARTTIME, waypointStats.getStartTime());
|
||||
values.put(WaypointsColumns.LENGTH, length);
|
||||
values.put(WaypointsColumns.DURATION, System.currentTimeMillis()
|
||||
- statsBuilder.getStatistics().getStartTime());
|
||||
values.put(WaypointsColumns.TOTALDISTANCE,
|
||||
waypointStats.getTotalDistance());
|
||||
values.put(WaypointsColumns.TOTALTIME, waypointStats.getTotalTime());
|
||||
values.put(WaypointsColumns.MOVINGTIME, waypointStats.getMovingTime());
|
||||
values.put(WaypointsColumns.AVGSPEED, waypointStats.getAverageSpeed());
|
||||
values.put(WaypointsColumns.AVGMOVINGSPEED,
|
||||
waypointStats.getAverageMovingSpeed());
|
||||
values.put(WaypointsColumns.MAXSPEED, waypointStats.getMaxSpeed());
|
||||
values.put(WaypointsColumns.MINELEVATION,
|
||||
waypointStats.getMinElevation());
|
||||
values.put(WaypointsColumns.MAXELEVATION,
|
||||
waypointStats.getMaxElevation());
|
||||
values.put(WaypointsColumns.ELEVATIONGAIN,
|
||||
waypointStats.getTotalElevationGain());
|
||||
values.put(WaypointsColumns.MINGRADE, waypointStats.getMinGrade());
|
||||
values.put(WaypointsColumns.MAXGRADE, waypointStats.getMaxGrade());
|
||||
getContentResolver().update(WaypointsColumns.CONTENT_URI,
|
||||
values, "_id=" + currentWaypointId, null);
|
||||
Waypoint waypoint = providerUtils.getWaypoint(currentWaypointId);
|
||||
if (waypoint != null) {
|
||||
waypoint.setLength(length);
|
||||
waypoint.setDuration(
|
||||
System.currentTimeMillis() - statsBuilder.getStatistics().getStartTime());
|
||||
waypoint.setTripStatistics(waypointStatsBuilder.getStatistics());
|
||||
providerUtils.updateWaypoint(waypoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1031,19 +994,14 @@ public class TrackRecordingService extends Service {
|
||||
isRecording = false;
|
||||
Track recordedTrack = providerUtils.getTrack(recordingTrackId);
|
||||
if (recordedTrack != null) {
|
||||
TripStatistics stats = recordedTrack.getTripStatistics();
|
||||
stats.setStopTime(System.currentTimeMillis());
|
||||
stats.setTotalTime(stats.getStopTime() - stats.getStartTime());
|
||||
long lastRecordedLocationId =
|
||||
providerUtils.getLastLocationId(recordingTrackId);
|
||||
ContentValues values = new ContentValues();
|
||||
long lastRecordedLocationId = providerUtils.getLastLocationId(recordingTrackId);
|
||||
if (lastRecordedLocationId >= 0 && recordedTrack.getStopId() >= 0) {
|
||||
values.put(TracksColumns.STOPID, lastRecordedLocationId);
|
||||
recordedTrack.setStopId(lastRecordedLocationId);
|
||||
}
|
||||
values.put(TracksColumns.STOPTIME, stats.getStopTime());
|
||||
values.put(TracksColumns.TOTALTIME, stats.getTotalTime());
|
||||
getContentResolver().update(TracksColumns.CONTENT_URI, values,
|
||||
"_id=" + recordedTrack.getId(), null);
|
||||
TripStatistics tripStatistics = recordedTrack.getTripStatistics();
|
||||
tripStatistics.setStopTime(System.currentTimeMillis());
|
||||
tripStatistics.setTotalTime(tripStatistics.getStopTime() - tripStatistics.getStartTime());
|
||||
providerUtils.updateTrack(recordedTrack);
|
||||
}
|
||||
showNotification();
|
||||
long recordedTrackId = recordingTrackId;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#Fri Oct 21 20:06:28 BRST 2011
|
||||
#Tue Jul 17 10:23:25 PDT 2012
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
@@ -76,29 +76,66 @@ org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
||||
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=0
|
||||
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=48
|
||||
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=48
|
||||
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=48
|
||||
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
|
||||
@@ -138,12 +175,14 @@ 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.format_guardian_clause_on_one_line=true
|
||||
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
|
||||
@@ -210,6 +249,7 @@ org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_re
|
||||
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
|
||||
@@ -340,7 +380,7 @@ 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=true
|
||||
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=100
|
||||
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
|
||||
@@ -348,10 +388,22 @@ 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.sort_local_variable_annotations=false
|
||||
org.eclipse.jdt.core.formatter.sort_member_annotations=false
|
||||
org.eclipse.jdt.core.formatter.sort_package_annotations=false
|
||||
org.eclipse.jdt.core.formatter.sort_parameter_annotations=false
|
||||
org.eclipse.jdt.core.formatter.sort_type_annotations=false
|
||||
org.eclipse.jdt.core.formatter.tabulation.char=space
|
||||
org.eclipse.jdt.core.formatter.tabulation.size=2
|
||||
org.eclipse.jdt.core.formatter.use_on_off_tags=false
|
||||
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
||||
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
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#Thu Jul 21 03:05:33 BRT 2011
|
||||
#Tue Jul 17 10:22:31 PDT 2012
|
||||
eclipse.preferences.version=1
|
||||
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
|
||||
formatter_profile=_MyTracks
|
||||
formatter_settings_version=12
|
||||
formatter_profile=_My Tracks
|
||||
formatter_settings_version=13
|
||||
org.eclipse.jdt.ui.ignorelowercasenames=true
|
||||
org.eclipse.jdt.ui.importorder=com;android;java;javax;org;
|
||||
org.eclipse.jdt.ui.ondemandthreshold=99
|
||||
|
||||
+268
-313
@@ -13,458 +13,413 @@
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.content;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Utility to access data from the mytracks content provider.
|
||||
*
|
||||
* Utilities to access data from the My Tracks content provider.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public interface MyTracksProviderUtils {
|
||||
|
||||
/**
|
||||
* Authority (first part of URI) for the MyTracks content provider:
|
||||
* The authority (the first part of the URI) for the My Tracks content
|
||||
* provider.
|
||||
*/
|
||||
public static final String AUTHORITY = "com.google.android.maps.mytracks";
|
||||
|
||||
/**
|
||||
* Deletes all tracks (including track points) from the provider.
|
||||
*/
|
||||
void deleteAllTracks();
|
||||
|
||||
/**
|
||||
* Deletes a track with the given track id.
|
||||
*
|
||||
* @param trackId the unique track id
|
||||
*/
|
||||
void deleteTrack(long trackId);
|
||||
|
||||
/**
|
||||
* Deletes a way point with the given way point id.
|
||||
* This will also correct the next statistics way point after the deleted one
|
||||
* to reflect the deletion.
|
||||
* The generator is needed to stitch together statistics waypoints.
|
||||
*
|
||||
* @param waypointId the unique way point id
|
||||
* @param descriptionGenerator the class to generate descriptions
|
||||
*/
|
||||
void deleteWaypoint(long waypointId,
|
||||
DescriptionGenerator descriptionGenerator);
|
||||
|
||||
/**
|
||||
* Finds the next statistics waypoint after the given waypoint.
|
||||
*
|
||||
* @param waypoint a given waypoint
|
||||
* @return the next statistics waypoint, or null if none found.
|
||||
*/
|
||||
Waypoint getNextStatisticsWaypointAfter(Waypoint waypoint);
|
||||
|
||||
/**
|
||||
* Updates the waypoint in the provider.
|
||||
*
|
||||
* @param waypoint
|
||||
* @return true if successful
|
||||
*/
|
||||
boolean updateWaypoint(Waypoint waypoint);
|
||||
|
||||
/**
|
||||
* Finds the first recorded location from the location provider.
|
||||
* Gets a track cursor. The caller owns the returned cursor and is responsible
|
||||
* for closing it.
|
||||
*
|
||||
* @return the first location, or null if no locations available
|
||||
* @param selection the selection
|
||||
* @param selectionArgs the selection arguments
|
||||
* @param sortOrder the sort order
|
||||
*/
|
||||
Location getFirstLocation();
|
||||
public Cursor getTracksCursor(String selection, String[] selectionArgs, String sortOrder);
|
||||
|
||||
/**
|
||||
* Finds the last recorded location from the location provider.
|
||||
*
|
||||
* @return the last location, or null if no locations available
|
||||
* Gets all the tracks. If no track exists, an empty list is returned.
|
||||
* <p>
|
||||
* Note that the returned tracks do not have any track points attached.
|
||||
*/
|
||||
Location getLastLocation();
|
||||
public List<Track> getAllTracks();
|
||||
|
||||
/**
|
||||
* Finds the first recorded waypoint for a given track from the location
|
||||
* provider.
|
||||
* This is a special waypoint that holds the stats for current segment.
|
||||
*
|
||||
* @param trackId the id of the track the waypoint belongs to
|
||||
* @return the first waypoint, or null if no waypoints available
|
||||
* Gets a track by a track id. Returns null if not found.
|
||||
* <p>
|
||||
* Note that the returned track doesn't have any track points attached.
|
||||
*
|
||||
* @param trackId the track id.
|
||||
*/
|
||||
Waypoint getFirstWaypoint(long trackId);
|
||||
public Track getTrack(long trackId);
|
||||
|
||||
/**
|
||||
* Finds the given waypoint from the location provider.
|
||||
*
|
||||
* @param waypointId
|
||||
* @return the waypoint, or null if it does not exist
|
||||
* Gets the last track. Returns null if doesn't exist.
|
||||
*/
|
||||
Waypoint getWaypoint(long waypointId);
|
||||
public Track getLastTrack();
|
||||
|
||||
/**
|
||||
* Finds the last recorded location id from the track points provider.
|
||||
*
|
||||
* @param trackId find last location on this track
|
||||
* @return the location id, or -1 if no locations available
|
||||
* Gets the last track id. Returns -1L if doesn't exist.
|
||||
*/
|
||||
long getLastLocationId(long trackId);
|
||||
public long getLastTrackId();
|
||||
|
||||
/**
|
||||
* Finds the id of the 1st waypoint for a given track.
|
||||
* The 1st waypoint is special as it contains the stats for the current
|
||||
* segment.
|
||||
*
|
||||
* @param trackId find last location on this track
|
||||
* @return the waypoint id, or -1 if no waypoints are available
|
||||
* Returns true if a track exists.
|
||||
*
|
||||
* @param trackId the track id
|
||||
*/
|
||||
long getFirstWaypointId(long trackId);
|
||||
public boolean trackExists(long trackId);
|
||||
|
||||
/**
|
||||
* Finds the id of the 1st waypoint for a given track.
|
||||
* The 1st waypoint is special as it contains the stats for the current
|
||||
* segment.
|
||||
*
|
||||
* @param trackId find last location on this track
|
||||
* @return the waypoint id, or -1 if no waypoints are available
|
||||
* Inserts a track.
|
||||
* <p>
|
||||
* Note: This doesn't insert any track points.
|
||||
*
|
||||
* @param track the track
|
||||
* @return the content provider URI of the inserted track.
|
||||
*/
|
||||
long getLastWaypointId(long trackId);
|
||||
public Uri insertTrack(Track track);
|
||||
|
||||
/**
|
||||
* Gets the next marker number.
|
||||
*
|
||||
* Updates a track.
|
||||
* <p>
|
||||
* Note: This doesn't update any track points.
|
||||
*
|
||||
* @param track the track
|
||||
*/
|
||||
public void updateTrack(Track track);
|
||||
|
||||
/**
|
||||
* Deletes all tracks (including waypoints and track points).
|
||||
*/
|
||||
public void deleteAllTracks();
|
||||
|
||||
/**
|
||||
* Deletes a track.
|
||||
*
|
||||
* @param trackId the track id
|
||||
*/
|
||||
public void deleteTrack(long trackId);
|
||||
|
||||
/**
|
||||
* Creates a {@link Track} from a cursor.
|
||||
*
|
||||
* @param cursor the cursor pointing to the track
|
||||
*/
|
||||
public Track createTrack(Cursor cursor);
|
||||
|
||||
/**
|
||||
* Creates a {@link ContentValues} from a track.
|
||||
*
|
||||
* @param track the track
|
||||
*/
|
||||
public ContentValues createContentValues(Track track);
|
||||
|
||||
/**
|
||||
* Gets a waypoint cursor. The caller owns the returned cursor and is
|
||||
* responsible for closing it.
|
||||
*
|
||||
* @param selection the selection
|
||||
* @param selectionArgs the selection arguments
|
||||
* @param sortOrder the sort order
|
||||
* @param maxWaypoints the maximum number of waypoints to return
|
||||
*/
|
||||
public Cursor getWaypointsCursor(
|
||||
String selection, String[] selectionArgs, String sortOrder, int maxWaypoints);
|
||||
|
||||
/**
|
||||
* Gets a waypoint cursor for a track. The caller owns the returned cursor and
|
||||
* is responsible for closing it.
|
||||
*
|
||||
* @param trackId the track id
|
||||
* @param minWaypointId the minimum waypoint id
|
||||
* @param maxWaypoints the maximum number of waypoints to return
|
||||
*/
|
||||
public Cursor getWaypointsCursor(long trackId, long minWaypointId, int maxWaypoints);
|
||||
|
||||
/**
|
||||
* Gets the first recorded waypoint for a track. The first waypoint is special
|
||||
* as it contains the stats for the current segment. Returns null if it
|
||||
* doesn't exist.
|
||||
*
|
||||
* @param trackId the track id
|
||||
*/
|
||||
public Waypoint getFirstWaypoint(long trackId);
|
||||
|
||||
/**
|
||||
* Gets the first waypoint id for a track. The first waypoint is special as it
|
||||
* contains the stats for the current segment. Returns -1L if it doesn't
|
||||
* exist.
|
||||
*
|
||||
* @param trackId the track id
|
||||
*/
|
||||
public long getFirstWaypointId(long trackId);
|
||||
|
||||
/**
|
||||
* Gets the last waypoint id for a track. Returns -1L if it doesn't exist.
|
||||
*
|
||||
* @param trackId the track id
|
||||
*/
|
||||
public long getLastWaypointId(long trackId);
|
||||
|
||||
/**
|
||||
* Gets the next marker number. Returns -1 if not able to get the next marker
|
||||
* number.
|
||||
*
|
||||
* @param trackId the track id
|
||||
* @param statistics true for statistics marker, false for waypoint marker
|
||||
* @return the next number or -1 if unable to get the value
|
||||
*/
|
||||
int getNextMarkerNumber(long trackId, boolean statistics);
|
||||
|
||||
/**
|
||||
* Finds the last recorded track from the track provider.
|
||||
*
|
||||
* @return the last track, or null if no tracks available
|
||||
*/
|
||||
Track getLastTrack();
|
||||
public int getNextMarkerNumber(long trackId, boolean statistics);
|
||||
|
||||
/**
|
||||
* Finds the last recorded track id from the tracks provider.
|
||||
*
|
||||
* @return the track id, or -1 if no tracks available
|
||||
* Gets the next statistics waypoint after the given waypoint. Returns null if
|
||||
* it doesn't exists.
|
||||
*
|
||||
* @param waypoint the given waypoint
|
||||
*/
|
||||
long getLastTrackId();
|
||||
public Waypoint getNextStatisticsWaypointAfter(Waypoint waypoint);
|
||||
|
||||
/**
|
||||
* Finds a location by given unique id.
|
||||
*
|
||||
* @param id the desired id
|
||||
* @return a Location object, or null if not found
|
||||
* Gets a waypoint from a waypoint id. Returns null if not found.
|
||||
*
|
||||
* @param waypointId the waypoint id
|
||||
*/
|
||||
Location getLocation(long id);
|
||||
public Waypoint getWaypoint(long waypointId);
|
||||
|
||||
/**
|
||||
* Creates a cursor over the locations in the track points provider which
|
||||
* iterates over a given range of unique ids.
|
||||
* Caller owns the returned cursor and is responsible for closing it.
|
||||
*
|
||||
* @param trackId the id of the track for which to get the points
|
||||
* @param minTrackPointId the minimum id for the track points
|
||||
* @param maxLocations maximum number of locations retrieved
|
||||
* @param descending if true the results will be returned in descending id
|
||||
* order (latest location first)
|
||||
* @return A cursor over the selected range of locations
|
||||
* Inserts a waypoint.
|
||||
*
|
||||
* @param waypoint the waypoint
|
||||
* @return the content provider URI of the inserted waypoint.
|
||||
*/
|
||||
Cursor getLocationsCursor(long trackId, long minTrackPointId,
|
||||
int maxLocations, boolean descending);
|
||||
public Uri insertWaypoint(Waypoint waypoint);
|
||||
|
||||
/**
|
||||
* Creates a cursor over the waypoints of a track.
|
||||
* Caller owns the returned cursor and is responsible for closing it.
|
||||
*
|
||||
* @param trackId the id of the track for which to get the points
|
||||
* @param minWaypointId the minimum id for the track points
|
||||
* @param maxWaypoints the maximum number of waypoints to return
|
||||
* @return A cursor over the selected range of locations
|
||||
* Updates a waypoint. Returns true if successful.
|
||||
*
|
||||
* @param waypoint the waypoint
|
||||
*/
|
||||
Cursor getWaypointsCursor(long trackId, long minWaypointId,
|
||||
int maxWaypoints);
|
||||
public boolean updateWaypoint(Waypoint waypoint);
|
||||
|
||||
/**
|
||||
* Creates a cursor over waypoints with the given selection.
|
||||
* Caller owns the returned cursor and is responsible for closing it.
|
||||
*
|
||||
* @param selection a given selection
|
||||
* @param selectionArgs arguments for the given selection
|
||||
* @param order the order in which to return results
|
||||
* @param maxWaypoints the maximum number of waypoints to return
|
||||
* @return a cursor of the selected waypoints
|
||||
* Deletes a waypoint. If deleting a statistics waypoint, this will also
|
||||
* correct the next statistics waypoint after the deleted one to reflect the
|
||||
* deletion. The generator is used to update the next statistics waypoint.
|
||||
*
|
||||
* @param waypointId the waypoint id
|
||||
* @param descriptionGenerator the description generator
|
||||
*/
|
||||
Cursor getWaypointsCursor(String selection, String[] selectionArgs, String order, int maxWaypoints);
|
||||
public void deleteWaypoint(long waypointId, DescriptionGenerator descriptionGenerator);
|
||||
|
||||
/**
|
||||
* Finds a track by given unique track id.
|
||||
* Note that the returned track object does not have any track points attached.
|
||||
* Use {@link #getLocationIterator(long, long, boolean, LocationFactory)} to load
|
||||
* the track points.
|
||||
*
|
||||
* @param id desired unique track id
|
||||
* @return a Track object, or null if not found
|
||||
* Creates a waypoint from a cursor.
|
||||
*
|
||||
* @param cursor the cursor pointing to the waypoint
|
||||
*/
|
||||
Track getTrack(long id);
|
||||
public Waypoint createWaypoint(Cursor cursor);
|
||||
|
||||
/**
|
||||
* Retrieves all tracks without track points. If no tracks exist, an empty
|
||||
* list will be returned. Use {@link #getLocationIterator(long, long, boolean, LocationFactory)}
|
||||
* to load the track points.
|
||||
*
|
||||
* @return a list of all the recorded tracks
|
||||
* Gets the first recorded location. Returns null if it doesn't exist.
|
||||
*/
|
||||
List<Track> getAllTracks();
|
||||
public Location getFirstLocation();
|
||||
|
||||
/**
|
||||
* Creates a cursor over the tracks provider with a given selection.
|
||||
* Caller owns the returned cursor and is responsible for closing it.
|
||||
*
|
||||
* @param selection a given selection
|
||||
* @param selectionArgs parameters for the given selection
|
||||
* @param order the order to return results in
|
||||
* @return a cursor of the selected tracks
|
||||
* Gets the last recorded location. Returns null if it doesn't exist.
|
||||
*/
|
||||
Cursor getTracksCursor(String selection, String[] selectionArgs, String order);
|
||||
public Location getLastLocation();
|
||||
|
||||
/**
|
||||
* Inserts a track in the tracks provider.
|
||||
* Note: This does not insert any track points.
|
||||
* Use {@link #insertTrackPoint(Location, long)} to insert them.
|
||||
*
|
||||
* @param track the track to insert
|
||||
* @return the content provider URI for the inserted track
|
||||
* Gets a location by track point id. Returns null if not found.
|
||||
*
|
||||
* @param trackPointId the track point id
|
||||
*/
|
||||
Uri insertTrack(Track track);
|
||||
public Location getLocation(long trackPointId);
|
||||
|
||||
/**
|
||||
* Inserts a track point in the tracks provider.
|
||||
*
|
||||
* @param location the location to insert
|
||||
* @return the content provider URI for the inserted track point
|
||||
* Creates a location cursor. The caller owns the returned cursor and is
|
||||
* responsible for closing it.
|
||||
*
|
||||
* @param trackId the track id
|
||||
* @param startTrackPointId the starting track point id
|
||||
* @param maxLocations maximum number of locations to return
|
||||
* @param descending true to sort the result in descending order (latest
|
||||
* location first)
|
||||
*/
|
||||
Uri insertTrackPoint(Location location, long trackId);
|
||||
public Cursor getLocationsCursor(
|
||||
long trackId, long startTrackPointId, int maxLocations, boolean descending);
|
||||
|
||||
/**
|
||||
* Inserts multiple track points in a single operation.
|
||||
*
|
||||
* @param locations an array of locations to insert
|
||||
* @param length the number of locations (from the beginning of the array)
|
||||
* to actually insert, or -1 for all of them
|
||||
* @param trackId the ID of the track to insert the points into
|
||||
* Creates a new read-only iterator over a given track's points. It provides a
|
||||
* lightweight way of iterating over long tracks without failing due to the
|
||||
* underlying cursor limitations. Since it's a read-only iterator,
|
||||
* {@link Iterator#remove()} always throws
|
||||
* {@link UnsupportedOperationException}. Each call to
|
||||
* {@link LocationIterator#next()} may advance to the next DB record, and if
|
||||
* so, the iterator calls {@link LocationFactory#createLocation()} and
|
||||
* populates it with information retrieved from the record. When done with
|
||||
* iteration, {@link LocationIterator#close()} must be called.
|
||||
*
|
||||
* @param trackId the track id
|
||||
* @param startTrackPointId the start track point id or -1L to start from the
|
||||
* first point
|
||||
* @param descending true to sort the result in descending order (latest
|
||||
* location first)
|
||||
* @param locationFactory the location factory
|
||||
*/
|
||||
public LocationIterator getLocationIterator(
|
||||
long trackId, long startTrackPointId, boolean descending, LocationFactory locationFactory);
|
||||
|
||||
/**
|
||||
* Gets the last location id for a track. Returns -1L if it doesn't exist.
|
||||
*
|
||||
* @param trackId the track id
|
||||
*/
|
||||
public long getLastLocationId(long trackId);
|
||||
|
||||
/**
|
||||
* Inserts a track point.
|
||||
*
|
||||
* @param location the location
|
||||
* @param trackId the track id
|
||||
* @return the content provider URI of the inserted track point
|
||||
*/
|
||||
public Uri insertTrackPoint(Location location, long trackId);
|
||||
|
||||
/**
|
||||
* Inserts multiple track points.
|
||||
*
|
||||
* @param locations an array of locations
|
||||
* @param length the number of locations (from the beginning of the array) to
|
||||
* insert, or -1 for all of them
|
||||
* @param trackId the track id
|
||||
* @return the number of points inserted
|
||||
*/
|
||||
int bulkInsertTrackPoints(Location[] locations, int length, long trackId);
|
||||
public int bulkInsertTrackPoints(Location[] locations, int length, long trackId);
|
||||
|
||||
/**
|
||||
* Inserts a waypoint in the provider.
|
||||
*
|
||||
* @param waypoint the waypoint to insert
|
||||
* @return the content provider URI for the inserted track
|
||||
* Fills a location from a cursor.
|
||||
*
|
||||
* @param cursor the cursor pointing to the location
|
||||
* @param location the location to be overwritten
|
||||
*/
|
||||
Uri insertWaypoint(Waypoint waypoint);
|
||||
public void fillLocation(Cursor cursor, Location location);
|
||||
|
||||
/**
|
||||
* Tests if a track with given id exists.
|
||||
*
|
||||
* @param id the unique id
|
||||
* @return true if track exists
|
||||
* Creates a location object from a cursor.
|
||||
*
|
||||
* @param cursor the cursor pointing to the location
|
||||
*/
|
||||
boolean trackExists(long id);
|
||||
public Location createLocation(Cursor cursor);
|
||||
|
||||
/**
|
||||
* Updates a track in the content provider.
|
||||
* Note: This will not update any track points.
|
||||
*
|
||||
* @param track a given track
|
||||
* A lightweight wrapper around the original {@link Cursor} with a method to
|
||||
* clean up.
|
||||
*/
|
||||
void updateTrack(Track track);
|
||||
|
||||
/**
|
||||
* Creates a Track object from a given cursor.
|
||||
*
|
||||
* @param cursor a cursor pointing at a db or provider with tracks
|
||||
* @return a new Track object
|
||||
*/
|
||||
Track createTrack(Cursor cursor);
|
||||
|
||||
/**
|
||||
* Creates the ContentValues for a given Track object.
|
||||
*
|
||||
* Note: If the track has an id<0 the id column will not be filled.
|
||||
*
|
||||
* @param track a given track object
|
||||
* @return a filled in ContentValues object
|
||||
*/
|
||||
ContentValues createContentValues(Track track);
|
||||
|
||||
/**
|
||||
* Creates a location object from a given cursor.
|
||||
*
|
||||
* @param cursor a cursor pointing at a db or provider with locations
|
||||
* @return a new location object
|
||||
*/
|
||||
Location createLocation(Cursor cursor);
|
||||
|
||||
/**
|
||||
* Fill a location object with values from a given cursor.
|
||||
*
|
||||
* @param cursor a cursor pointing at a db or provider with locations
|
||||
* @param location a location object to be overwritten
|
||||
*/
|
||||
void fillLocation(Cursor cursor, Location location);
|
||||
|
||||
/**
|
||||
* Creates a waypoint object from a given cursor.
|
||||
*
|
||||
* @param cursor a cursor pointing at a db or provider with waypoints.
|
||||
* @return a new waypoint object
|
||||
*/
|
||||
Waypoint createWaypoint(Cursor cursor);
|
||||
|
||||
/**
|
||||
* A lightweight wrapper around the original {@link Cursor} with a method to clean up.
|
||||
*/
|
||||
interface LocationIterator extends Iterator<Location> {
|
||||
/**
|
||||
* Returns ID of the most recently retrieved track point through a call to {@link #next()}.
|
||||
*
|
||||
* @return the ID of the most recent track point ID.
|
||||
*/
|
||||
long getLocationId();
|
||||
public interface LocationIterator extends Iterator<Location> {
|
||||
|
||||
/**
|
||||
* Should be called in case the underlying iterator hasn't reached the last record.
|
||||
* Calling it if it has reached the last record is a no-op.
|
||||
* Gets the most recently retrieved track point id by {@link #next()}.
|
||||
*/
|
||||
void close();
|
||||
public long getLocationId();
|
||||
|
||||
/**
|
||||
* Closes the iterator.
|
||||
*/
|
||||
public void close();
|
||||
}
|
||||
|
||||
/**
|
||||
* A factory for creating new {@class Location}s.
|
||||
* A factory for creating new {@link Location}.
|
||||
*/
|
||||
interface LocationFactory {
|
||||
public interface LocationFactory {
|
||||
|
||||
/**
|
||||
* Creates a new {@link Location} object to be populated from the underlying database record.
|
||||
* It's up to the implementing class to decide whether to create a new instance or reuse
|
||||
* existing to optimize for speed.
|
||||
*
|
||||
* @return a {@link Location} to be populated from the database.
|
||||
* Creates a new {@link Location}. An implementation can create new
|
||||
* instances or reuse existing instances for optimization.
|
||||
*/
|
||||
Location createLocation();
|
||||
public Location createLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* The default {@class Location}s factory, which creates a new location of 'gps' type.
|
||||
* The default {@link LocationFactory} which creates a location each time.
|
||||
*/
|
||||
LocationFactory DEFAULT_LOCATION_FACTORY = new LocationFactory() {
|
||||
@Override
|
||||
public LocationFactory DEFAULT_LOCATION_FACTORY = new LocationFactory() {
|
||||
@Override
|
||||
public Location createLocation() {
|
||||
return new Location("gps");
|
||||
return new Location(LocationManager.GPS_PROVIDER);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A location factory which uses two location instances (one for the current location,
|
||||
* and one for the previous), useful when we need to keep the last location.
|
||||
* A {@link LocationFactory} which uses two location instances (one for the
|
||||
* current location and one for the previous), useful when needing to keep the
|
||||
* last location.
|
||||
*/
|
||||
public class DoubleBufferedLocationFactory implements LocationFactory {
|
||||
private final Location locs[] = new MyTracksLocation[] {
|
||||
new MyTracksLocation("gps"),
|
||||
new MyTracksLocation("gps")
|
||||
};
|
||||
private int lastLoc = 0;
|
||||
|
||||
private final Location locations[] = new MyTracksLocation[] {
|
||||
new MyTracksLocation(LocationManager.GPS_PROVIDER),
|
||||
new MyTracksLocation(LocationManager.GPS_PROVIDER) };
|
||||
private int lastLocation = 0;
|
||||
|
||||
@Override
|
||||
public Location createLocation() {
|
||||
lastLoc = (lastLoc + 1) % locs.length;
|
||||
return locs[lastLoc];
|
||||
lastLocation = (lastLocation + 1) % locations.length;
|
||||
return locations[lastLocation];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new read-only iterator over all track points for the given track. It provides
|
||||
* a lightweight way of iterating over long tracks without failing due to the underlying cursor
|
||||
* limitations. Since it's a read-only iterator, {@link Iterator#remove()} always throws
|
||||
* {@class UnsupportedOperationException}.
|
||||
*
|
||||
* Each call to {@link LocationIterator#next()} may advance to the next DB record, and if so,
|
||||
* the iterator calls {@link LocationFactory#createLocation()} and populates it with information
|
||||
* retrieved from the record.
|
||||
*
|
||||
* When done with iteration, you must call {@link LocationIterator#close()} to make sure that all
|
||||
* resources are properly deallocated.
|
||||
*
|
||||
* Example use:
|
||||
* <code>
|
||||
* ...
|
||||
* LocationIterator it = providerUtils.getLocationIterator(
|
||||
* 1, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
|
||||
* try {
|
||||
* for (Location loc : it) {
|
||||
* ... // Do something useful with the location.
|
||||
* }
|
||||
* } finally {
|
||||
* it.close();
|
||||
* }
|
||||
* ...
|
||||
* </code>
|
||||
*
|
||||
* @param trackId the ID of a track to retrieve locations for.
|
||||
* @param startTrackPointId the ID of the first track point to load, or -1 to start from
|
||||
* the first point.
|
||||
* @param descending if true the results will be returned in descending ID
|
||||
* order (latest location first).
|
||||
* @param locationFactory the factory for creating new locations.
|
||||
*
|
||||
* @return the read-only iterator over the given track's points.
|
||||
*/
|
||||
LocationIterator getLocationIterator(long trackId, long startTrackPointId, boolean descending,
|
||||
LocationFactory locationFactory);
|
||||
|
||||
/**
|
||||
* A factory which can produce instances of {@link MyTracksProviderUtils},
|
||||
* and can be overridden in tests (a.k.a. poor man's guice).
|
||||
* A factory which can produce instances of {@link MyTracksProviderUtils}, and
|
||||
* can be overridden for testing.
|
||||
*/
|
||||
public static class Factory {
|
||||
|
||||
private static Factory instance = new Factory();
|
||||
|
||||
/**
|
||||
* Creates and returns an instance of {@link MyTracksProviderUtils} which
|
||||
* uses the given context to access its data.
|
||||
* Creates an instance of {@link MyTracksProviderUtils}.
|
||||
*
|
||||
* @param context the context
|
||||
*/
|
||||
public static MyTracksProviderUtils get(Context context) {
|
||||
return instance.newForContext(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the global instance of this factory.
|
||||
* Returns the factory instance.
|
||||
*/
|
||||
public static Factory getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the global instance for this factory, to be used for testing.
|
||||
* If used, don't forget to set it back to the original value after the
|
||||
* test is run.
|
||||
* Overrides the factory instance for testing. Don't forget to set it back
|
||||
* to the original value after testing.
|
||||
*
|
||||
* @param factory the factory
|
||||
*/
|
||||
public static void overrideInstance(Factory factory) {
|
||||
instance = factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of {@link MyTracksProviderUtils}.
|
||||
* Creates an instance of {@link MyTracksProviderUtils}. Allows subclasses
|
||||
* to override for testing.
|
||||
*
|
||||
* @param context the context
|
||||
*/
|
||||
protected MyTracksProviderUtils newForContext(Context context) {
|
||||
return new MyTracksProviderUtilsImpl(context.getContentResolver());
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user