Merge heads

This commit is contained in:
youtaol
2013-01-30 13:56:51 +08:00
26 changed files with 534 additions and 286 deletions
+2 -1
View File
@@ -52,6 +52,8 @@ limitations under the License.
<!-- Permission to read/write external storage -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Permission to read contacts -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<!-- Permissions to access My Tracks data -->
<uses-permission android:name="com.google.android.apps.mytracks.MYTRACKS_NOTIFICATIONS" />
<uses-permission android:name="com.google.android.apps.mytracks.READ_TRACK_DATA" />
@@ -211,7 +213,6 @@ limitations under the License.
android:name="com.google.android.apps.mytracks.io.maps.ChooseMapActivity" />
<activity android:name="com.google.android.apps.mytracks.io.maps.SendMapsActivity" />
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.AccountChooserActivity" />
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.ConfirmSharingActivity" />
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity" />
<activity android:name="com.google.android.apps.mytracks.settings.BackupResetSettingsActivity" />
<activity android:name="com.google.android.apps.mytracks.settings.ChartSettingsActivity" />
+34
View File
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2013 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.
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/ScrollView" >
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical"
android:padding="8dp" >
<MultiAutoCompleteTextView
android:hint="@string/share_track_add_people_hint"
android:completionThreshold="1"
android:id="@+id/add_people"
android:imeOptions="actionDone"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:singleLine="false" >
</MultiAutoCompleteTextView>
</LinearLayout>
</ScrollView>
+32
View File
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2013 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.
-->
<TwoLineListItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:mode="twoLine"
android:paddingBottom="2dp"
android:paddingTop="2dp" >
<TextView
android:id="@android:id/text1"
android:paddingLeft="8dp"
style="@style/TextMedium" />
<TextView
android:id="@android:id/text2"
android:layout_below="@android:id/text1"
android:paddingLeft="16dp"
style="@style/TextSmall" />
</TwoLineListItem>
+1 -1
View File
@@ -17,7 +17,7 @@ limitations under the License.
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:icon="@drawable/menu_map_layer"
android:orderInCategory="5"
android:orderInCategory="6"
android:showAsAction="ifRoom"
android:title="@string/menu_map_layer">
<menu>
+19 -12
View File
@@ -35,21 +35,28 @@ limitations under the License.
android:title="@string/menu_share">
</item>
<item
android:icon="@drawable/menu_markers"
android:id="@+id/track_detail_markers"
android:icon="@drawable/menu_share"
android:id="@+id/track_detail_share_drive"
android:orderInCategory="4"
android:showAsAction="ifRoom"
android:title="@string/menu_share_drive">
</item>
<item
android:icon="@drawable/menu_markers"
android:id="@+id/track_detail_markers"
android:orderInCategory="5"
android:showAsAction="ifRoom"
android:title="@string/menu_markers"/>
<!-- android:orderInCategory="5" is in map.xml -->
<!-- android:orderInCategory="6" is in map.xml -->
<item
android:icon="@drawable/menu_send_google"
android:id="@+id/track_detail_send_google"
android:orderInCategory="6"
android:orderInCategory="7"
android:title="@string/menu_send_google"/>
<item
android:icon="@drawable/menu_save"
android:id="@+id/track_detail_save"
android:orderInCategory="7"
android:orderInCategory="8"
android:title="@string/menu_save">
<menu>
<item android:id="@+id/track_detail_save_gpx"/>
@@ -61,36 +68,36 @@ limitations under the License.
<item
android:icon="@drawable/menu_edit"
android:id="@+id/track_detail_edit"
android:orderInCategory="8"
android:orderInCategory="9"
android:title="@string/menu_edit"/>
<item
android:icon="@drawable/menu_delete"
android:id="@+id/track_detail_delete"
android:orderInCategory="9"
android:orderInCategory="10"
android:title="@string/menu_delete"/>
<item
android:icon="@drawable/menu_voice_frequency"
android:id="@+id/track_detail_voice_frequency"
android:orderInCategory="10"
android:orderInCategory="11"
android:title="@string/menu_voice_frequency"/>
<item
android:icon="@drawable/menu_split_frequency"
android:id="@+id/track_detail_split_frequency"
android:orderInCategory="11"
android:orderInCategory="12"
android:title="@string/menu_split_frequency"/>
<item
android:icon="@drawable/menu_sensor_state"
android:id="@+id/track_detail_sensor_state"
android:orderInCategory="12"
android:orderInCategory="13"
android:title="@string/menu_sensor_state"/>
<item
android:icon="@drawable/menu_settings"
android:id="@+id/track_detail_settings"
android:orderInCategory="13"
android:orderInCategory="14"
android:title="@string/menu_settings"/>
<item
android:icon="@drawable/menu_help"
android:id="@+id/track_detail_help"
android:orderInCategory="14"
android:orderInCategory="15"
android:title="@string/menu_help"/>
</menu>
+4 -3
View File
@@ -30,6 +30,9 @@ limitations under the License.
<string name="chart_show_heart_rate_key">chartShowHeartRate</string>
<string name="chart_show_power_key">chartShowPower</string>
<string name="chart_show_speed_key">chartShowSpeed</string>
<string name="confirm_play_earth_key">confirmPlayEarth</string>
<string name="confirm_share_drive_key">confirmShareDrive</string>
<string name="confirm_share_map_key">confirmShareMap</string>
<string name="default_activity_key">defaultActivity</string>
<string name="default_map_public_key">defaultMapPublic</string>
<string name="drive_sync_key">driveSync</string>
@@ -45,9 +48,7 @@ limitations under the License.
<string name="send_to_drive_key">sendToDrive</string>
<string name="send_to_fusion_tables_key">sendToFusionTables</string>
<string name="send_to_maps_key">sendToMaps</string>
<string name="sensor_type_key">sensorType</string>
<string name="show_confirm_play_earth_dialog_key">showConfirmPlayDialog</string>
<string name="show_confirm_sharing_dialog_key">showConfrimSharingDialog</string>
<string name="sensor_type_key">sensorType</string>
<string name="split_frequency_key">splitFrequency</string>
<string name="stats_show_coordinate_key">statsShowCoordinate</string>
<string name="stats_show_elevation_key">statsShowElevation</string>
+27 -6
View File
@@ -918,7 +918,7 @@ limitations under the License.
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
default between public and unlisted via Settings -> Sharing. After uploading tracks, you can
default between public and unlisted via Settings -> Google. After uploading tracks, you can
change their visibility in Google Maps, Google Fusion Tables, and Google Docs.
</string>
<string name="help_share_visibility_question"
@@ -1252,6 +1252,12 @@ limitations under the License.
Character limit: ~20 (1 line)">
Share
</string>
<string name="menu_share_drive"
translation_description="In the menu, to share a track via Google Drive.
Character limit: ~20 (1 line)">
Share via Drive
</string>
<string name="menu_show_on_map"
translation_description="In the menu, to show a track or a marker on the map.
@@ -2191,13 +2197,28 @@ limitations under the License.
</string>
<!-- Share Track -->
<string name="share_track_confirm_message"
translation_description="The confirmation message when sharing a track with friends.
<string name="share_track_add_people"
translation_description="The dialog title for adding people to share a track with.">
Add people
</string>
<string name="share_track_add_people_hint"
translation_description="The hint in the auto complete text box for entering email addresses.">
Enter email addresses
</string>
<string name="share_track_drive_confirm_message"
translation_description="The confirmation message when sharing a track via Google Drive with
friends.">
This will upload your track to Google Drive so you can share the file with friends. The file
will be private and only those you have shared with will have access.
</string>
<string name="share_track_map_confirm_message"
translation_description="The confirmation message when sharing a track via Google Maps with
friends.
%1$s url. E.g., 'support.google.com/maps/bin/answer.py?answer=144365'.">
This will upload your track to Google Maps so that you can share the map url with friends. The
map will be either public or unlisted depending on your setting at Settings -> Sharing. For more
info on public versus unlisted, see %1$s.
This will upload your track to Google Maps so you can share the map url with friends. The map
will be either public or unlisted depending on your setting at Settings -> Google. For more info
on public versus unlisted, see %1$s.
</string>
<string name="share_track_picker_title"
translation_description="When sharing a track with friends, the title on the picker to ask the
@@ -21,10 +21,11 @@ import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TrackDataHub;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.fragments.AddPeopleDialogFragment;
import com.google.android.apps.mytracks.fragments.ChartFragment;
import com.google.android.apps.mytracks.fragments.ChooseActivityDialogFragment;
import com.google.android.apps.mytracks.fragments.ChooseUploadServiceDialogFragment;
import com.google.android.apps.mytracks.fragments.ConfirmPlayDialogFragment;
import com.google.android.apps.mytracks.fragments.ConfirmDialogFragment;
import com.google.android.apps.mytracks.fragments.DeleteOneTrackDialogFragment;
import com.google.android.apps.mytracks.fragments.DeleteOneTrackDialogFragment.DeleteOneTrackCaller;
import com.google.android.apps.mytracks.fragments.FrequencyDialogFragment;
@@ -39,6 +40,7 @@ import com.google.android.apps.mytracks.settings.SettingsActivity;
import com.google.android.apps.mytracks.util.AnalyticsUtils;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
import com.google.android.maps.mytracks.R;
@@ -75,7 +77,7 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
private static final String TAG = TrackDetailActivity.class.getSimpleName();
private static final String CURRENT_TAB_TAG_KEY = "current_tab_tag_key";
// The following are set in onCreate
private SharedPreferences sharedPreferences;
private TrackRecordingServiceConnection trackRecordingServiceConnection;
@@ -95,6 +97,7 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
private MenuItem insertMarkerMenuItem;
private MenuItem playMenuItem;
private MenuItem shareMenuItem;
private MenuItem shareDriveMenuItem;
private MenuItem sendGoogleMenuItem;
private MenuItem saveMenuItem;
private MenuItem voiceFrequencyMenuItem;
@@ -293,6 +296,7 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
insertMarkerMenuItem = menu.findItem(R.id.track_detail_insert_marker);
playMenuItem = menu.findItem(R.id.track_detail_play);
shareMenuItem = menu.findItem(R.id.track_detail_share);
shareDriveMenuItem = menu.findItem(R.id.track_detail_share_drive);
sendGoogleMenuItem = menu.findItem(R.id.track_detail_send_google);
saveMenuItem = menu.findItem(R.id.track_detail_save);
voiceFrequencyMenuItem = menu.findItem(R.id.track_detail_voice_frequency);
@@ -311,6 +315,34 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
return super.onPrepareOptionsMenu(menu);
}
/**
* Invokes when the confirm dialog is done.
*
* @param id the confirm id
*/
public void onConfirmDialogDone(int id) {
switch (id) {
case R.string.confirm_play_earth_key:
AnalyticsUtils.sendPageViews(this, "/action/play");
Intent intent = IntentUtils.newIntent(this, SaveActivity.class)
.putExtra(SaveActivity.EXTRA_TRACK_ID, trackId)
.putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.KML)
.putExtra(SaveActivity.EXTRA_PLAY_TRACK, true);
startActivity(intent);
break;
case R.string.confirm_share_map_key:
AnalyticsUtils.sendPageViews(this, "/action/share");
ChooseActivityDialogFragment.newInstance(trackId, null).show(
getSupportFragmentManager(), ChooseActivityDialogFragment.CHOOSE_ACTIVITY_DIALOG_TAG);
break;
case R.string.confirm_share_drive_key:
AddPeopleDialogFragment.newInstance(trackId)
.show(getSupportFragmentManager(), AddPeopleDialogFragment.ADD_PEOPLE_DIALOG_TAG);
break;
default:
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent intent;
@@ -323,17 +355,26 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
return true;
case R.id.track_detail_play:
if (isEarthInstalled()) {
ConfirmPlayDialogFragment.newInstance(trackId)
.show(getSupportFragmentManager(), ConfirmPlayDialogFragment.CONFIRM_PLAY_DIALOG_TAG);
ConfirmDialogFragment.newInstance(R.string.confirm_play_earth_key,
PreferencesUtils.CONFIRM_PLAY_EARTH_DEFAULT,
getString(R.string.track_detail_play_confirm_message))
.show(getSupportFragmentManager(), ConfirmDialogFragment.CONFIRM_DIALOG_TAG);
} else {
new InstallEarthDialogFragment().show(
getSupportFragmentManager(), InstallEarthDialogFragment.INSTALL_EARTH_DIALOG_TAG);
}
return true;
case R.id.track_detail_share:
AnalyticsUtils.sendPageViews(this, "/action/share");
ChooseActivityDialogFragment.newInstance(trackId, null).show(
getSupportFragmentManager(), ChooseActivityDialogFragment.CHOOSE_ACTIVITY_DIALOG_TAG);
ConfirmDialogFragment.newInstance(R.string.confirm_share_map_key,
PreferencesUtils.CONFIRM_SHARE_MAP_DEFAULT, StringUtils.getHtml(
this, R.string.share_track_map_confirm_message, R.string.maps_public_unlisted_url))
.show(getSupportFragmentManager(), ConfirmDialogFragment.CONFIRM_DIALOG_TAG);
return true;
case R.id.track_detail_share_drive:
ConfirmDialogFragment.newInstance(R.string.confirm_share_drive_key,
PreferencesUtils.CONFIRM_SHARE_DRIVE_DEFAULT,
getString(R.string.share_track_drive_confirm_message))
.show(getSupportFragmentManager(), ConfirmDialogFragment.CONFIRM_DIALOG_TAG);
return true;
case R.id.track_detail_markers:
intent = IntentUtils.newIntent(this, MarkerListActivity.class)
@@ -478,6 +519,9 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
if (shareMenuItem != null) {
shareMenuItem.setVisible(!isRecording);
}
if (shareDriveMenuItem != null) {
shareDriveMenuItem.setVisible(!isRecording);
}
if (sendGoogleMenuItem != null) {
sendGoogleMenuItem.setVisible(!isRecording);
}
@@ -0,0 +1,125 @@
/*
* Copyright 2013 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.fragments;
import com.google.android.apps.mytracks.io.sendtogoogle.AccountChooserActivity;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.widget.SimpleCursorAdapter;
import android.view.View;
import android.widget.FilterQueryProvider;
import android.widget.MultiAutoCompleteTextView;
/**
* A DialogFragment to add people to share a track with.
*
* @author Jimmy Shih
*/
public class AddPeopleDialogFragment extends DialogFragment {
public static final String ADD_PEOPLE_DIALOG_TAG = "addPeopleDialog";
private static final String KEY_TRACK_ID = "trackId";
public static AddPeopleDialogFragment newInstance(long trackId) {
Bundle bundle = new Bundle();
bundle.putLong(KEY_TRACK_ID, trackId);
AddPeopleDialogFragment addPeopleDialogFragment = new AddPeopleDialogFragment();
addPeopleDialogFragment.setArguments(bundle);
return addPeopleDialogFragment;
}
private MultiAutoCompleteTextView multiAutoCompleteTextView;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
FragmentActivity activity = getActivity();
View view = activity.getLayoutInflater().inflate(R.layout.add_people, null);
multiAutoCompleteTextView = (MultiAutoCompleteTextView) view.findViewById(R.id.add_people);
multiAutoCompleteTextView.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());
SimpleCursorAdapter adapter = new SimpleCursorAdapter(getActivity(), R.layout.add_people_item,
getCursor(getActivity(), null), new String[] {
ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.CommonDataKinds.Email.DATA },
new int[] { android.R.id.text1, android.R.id.text2 }, 0);
adapter.setCursorToStringConverter(new SimpleCursorAdapter.CursorToStringConverter() {
@Override
public CharSequence convertToString(Cursor cursor) {
int index = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA);
return cursor.getString(index).trim();
}
});
adapter.setFilterQueryProvider(new FilterQueryProvider() {
@Override
public Cursor runQuery(CharSequence constraint) {
return getCursor(getActivity(), constraint);
}
});
multiAutoCompleteTextView.setAdapter(adapter);
return new AlertDialog.Builder(activity).setNegativeButton(R.string.generic_cancel, null)
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String acl = multiAutoCompleteTextView.getText().toString();
if (acl != null && !acl.equals("")) {
long trackId = getArguments().getLong(KEY_TRACK_ID);
SendRequest sendRequest = new SendRequest(trackId);
sendRequest.setSendDrive(true);
sendRequest.setAcl(acl);
Intent intent = IntentUtils.newIntent(getActivity(), AccountChooserActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
startActivity(intent);
}
}
}).setTitle(R.string.share_track_add_people).setView(view).create();
}
/**
* Gets the cursor
*
* @param activity the activity
* @param constraint the constraint
*/
private Cursor getCursor(Activity activity, CharSequence constraint) {
String order = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
String selection = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '1'";
if (constraint != null) {
selection += " AND (" + ContactsContract.Contacts.DISPLAY_NAME + " LIKE '%" + constraint
+ "%' OR " + ContactsContract.CommonDataKinds.Email.DATA + " LIKE '%" + constraint
+ "%' )";
}
String[] projection = new String[] { ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.CommonDataKinds.Email.DATA };
Uri uri = ContactsContract.CommonDataKinds.Email.CONTENT_URI;
return activity.getContentResolver().query(uri, projection, selection, null, order);
}
}
@@ -16,7 +16,7 @@
package com.google.android.apps.mytracks.fragments;
import com.google.android.apps.mytracks.io.sendtogoogle.ConfirmSharingActivity;
import com.google.android.apps.mytracks.io.sendtogoogle.AccountChooserActivity;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.maps.mytracks.R;
@@ -120,7 +120,7 @@ public class ChooseActivityDialogFragment extends DialogFragment {
sendRequest.setNewMap(true);
sendRequest.setSharingAppPackageName(packageName);
sendRequest.setSharingAppClassName(className);
Intent intent = IntentUtils.newIntent(activity, ConfirmSharingActivity.class)
Intent intent = IntentUtils.newIntent(activity, AccountChooserActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
startActivity(intent);
dismiss();
@@ -0,0 +1,89 @@
/*
* Copyright 2012 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.fragments;
import com.google.android.apps.mytracks.TrackDetailActivity;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
/**
* A DialogFragment to confirm an action.
*
* @author Jimmy Shih
*/
public class ConfirmDialogFragment extends DialogFragment {
public static final String CONFIRM_DIALOG_TAG = "confirmDialog";
private static final String KEY_CONFIRM_ID = "confirmId";
private static final String KEY_DEFAULT_VALUE = "defaultValue";
private static final String KEY_MESSAGE = "message";
private CheckBox checkBox;
public static ConfirmDialogFragment newInstance(
int confirmId, boolean defaultValue, CharSequence message) {
Bundle bundle = new Bundle();
bundle.putInt(KEY_CONFIRM_ID, confirmId);
bundle.putBoolean(KEY_DEFAULT_VALUE, defaultValue);
bundle.putCharSequence(KEY_MESSAGE, message);
ConfirmDialogFragment confirmDialogFragment = new ConfirmDialogFragment();
confirmDialogFragment.setArguments(bundle);
return confirmDialogFragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int confirmId = getArguments().getInt(KEY_CONFIRM_ID);
boolean defaultValue = getArguments().getBoolean(KEY_DEFAULT_VALUE);
if (!PreferencesUtils.getBoolean(getActivity(), confirmId, defaultValue)) {
dismiss();
TrackDetailActivity trackDetailActivity = (TrackDetailActivity) getActivity();
trackDetailActivity.onConfirmDialogDone(confirmId);
}
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View view = getActivity().getLayoutInflater().inflate(R.layout.confirm_dialog, null);
TextView textView = (TextView) view.findViewById(R.id.confirm_dialog_message);
textView.setText(getArguments().getCharSequence(KEY_MESSAGE));
checkBox = (CheckBox) view.findViewById(R.id.confirm_dialog_check_box);
return new AlertDialog.Builder(getActivity()).setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
int confirmId = getArguments().getInt(KEY_CONFIRM_ID);
PreferencesUtils.setBoolean(getActivity(), confirmId, !checkBox.isChecked());
TrackDetailActivity trackDetailActivity = (TrackDetailActivity) getActivity();
trackDetailActivity.onConfirmDialogDone(confirmId);
}
}).setTitle(R.string.generic_confirm_title).setView(view).create();
}
}
@@ -1,102 +0,0 @@
/*
* Copyright 2012 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.fragments;
import com.google.android.apps.mytracks.io.file.SaveActivity;
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
import com.google.android.apps.mytracks.util.AnalyticsUtils;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
/**
* A DialogFragment to confirm play in Google Earth.
*
* @author Jimmy Shih
*/
public class ConfirmPlayDialogFragment extends DialogFragment {
public static final String CONFIRM_PLAY_DIALOG_TAG = "confirmPlayDialog";
private static final String KEY_TRACK_ID = "trackId";
private FragmentActivity activity;
private CheckBox checkBox;
public static ConfirmPlayDialogFragment newInstance(long trackId) {
Bundle bundle = new Bundle();
bundle.putLong(KEY_TRACK_ID, trackId);
ConfirmPlayDialogFragment confirmPlayDialogFragment = new ConfirmPlayDialogFragment();
confirmPlayDialogFragment.setArguments(bundle);
return confirmPlayDialogFragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activity = getActivity();
if (!PreferencesUtils.getBoolean(getActivity(), R.string.show_confirm_play_earth_dialog_key,
PreferencesUtils.SHOW_CONFIRM_PLAY_DIALOG_DEFAULT)) {
dismiss();
playTrack();
}
}
private void playTrack() {
long trackId = getArguments().getLong(KEY_TRACK_ID);
AnalyticsUtils.sendPageViews(activity, "/action/play");
Intent intent = IntentUtils.newIntent(activity, SaveActivity.class)
.putExtra(SaveActivity.EXTRA_TRACK_ID, trackId)
.putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.KML)
.putExtra(SaveActivity.EXTRA_PLAY_TRACK, true);
startActivity(intent);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View view = activity.getLayoutInflater().inflate(R.layout.confirm_dialog, null);
TextView textView = (TextView) view.findViewById(R.id.confirm_dialog_message);
textView.setText(R.string.track_detail_play_confirm_message);
checkBox = (CheckBox) view.findViewById(R.id.confirm_dialog_check_box);
return new AlertDialog.Builder(activity)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
PreferencesUtils.setBoolean(
activity, R.string.show_confirm_play_earth_dialog_key, !checkBox.isChecked());
playTrack();
}
})
.setTitle(R.string.generic_confirm_title)
.setView(view)
.create();
}
}
@@ -38,7 +38,8 @@ public class SendDriveActivity extends AbstractSendActivity {
@Override
protected AbstractSendAsyncTask createAsyncTask() {
return new SendDriveAsyncTask(this, sendRequest.getTrackId(), sendRequest.getAccount());
return new SendDriveAsyncTask(
this, sendRequest.getTrackId(), sendRequest.getAccount(), sendRequest.getAcl());
}
@Override
@@ -23,6 +23,7 @@ import com.google.android.apps.mytracks.io.sync.SyncUtils;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.Permission;
import android.accounts.Account;
import android.content.Context;
@@ -42,12 +43,18 @@ public class SendDriveAsyncTask extends AbstractSendAsyncTask {
private final long trackId;
private final Account account;
private final Context context;
private final String[] acl;
private final MyTracksProviderUtils myTracksProviderUtils;
public SendDriveAsyncTask(SendDriveActivity activity, long trackId, Account account) {
public SendDriveAsyncTask(SendDriveActivity activity, long trackId, Account account, String acl) {
super(activity);
this.trackId = trackId;
this.account = account;
if (acl != null) {
this.acl = acl.split(",");
} else {
this.acl = null;
}
context = activity.getApplicationContext();
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
@@ -78,13 +85,22 @@ public class SendDriveAsyncTask extends AbstractSendAsyncTask {
if (driveId != null && !driveId.equals("")) {
File driveFile = drive.files().get(driveId).execute();
if (SyncUtils.isDriveFileValid(driveFile, folderId)) {
return SyncUtils.updateDriveFile(context, myTracksProviderUtils, drive, driveFile, track);
if (SyncUtils.updateDriveFile(context, myTracksProviderUtils, drive, driveFile, track)) {
addPermission(drive, driveId);
return true;
}
}
track.setDriveId("");
track.setModifiedTime(-1L);
myTracksProviderUtils.updateTrack(track);
}
return SyncUtils.addDriveFile(context, myTracksProviderUtils, drive, folderId, track);
String id = SyncUtils.addDriveFile(context, myTracksProviderUtils, drive, folderId, track);
if (id == null) {
return false;
}
addPermission(drive, id);
return true;
} catch (IOException e) {
Log.e(TAG, "IOException", e);
return false;
@@ -93,4 +109,25 @@ public class SendDriveAsyncTask extends AbstractSendAsyncTask {
@Override
protected void invalidateToken() {}
/**
* Adds permision.
*
* @param drive the drive
* @param driveId the drive id
*/
private void addPermission(Drive drive, String driveId) throws IOException {
if (acl != null) {
for (String email : acl) {
email = email.trim();
if (!email.equals("")) {
Permission permission = new Permission();
permission.setValue(email);
permission.setType("user");
permission.setRole("reader");
drive.permissions().insert(driveId, permission).execute();
}
}
}
}
}
@@ -101,6 +101,7 @@ abstract class AbstractImporter extends DefaultHandler {
private static final int MAX_BUFFERED_LOCATIONS = 512;
private final Context context;
private final long importTrackId;
private final MyTracksProviderUtils myTracksProviderUtils;
private final int minRecordingDistance;
private final List<Long> trackIds;
@@ -128,14 +129,18 @@ abstract class AbstractImporter extends DefaultHandler {
* Constructor.
*
* @param context the context
* @param importTrackId the track id to import to. -1L to import to a new
* track.
*/
protected AbstractImporter(Context context) {
this(context, MyTracksProviderUtils.Factory.get(context));
protected AbstractImporter(Context context, long importTrackId) {
this(context, importTrackId, MyTracksProviderUtils.Factory.get(context));
}
@VisibleForTesting
protected AbstractImporter(Context context, MyTracksProviderUtils myTracksProviderUtils) {
protected AbstractImporter(
Context context, long importTrackId, MyTracksProviderUtils myTracksProviderUtils) {
this.context = context;
this.importTrackId = importTrackId;
this.myTracksProviderUtils = myTracksProviderUtils;
this.minRecordingDistance = PreferencesUtils.getInt(context,
R.string.min_recording_distance_key, PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT);
@@ -290,10 +295,20 @@ abstract class AbstractImporter extends DefaultHandler {
/**
* On track start.
*/
protected void onTrackStart() {
protected void onTrackStart() throws SAXException {
trackData = new TrackData();
Uri uri = myTracksProviderUtils.insertTrack(trackData.track);
long trackId = Long.parseLong(uri.getLastPathSegment());
long trackId;
if (importTrackId == -1L) {
Uri uri = myTracksProviderUtils.insertTrack(trackData.track);
trackId = Long.parseLong(uri.getLastPathSegment());
} else {
if (trackIds.size() > 0) {
throw new SAXException(createErrorMessage(
"Cannot import more than one track to an existing track " + importTrackId));
}
trackId = importTrackId;
myTracksProviderUtils.clearTrack(trackId);
}
trackIds.add(trackId);
trackData.track.setId(trackId);
}
@@ -52,14 +52,15 @@ public class GpxImporter extends AbstractImporter {
* Constructor.
*
* @param context the context
* @param importTrackId track id to import to. -1L to import to a new track.
*/
public GpxImporter(Context context) {
super(context);
public GpxImporter(Context context, long importTrackId) {
super(context, importTrackId);
}
@VisibleForTesting
public GpxImporter(Context context, MyTracksProviderUtils myTracksProviderUtils) {
super(context, myTracksProviderUtils);
super(context, -1L, myTracksProviderUtils);
}
@Override
@@ -117,7 +118,7 @@ public class GpxImporter extends AbstractImporter {
}
@Override
protected void onTrackStart() {
protected void onTrackStart() throws SAXException {
super.onTrackStart();
name = null;
description = null;
@@ -157,8 +157,9 @@ public class ImportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
*/
private boolean importFile(final File file) {
try {
AbstractImporter importer = trackFileFormat == TrackFileFormat.KML ? new KmlImporter(context)
: new GpxImporter(context);
AbstractImporter importer = trackFileFormat == TrackFileFormat.KML ? new KmlImporter(
context, -1L)
: new GpxImporter(context, -1L);
long trackIds[] = importer.importFile(new FileInputStream(file));
int length = trackIds.length;
if (length > 0) {
@@ -71,14 +71,15 @@ public class KmlImporter extends AbstractImporter {
* Constructor.
*
* @param context the context
* @param importTrackId track id to import to. -1L to import to a new track.
*/
public KmlImporter(Context context) {
super(context);
public KmlImporter(Context context, long importTrackId) {
super(context, importTrackId);
}
@VisibleForTesting
public KmlImporter(Context context, MyTracksProviderUtils myTracksProviderUtils) {
super(context, myTracksProviderUtils);
super(context, -1L, myTracksProviderUtils);
}
@Override
@@ -1,106 +0,0 @@
/*
* Copyright 2012 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.io.sendtogoogle;
import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
/**
* An interstitial to confirm sharing with friends.
*
* @author Jimmy Shih
*/
public class ConfirmSharingActivity extends Activity {
private static final int DIALOG_ID = 0;
private SendRequest sendRequest;
private CheckBox checkBox;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sendRequest = getIntent().getParcelableExtra(SendRequest.SEND_REQUEST_KEY);
if (PreferencesUtils.getBoolean(this, R.string.show_confirm_sharing_dialog_key,
PreferencesUtils.SHOW_CONFIRM_SHARING_DIALOG_DEFAULT)) {
showDialog(DIALOG_ID);
} else {
startNextActivity();
}
}
@Override
protected Dialog onCreateDialog(int id) {
if (id != DIALOG_ID) {
return null;
}
View view = getLayoutInflater().inflate(R.layout.confirm_dialog, null);
TextView textView = (TextView) view.findViewById(R.id.confirm_dialog_message);
textView.setText(StringUtils.getHtml(
this, R.string.share_track_confirm_message, R.string.maps_public_unlisted_url));
checkBox = (CheckBox) view.findViewById(R.id.confirm_dialog_check_box);
DialogInterface.OnClickListener okListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int button) {
PreferencesUtils.setBoolean(ConfirmSharingActivity.this,
R.string.show_confirm_sharing_dialog_key, !checkBox.isChecked());
startNextActivity();
}
};
DialogInterface.OnClickListener cancelListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int button) {
finish();
}
};
Dialog dialog = DialogUtils.createConfirmationDialog(
this, -1, view, okListener, cancelListener);
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
finish();
}
});
return dialog;
}
/**
* Starts the next activity for sharing with friends and finishes this
* activity.
*/
private void startNextActivity() {
Intent intent = IntentUtils.newIntent(this, AccountChooserActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
startActivity(intent);
finish();
}
}
@@ -33,6 +33,7 @@ public class SendRequest implements Parcelable {
private long trackId = -1L;
private String sharingAppPackageName = null;
private String sharingAppClassName = null;
private String acl = null;
private boolean sendDrive = false;
private boolean sendMaps = false;
private boolean sendFusionTables = false;
@@ -93,6 +94,22 @@ public class SendRequest implements Parcelable {
this.sharingAppClassName = sharingAppClassName;
}
/**
* Gets the email address of the user to share the track with.
*/
public String getAcl() {
return acl;
}
/**
* Sets the email address of the user to share the track with.
*
* @param acl the email address
*/
public void setAcl(String acl) {
this.acl = acl;
}
/**
* True if the user has selected the send to Google Drive option.
*/
@@ -279,6 +296,7 @@ public class SendRequest implements Parcelable {
trackId = in.readLong();
sharingAppPackageName = in.readString();
sharingAppClassName = in.readString();
acl = in.readString();
sendDrive = in.readByte() == 1;
sendMaps = in.readByte() == 1;
sendFusionTables = in.readByte() == 1;
@@ -302,6 +320,7 @@ public class SendRequest implements Parcelable {
out.writeLong(trackId);
out.writeString(sharingAppPackageName);
out.writeString(sharingAppClassName);
out.writeString(acl);
out.writeByte((byte) (sendDrive ? 1 : 0));
out.writeByte((byte) (sendMaps ? 1 : 0));
out.writeByte((byte) (sendFusionTables ? 1 : 0));
@@ -254,7 +254,7 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
InputStream inputStream = downloadDriveFile(driveFile);
// TODO: should retry if inputStream is null
if (inputStream != null) {
KmlImporter kmlImporter = new KmlImporter(context);
KmlImporter kmlImporter = new KmlImporter(context, -1L);
long[] tracksIds = kmlImporter.importFile(inputStream);
if (tracksIds.length == 1) {
Track track = myTracksProviderUtils.getTrack(tracksIds[0]);
@@ -333,29 +333,20 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
track.setModifiedTime(driveModifiedTime);
myTracksProviderUtils.updateTrack(track);
} else {
KmlImporter kmlImporter = new KmlImporter(context);
KmlImporter kmlImporter = new KmlImporter(context, track.getId());
long[] tracksIds = kmlImporter.importFile(inputStream);
if (tracksIds.length == 1) {
// Delete track and update the new imported track
track.setDriveId("");
myTracksProviderUtils.updateTrack(track);
myTracksProviderUtils.deleteTrack(track.getId());
Track newTrack = myTracksProviderUtils.getTrack(tracksIds[0]);
newTrack.setDriveId(driveFile.getId());
newTrack.setModifiedTime(driveModifiedTime);
myTracksProviderUtils.updateTrack(newTrack);
} else {
/*
* Do not need to retry, the drive file is invalid. Remove imported
* tracks and update the track modified time.
* TODO: Should revert the track back to the original.
*/
Log.e(TAG, "Unable to update drive change for track " + track.getName());
for (int i = 0; i < tracksIds.length; i++) {
myTracksProviderUtils.deleteTrack(tracksIds[i]);
}
track.setModifiedTime(driveModifiedTime);
myTracksProviderUtils.updateTrack(track);
Log.e(
TAG, "Unable to update drive change. Imported size is not 1 for " + track.getName());
}
}
}
@@ -295,13 +295,14 @@ public class SyncUtils {
* @param drive the drive
* @param folderId the folder id
* @param track the track
* @return the added drive file id or null.
*/
public static boolean addDriveFile(Context context, MyTracksProviderUtils myTracksProviderUtils,
public static String addDriveFile(Context context, MyTracksProviderUtils myTracksProviderUtils,
Drive drive, String folderId, Track track) throws IOException {
java.io.File file = getFile(context, myTracksProviderUtils, track);
if (file == null) {
Log.e(TAG, "Unable to add Drive file. File is null for track " + track.getName());
return false;
return null;
}
try {
@@ -323,12 +324,13 @@ public class SyncUtils {
File uploadedFile = drive.files().insert(newMetaData, fileContent).execute();
if (uploadedFile == null) {
Log.e(TAG, "Unable to add Drive file. Uploaded file is null for track " + track.getName());
return false;
return null;
}
track.setDriveId(uploadedFile.getId());
String id = uploadedFile.getId();
track.setDriveId(id);
track.setModifiedTime(uploadedFile.getModifiedDate().getValue());
myTracksProviderUtils.updateTrack(track);
return true;
return id;
} finally {
file.delete();
}
@@ -99,7 +99,12 @@ public class GoogleSettingsActivity extends AbstractSettingsActivity {
String googleAccount = PreferencesUtils.getString(
GoogleSettingsActivity.this, R.string.google_account_key,
PreferencesUtils.GOOGLE_ACCOUNT_DEFAULT);
if (!newGoogleAccount.equals(googleAccount)) {
if (googleAccount == null
|| googleAccount.equals(PreferencesUtils.GOOGLE_ACCOUNT_DEFAULT)) {
updateUiByAccountName(newGoogleAccount);
return true;
}
if (!googleAccount.equals(newGoogleAccount)) {
Bundle newBundle = new Bundle();
newBundle.putString(ACCOUNT_NAME_KEY, newGoogleAccount);
showDialog(DIALOG_CONFIRM_SWITCH_ACCOUNT, newBundle);
@@ -49,6 +49,11 @@ public class PreferencesUtils {
public static final boolean CHART_SHOW_HEART_RATE_DEFAULT = true;
public static final boolean CHART_SHOW_POWER_DEFAULT = true;
public static final boolean CHART_SHOW_SPEED_DEFAULT = true;
public static final boolean CONFIRM_PLAY_EARTH_DEFAULT = true;
public static final boolean CONFIRM_SHARE_DRIVE_DEFAULT = true;
public static final boolean CONFIRM_SHARE_MAP_DEFAULT = true;
public static final String DEFAULT_ACTIVITY_DEFAULT = "";
public static final boolean DEFAULT_MAP_PUBLIC_DEFAULT = false;
public static final String DRIVE_DELETED_LIST_DEFAULT = "";
@@ -85,8 +90,6 @@ public class PreferencesUtils {
public static final boolean SEND_TO_MAPS_DEFAULT = false;
public static final String SENSOR_TYPE_DEFAULT = "NONE";
public static final boolean SHOW_CONFIRM_PLAY_DIALOG_DEFAULT = true;
public static final boolean SHOW_CONFIRM_SHARING_DIALOG_DEFAULT = true;
public static final int SPLIT_FREQUENCY_DEFAULT = 0;
public static final boolean STATS_SHOW_COORDINATE_DEFAULT = false;
public static final boolean STATS_SHOW_ELEVATION_DEFAULT = false;
@@ -40,6 +40,13 @@ public interface MyTracksProviderUtils {
*/
public static final String AUTHORITY = "com.google.android.maps.mytracks";
/**
* Clears a track. Removes waypoints and trackpoints. Only keeps the track id.
*
* @param trackId the track id
*/
public void clearTrack(long trackId);
/**
* Creates a {@link Track} from a cursor.
*
@@ -50,6 +50,14 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
this.contentResolver = contentResolver;
}
@Override
public void clearTrack(long trackId) {
deleteTrackPointsAndWaypoints(trackId);
Track track = new Track();
track.setId(trackId);
updateTrack(track);
}
@Override
public Track createTrack(Cursor cursor) {
int idIndex = cursor.getColumnIndexOrThrow(TracksColumns._ID);
@@ -176,6 +184,21 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
@Override
public void deleteTrack(long trackId) {
deleteTrackPointsAndWaypoints(trackId);
// Delete track last since it triggers a database vaccum call
contentResolver.delete(TracksColumns.CONTENT_URI, TracksColumns._ID + "=?",
new String[] { Long.toString(trackId) });
}
/**
* Deletes track points and waypoints of a track. Assumes
* {@link TracksColumns#STARTID}, {@link TracksColumns#STOPID}, and
* {@link TracksColumns#NUMPOINTS} will be updated by the caller.
*
* @param trackId the track id
*/
private void deleteTrackPointsAndWaypoints(long trackId) {
Track track = getTrack(trackId);
if (track != null) {
String where = TrackPointsColumns._ID + ">=? AND " + TrackPointsColumns._ID + "<=?";
@@ -185,10 +208,6 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
}
contentResolver.delete(WaypointsColumns.CONTENT_URI, WaypointsColumns.TRACKID + "=?",
new String[] { Long.toString(trackId) });
// Delete track last since it triggers a database vaccum call
contentResolver.delete(TracksColumns.CONTENT_URI, TracksColumns._ID + "=?",
new String[] { Long.toString(trackId) });
}
@Override