Merge heads

This commit is contained in:
youtaol
2013-08-15 09:46:14 +08:00
parent 4d8c44782e
commit d64b6a4d93
30 changed files with 785 additions and 189 deletions
+3
View File
@@ -107,6 +107,9 @@ limitations under the License.
<uses-feature <uses-feature
android:name="android.hardware.bluetooth" android:name="android.hardware.bluetooth"
android:required="false" /> android:required="false" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-feature <uses-feature
android:name="android.hardware.faketouch" android:name="android.hardware.faketouch"
android:required="false" /> android:required="false" />
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

+62 -34
View File
@@ -24,9 +24,9 @@ limitations under the License.
android:shrinkColumns="1" android:shrinkColumns="1"
android:stretchColumns="1" android:stretchColumns="1"
style="@style/ListItem" > style="@style/ListItem" >
<TableRow <!-- First row -->
android:layout_height="wrap_content" <TableRow>
android:layout_width="match_parent" > <!-- First column -->
<ImageView <ImageView
android:contentDescription="@string/icon_track" android:contentDescription="@string/icon_track"
android:id="@+id/list_item_icon" android:id="@+id/list_item_icon"
@@ -35,39 +35,67 @@ limitations under the License.
android:layout_marginLeft="8dp" android:layout_marginLeft="8dp"
android:layout_marginRight="8dp" android:layout_marginRight="8dp"
android:layout_width="wrap_content" /> android:layout_width="wrap_content" />
<TableLayout <!-- Second column -->
<LinearLayout
android:baselineAligned="false"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="match_parent" android:layout_width="match_parent" >
android:shrinkColumns="0" <LinearLayout
android:stretchColumns="0" > android:layout_height="wrap_content"
<TableRow> android:layout_weight="3"
<TextView android:layout_width="0dp" >
android:id="@+id/list_item_name" <TableLayout
android:layout_gravity="bottom" android:layout_height="wrap_content"
android:layout_width="fill_parent" android:layout_weight="1"
android:singleLine="true" android:layout_width="0dp"
style="@style/TextMedium" /> android:shrinkColumns="*"
<TextView android:stretchColumns="*" >
android:id="@+id/list_item_date" <TableRow>
style="@style/ListItemDate" /> <TextView
</TableRow> android:ellipsize="end"
<TableRow> android:id="@+id/list_item_name"
<!-- Need to match the style set in ListItemUtils.setListItem --> android:singleLine="true"
<TextView style="@style/TextMedium" />
android:id="@+id/list_item_time_distance" </TableRow>
android:layout_gravity="bottom" <TableRow>
android:layout_width="fill_parent" <!-- Need to match the style set in ListItemUtils.setListItem -->
android:singleLine="true" <TextView
style="@style/TextSmall" /> android:ellipsize="end"
<TextView android:id="@+id/list_item_time_distance"
android:id="@+id/list_item_time" android:singleLine="true"
style="@style/ListItemDate" /> style="@style/TextSmall" />
</TableRow> </TableRow>
</TableLayout> </TableLayout>
<ImageView
android:id="@+id/list_item_photo"
android:layout_gravity="center"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_weight="1"
android:layout_width="0dp"
android:scaleType="centerCrop" />
</LinearLayout>
<TableLayout
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_width="0dp"
android:shrinkColumns="*"
android:stretchColumns="*" >
<TableRow>
<TextView
android:id="@+id/list_item_date"
style="@style/ListItemDate" />
</TableRow>
<TableRow>
<TextView
android:id="@+id/list_item_time"
style="@style/ListItemDate" />
</TableRow>
</TableLayout>
</LinearLayout>
</TableRow> </TableRow>
<TableRow <!-- Second row -->
android:layout_height="wrap_content" <TableRow>
android:layout_width="match_parent" >
<TextView <TextView
android:id="@+id/list_item_description" android:id="@+id/list_item_description"
android:layout_column="1" android:layout_column="1"
@@ -0,0 +1,24 @@
<?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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent" >
<android.support.v4.view.ViewPager
android:id="@+id/maker_detail_activity_view_pager"
android:layout_height="match_parent"
android:layout_width="match_parent" />
</LinearLayout>
@@ -21,14 +21,19 @@ limitations under the License.
android:layout_width="match_parent" android:layout_width="match_parent"
android:orientation="vertical" android:orientation="vertical"
android:padding="8dp" > android:padding="8dp" >
<TextView
android:id="@+id/marker_detail_name"
style="@style/TextLarge" />
<LinearLayout <LinearLayout
android:id="@+id/marker_detail_waypoint_section" android:id="@+id/marker_detail_waypoint_section"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:orientation="vertical" > android:orientation="vertical" >
<ImageView
android:id="@+id/marker_detail_waypoint_photo"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:scaleType="centerInside" />
<TextView
android:id="@+id/marker_detail_waypoint_name"
style="@style/TextLarge.WithTopMargin" />
<TextView <TextView
android:id="@+id/marker_detail_waypoint_marker_type" android:id="@+id/marker_detail_waypoint_marker_type"
style="@style/TextLarge.WithTopMargin" /> style="@style/TextLarge.WithTopMargin" />
@@ -41,6 +46,9 @@ limitations under the License.
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:orientation="vertical" > android:orientation="vertical" >
<TextView
android:id="@+id/marker_detail_statistics_name"
style="@style/TextLarge" />
<TextView <TextView
android:text="@string/marker_detail_statistics_title" android:text="@string/marker_detail_statistics_title"
style="@style/TextLarge.WithTopMargin" /> style="@style/TextLarge.WithTopMargin" />
+1 -1
View File
@@ -17,7 +17,7 @@ limitations under the License.
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item <item
android:icon="@drawable/ic_menu_map_layer" android:icon="@drawable/ic_menu_map_layer"
android:orderInCategory="5" android:orderInCategory="6"
android:showAsAction="ifRoom" android:showAsAction="ifRoom"
android:title="@string/menu_map_layer"> android:title="@string/menu_map_layer">
<menu> <menu>
+19 -13
View File
@@ -21,68 +21,74 @@ limitations under the License.
android:orderInCategory="1" android:orderInCategory="1"
android:showAsAction="ifRoom" android:showAsAction="ifRoom"
android:title="@string/menu_insert_marker"/> android:title="@string/menu_insert_marker"/>
<item
android:icon="@drawable/ic_menu_insert_photo"
android:id="@+id/track_detail_insert_photo"
android:orderInCategory="2"
android:showAsAction="ifRoom"
android:title="@string/menu_insert_photo"/>
<item <item
android:icon="@drawable/ic_menu_play" android:icon="@drawable/ic_menu_play"
android:id="@+id/track_detail_play" android:id="@+id/track_detail_play"
android:orderInCategory="2" android:orderInCategory="3"
android:showAsAction="ifRoom" android:showAsAction="ifRoom"
android:title="@string/menu_play"/> android:title="@string/menu_play"/>
<item <item
android:icon="@drawable/ic_menu_share" android:icon="@drawable/ic_menu_share"
android:id="@+id/track_detail_share" android:id="@+id/track_detail_share"
android:orderInCategory="3" android:orderInCategory="4"
android:showAsAction="ifRoom" android:showAsAction="ifRoom"
android:title="@string/menu_share"/> android:title="@string/menu_share"/>
<item <item
android:icon="@drawable/ic_menu_markers" android:icon="@drawable/ic_menu_markers"
android:id="@+id/track_detail_markers" android:id="@+id/track_detail_markers"
android:orderInCategory="4" android:orderInCategory="5"
android:showAsAction="ifRoom" android:showAsAction="ifRoom"
android:title="@string/menu_markers"/> android:title="@string/menu_markers"/>
<!-- android:orderInCategory="5" is in map.xml --> <!-- android:orderInCategory="6" is in map.xml -->
<item <item
android:icon="@drawable/ic_menu_export" android:icon="@drawable/ic_menu_export"
android:id="@+id/track_detail_export" android:id="@+id/track_detail_export"
android:orderInCategory="6" android:orderInCategory="7"
android:title="@string/menu_export"/> android:title="@string/menu_export"/>
<item <item
android:icon="@drawable/ic_menu_edit" android:icon="@drawable/ic_menu_edit"
android:id="@+id/track_detail_edit" android:id="@+id/track_detail_edit"
android:orderInCategory="7" android:orderInCategory="8"
android:title="@string/menu_edit"/> android:title="@string/menu_edit"/>
<item <item
android:icon="@drawable/ic_menu_delete" android:icon="@drawable/ic_menu_delete"
android:id="@+id/track_detail_delete" android:id="@+id/track_detail_delete"
android:orderInCategory="8" android:orderInCategory="9"
android:title="@string/menu_delete"/> android:title="@string/menu_delete"/>
<item <item
android:icon="@drawable/ic_menu_voice_frequency" android:icon="@drawable/ic_menu_voice_frequency"
android:id="@+id/track_detail_voice_frequency" android:id="@+id/track_detail_voice_frequency"
android:orderInCategory="9" android:orderInCategory="10"
android:title="@string/menu_voice_frequency"/> android:title="@string/menu_voice_frequency"/>
<item <item
android:icon="@drawable/ic_menu_split_frequency" android:icon="@drawable/ic_menu_split_frequency"
android:id="@+id/track_detail_split_frequency" android:id="@+id/track_detail_split_frequency"
android:orderInCategory="10" android:orderInCategory="11"
android:title="@string/menu_split_frequency"/> android:title="@string/menu_split_frequency"/>
<item <item
android:icon="@drawable/ic_menu_sensor_state" android:icon="@drawable/ic_menu_sensor_state"
android:id="@+id/track_detail_sensor_state" android:id="@+id/track_detail_sensor_state"
android:orderInCategory="11" android:orderInCategory="12"
android:title="@string/menu_sensor_state"/> android:title="@string/menu_sensor_state"/>
<item <item
android:icon="@drawable/ic_menu_settings" android:icon="@drawable/ic_menu_settings"
android:id="@+id/track_detail_settings" android:id="@+id/track_detail_settings"
android:orderInCategory="12" android:orderInCategory="13"
android:title="@string/menu_settings"/> android:title="@string/menu_settings"/>
<item <item
android:icon="@drawable/ic_menu_feedback" android:icon="@drawable/ic_menu_feedback"
android:id="@+id/track_detail_feedback" android:id="@+id/track_detail_feedback"
android:orderInCategory="13" android:orderInCategory="14"
android:title="@string/menu_feedback"/> android:title="@string/menu_feedback"/>
<item <item
android:icon="@drawable/ic_menu_help" android:icon="@drawable/ic_menu_help"
android:id="@+id/track_detail_help" android:id="@+id/track_detail_help"
android:orderInCategory="14" android:orderInCategory="15"
android:title="@string/menu_help"/> android:title="@string/menu_help"/>
</menu> </menu>
+10
View File
@@ -1005,6 +1005,10 @@ limitations under the License.
translation_description="When deleting multiple markers, the confirmation message."> translation_description="When deleting multiple markers, the confirmation message.">
All markers for this track will be permanently deleted from the device. All markers for this track will be permanently deleted from the device.
</string> </string>
<string name="marker_insert_photo_error"
translation_description="The error message when unable to insert a photo marker.">
Unable to insert a photo marker. Try again.
</string>
<string name="marker_label_end" <string name="marker_label_end"
translation_description="When inserting a marker to indicate the end of a track, the marker's translation_description="When inserting a marker to indicate the end of a track, the marker's
name. E.g., 'track_name (End)'. name. E.g., 'track_name (End)'.
@@ -1124,6 +1128,12 @@ limitations under the License.
Character limit: ~20 (1 line)"> Character limit: ~20 (1 line)">
Insert marker Insert marker
</string> </string>
<string name="menu_insert_photo"
translation_description="In the menu, to insert a photo.
Character limit: ~20 (1 line)">
Insert photo
</string>
<string name="menu_map" <string name="menu_map"
translation_description="In the menu, under the map layer option, the submenu to display normal translation_description="In the menu, under the map layer option, the submenu to display normal
map. map.
@@ -80,8 +80,9 @@ public abstract class AbstractSendToGoogleActivity extends AbstractMyTracksActiv
private static final int FUSION_TABLES_REQUEST_CODE = 1; private static final int FUSION_TABLES_REQUEST_CODE = 1;
private static final int SPREADSHEETS_REQUEST_CODE = 2; private static final int SPREADSHEETS_REQUEST_CODE = 2;
private static final int DELETE_REQUEST_CODE = 3; private static final int DELETE_REQUEST_CODE = 3;
protected static final int GOOGLE_PLAY_SERVICES_REQUEST_CODE = 4; protected static final int GOOGLE_PLAY_SERVICES_REQUEST_CODE = 4;
protected static final int CAMERA_REQUEST_CODE = 5;
private SendRequest sendRequest; private SendRequest sendRequest;
@Override @Override
@@ -17,22 +17,22 @@
package com.google.android.apps.mytracks; package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint; import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
import com.google.android.apps.mytracks.fragments.DeleteMarkerDialogFragment;
import com.google.android.apps.mytracks.fragments.DeleteMarkerDialogFragment.DeleteMarkerCaller; import com.google.android.apps.mytracks.fragments.DeleteMarkerDialogFragment.DeleteMarkerCaller;
import com.google.android.apps.mytracks.fragments.MarkerDetailFragment;
import com.google.android.apps.mytracks.util.IntentUtils; import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.StatsUtils;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log; import android.util.Log;
import android.view.Menu;
import android.view.MenuItem; import java.util.ArrayList;
import android.view.View;
import android.widget.TextView;
/** /**
* An activity to display marker detail info. * An activity to display marker detail info.
@@ -44,72 +44,59 @@ public class MarkerDetailActivity extends AbstractMyTracksActivity implements De
public static final String EXTRA_MARKER_ID = "marker_id"; public static final String EXTRA_MARKER_ID = "marker_id";
private static final String TAG = MarkerDetailActivity.class.getSimpleName(); private static final String TAG = MarkerDetailActivity.class.getSimpleName();
private MyTracksProviderUtils myTracksProviderUtils;
private long markerId;
private Waypoint waypoint; private Waypoint waypoint;
private ArrayList<Long> markerIds;
private TextView name;
private View waypointSection;
private View statisticsSection;
@Override @Override
protected void onCreate(Bundle bundle) { protected void onCreate(Bundle bundle) {
super.onCreate(bundle); super.onCreate(bundle);
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(this); long markerId = getIntent().getLongExtra(EXTRA_MARKER_ID, -1L);
markerId = getIntent().getLongExtra(EXTRA_MARKER_ID, -1L);
if (markerId == -1L) { if (markerId == -1L) {
Log.d(TAG, "invalid marker id"); Log.d(TAG, "invalid marker id");
finish(); finish();
return; return;
} }
name = (TextView) findViewById(R.id.marker_detail_name);
waypointSection = findViewById(R.id.marker_detail_waypoint_section); MyTracksProviderUtils myTracksProviderUtils = MyTracksProviderUtils.Factory.get(this);
statisticsSection = findViewById(R.id.marker_detail_statistics_section); waypoint = myTracksProviderUtils.getWaypoint(markerId);
markerIds = new ArrayList<Long>();
int markerIndex = -1;
Cursor cursor = null;
try {
cursor = myTracksProviderUtils.getWaypointCursor(waypoint.getTrackId(), -1L, -1);
if (cursor != null && cursor.moveToFirst()) {
/*
* Yes, this will skip the first waypoint and that is intentional as the
* first waypoint holds the stats for the track.
*/
while (cursor.moveToNext()) {
Waypoint current = myTracksProviderUtils.createWaypoint(cursor);
markerIds.add(current.getId());
if (current.getId() == markerId) {
markerIndex = markerIds.size() - 1;
}
}
}
} finally {
if (cursor != null) {
cursor.close();
}
}
ViewPager viewPager = (ViewPager) findViewById(R.id.maker_detail_activity_view_pager);
viewPager.setAdapter(new MarkerDetailPagerAdapter(getSupportFragmentManager()));
if (markerIndex != -1) {
viewPager.setCurrentItem(markerIndex);
}
} }
@Override @Override
protected int getLayoutResId() { protected int getLayoutResId() {
return R.layout.marker_detail; return R.layout.marker_detail_activity;
}
@Override
protected void onResume() {
super.onResume();
waypoint = MyTracksProviderUtils.Factory.get(this).getWaypoint(markerId);
if (waypoint == null) {
Log.d(TAG, "waypoint is null");
finish();
return;
}
name.setText(getString(R.string.generic_name_line, waypoint.getName()));
if (waypoint.getType() == WaypointType.WAYPOINT) {
waypointSection.setVisibility(View.VISIBLE);
statisticsSection.setVisibility(View.GONE);
TextView markerType = (TextView) findViewById(R.id.marker_detail_waypoint_marker_type);
markerType.setText(
getString(R.string.marker_detail_waypoint_marker_type, waypoint.getCategory()));
TextView description = (TextView) findViewById(R.id.marker_detail_waypoint_description);
description.setText(getString(R.string.generic_description_line, waypoint.getDescription()));
} else {
waypointSection.setVisibility(View.GONE);
statisticsSection.setVisibility(View.VISIBLE);
StatsUtils.setTripStatisticsValues(this, waypoint.getTripStatistics());
StatsUtils.setLocationValues(this, waypoint.getLocation(), false);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.marker_detail, menu);
Track track = myTracksProviderUtils.getTrack(waypoint.getTrackId());
boolean isSharedWithMe = track != null ? track.isSharedWithMe() : true;
menu.findItem(R.id.marker_detail_edit).setVisible(!isSharedWithMe);
menu.findItem(R.id.marker_detail_delete).setVisible(!isSharedWithMe);
return true;
} }
@Override @Override
@@ -120,29 +107,6 @@ public class MarkerDetailActivity extends AbstractMyTracksActivity implements De
finish(); finish();
} }
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent intent;
switch (item.getItemId()) {
case R.id.marker_detail_show_on_map:
intent = IntentUtils.newIntent(this, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.EXTRA_MARKER_ID, markerId);
startActivity(intent);
return true;
case R.id.marker_detail_edit:
intent = IntentUtils.newIntent(this, MarkerEditActivity.class)
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, markerId);
startActivity(intent);
return true;
case R.id.marker_detail_delete:
DeleteMarkerDialogFragment.newInstance(new long[] { markerId })
.show(getSupportFragmentManager(), DeleteMarkerDialogFragment.DELETE_MARKER_DIALOG_TAG);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override @Override
public void onDeleteMarkerDone() { public void onDeleteMarkerDone() {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@@ -152,4 +116,26 @@ public class MarkerDetailActivity extends AbstractMyTracksActivity implements De
} }
}); });
} }
}
/**
* Marker detail pager adapter.
*
* @author Jimmy Shih
*/
private class MarkerDetailPagerAdapter extends FragmentStatePagerAdapter {
public MarkerDetailPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
@Override
public Fragment getItem(int position) {
return MarkerDetailFragment.newInstance(markerIds.get(position));
}
@Override
public int getCount() {
return markerIds.size();
}
}
}
@@ -169,6 +169,7 @@ public class MarkerEditActivity extends AbstractMyTracksActivity {
waypointName.getText().toString(), waypointName.getText().toString(),
waypointMarkerType.getText().toString(), waypointMarkerType.getText().toString(),
waypointDescription.getText().toString(), waypointDescription.getText().toString(),
null,
null); null);
TrackRecordingServiceConnectionUtils.addMarker( TrackRecordingServiceConnectionUtils.addMarker(
this, trackRecordingServiceConnection, waypointCreationRequest); this, trackRecordingServiceConnection, waypointCreationRequest);
@@ -63,7 +63,7 @@ public class MarkerListActivity extends AbstractMyTracksActivity implements Dele
private static final String[] PROJECTION = new String[] { WaypointsColumns._ID, private static final String[] PROJECTION = new String[] { WaypointsColumns._ID,
WaypointsColumns.NAME, WaypointsColumns.DESCRIPTION, WaypointsColumns.CATEGORY, WaypointsColumns.NAME, WaypointsColumns.DESCRIPTION, WaypointsColumns.CATEGORY,
WaypointsColumns.TYPE, WaypointsColumns.TIME }; WaypointsColumns.TYPE, WaypointsColumns.TIME, WaypointsColumns.PHOTOURL };
// Callback when an item is selected in the contextual action mode // Callback when an item is selected in the contextual action mode
private ContextualActionModeCallback private ContextualActionModeCallback
@@ -173,19 +173,25 @@ public class MarkerListActivity extends AbstractMyTracksActivity implements Dele
public void bindView(View view, Context context, Cursor cursor) { public void bindView(View view, Context context, Cursor cursor) {
int typeIndex = cursor.getColumnIndex(WaypointsColumns.TYPE); int typeIndex = cursor.getColumnIndex(WaypointsColumns.TYPE);
int nameIndex = cursor.getColumnIndex(WaypointsColumns.NAME); int nameIndex = cursor.getColumnIndex(WaypointsColumns.NAME);
int categoryIndex = cursor.getColumnIndex(WaypointsColumns.CATEGORY); int photoUrlIndex = cursor.getColumnIndex(WaypointsColumns.PHOTOURL);
int timeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.TIME); int timeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.TIME);
int categoryIndex = cursor.getColumnIndex(WaypointsColumns.CATEGORY);
int descriptionIndex = cursor.getColumnIndex(WaypointsColumns.DESCRIPTION); int descriptionIndex = cursor.getColumnIndex(WaypointsColumns.DESCRIPTION);
boolean statistics = WaypointType.values()[cursor.getInt(typeIndex)] boolean statistics = WaypointType.values()[cursor.getInt(typeIndex)]
== WaypointType.STATISTICS; == WaypointType.STATISTICS;
int iconId = statistics ? R.drawable.ic_marker_yellow_pushpin int iconId = statistics ? R.drawable.ic_marker_yellow_pushpin
: R.drawable.ic_marker_blue_pushpin; : R.drawable.ic_marker_blue_pushpin;
String name = cursor.getString(nameIndex);
String sharedOwner = track.getSharedOwner();
String photoUrl = cursor.getString(photoUrlIndex);
long time = cursor.getLong(timeIndex);
String category = statistics ? null : cursor.getString(categoryIndex); String category = statistics ? null : cursor.getString(categoryIndex);
String description = statistics ? null : cursor.getString(descriptionIndex); String description = statistics ? null : cursor.getString(descriptionIndex);
ListItemUtils.setListItem(MarkerListActivity.this, view, false, true, iconId, ListItemUtils.setListItem(MarkerListActivity.this, view, false, true, iconId,
R.string.icon_marker, cursor.getString(nameIndex), category, null, null, R.string.icon_marker, name, sharedOwner, null, null, photoUrl, time, category,
cursor.getLong(timeIndex), description, track.getSharedOwner()); description);
} }
}; };
listView.setAdapter(resourceCursorAdapter); listView.setAdapter(resourceCursorAdapter);
@@ -83,12 +83,14 @@ public class SearchListActivity extends AbstractSendToGoogleActivity implements
private static final String ICON_ID_FIELD = "icon"; private static final String ICON_ID_FIELD = "icon";
private static final String ICON_CONTENT_DESCRIPTION_ID_FIELD = "iconContentDescription"; private static final String ICON_CONTENT_DESCRIPTION_ID_FIELD = "iconContentDescription";
private static final String NAME_FIELD = "name"; private static final String NAME_FIELD = "name";
private static final String CATEGORY_FIELD = "category"; private static final String SHARED_OWNER_FIELD = "sharedOwner";
private static final String TOTAL_TIME_FIELD = "totalTime"; private static final String TOTAL_TIME_FIELD = "totalTime";
private static final String TOTAL_DISTANCE_FIELD = "totalDistance"; private static final String TOTAL_DISTANCE_FIELD = "totalDistance";
private static final String PHOTO_URL_FIELD = "photoUrl";
private static final String START_TIME_FIELD = "startTime"; private static final String START_TIME_FIELD = "startTime";
private static final String CATEGORY_FIELD = "category";
private static final String DESCRIPTION_FIELD = "description"; private static final String DESCRIPTION_FIELD = "description";
private static final String SHARED_OWNER_FIELD = "sharedOwner";
private static final String TRACK_ID_FIELD = "trackId"; private static final String TRACK_ID_FIELD = "trackId";
private static final String MARKER_ID_FIELD = "markerId"; private static final String MARKER_ID_FIELD = "markerId";
@@ -228,15 +230,17 @@ public class SearchListActivity extends AbstractSendToGoogleActivity implements
int iconId = (Integer) resultMap.get(ICON_ID_FIELD); int iconId = (Integer) resultMap.get(ICON_ID_FIELD);
int iconContentDescriptionId = (Integer) resultMap.get(ICON_CONTENT_DESCRIPTION_ID_FIELD); int iconContentDescriptionId = (Integer) resultMap.get(ICON_CONTENT_DESCRIPTION_ID_FIELD);
String name = (String) resultMap.get(NAME_FIELD); String name = (String) resultMap.get(NAME_FIELD);
String category = (String) resultMap.get(CATEGORY_FIELD); String sharedOwner = (String) resultMap.get(SHARED_OWNER_FIELD);
String totalTime = (String) resultMap.get(TOTAL_TIME_FIELD); String totalTime = (String) resultMap.get(TOTAL_TIME_FIELD);
String totalDistance = (String) resultMap.get(TOTAL_DISTANCE_FIELD); String totalDistance = (String) resultMap.get(TOTAL_DISTANCE_FIELD);
String photoUrl = (String) resultMap.get(PHOTO_URL_FIELD);
Long startTime = (Long) resultMap.get(START_TIME_FIELD); Long startTime = (Long) resultMap.get(START_TIME_FIELD);
String category = (String) resultMap.get(CATEGORY_FIELD);
String description = (String) resultMap.get(DESCRIPTION_FIELD); String description = (String) resultMap.get(DESCRIPTION_FIELD);
String sharedOwner = (String) resultMap.get(SHARED_OWNER_FIELD);
ListItemUtils.setListItem(SearchListActivity.this, view, isRecording, isPaused, iconId, ListItemUtils.setListItem(SearchListActivity.this, view, isRecording, isPaused, iconId,
iconContentDescriptionId, name, category, totalTime, totalDistance, startTime, iconContentDescriptionId, name, sharedOwner, totalTime, totalDistance, photoUrl,
description, sharedOwner); startTime, category, description);
return view; return view;
} }
}; };
@@ -487,14 +491,15 @@ public class SearchListActivity extends AbstractSendToGoogleActivity implements
statistics ? R.drawable.ic_marker_yellow_pushpin : R.drawable.ic_marker_blue_pushpin); statistics ? R.drawable.ic_marker_yellow_pushpin : R.drawable.ic_marker_blue_pushpin);
resultMap.put(ICON_CONTENT_DESCRIPTION_ID_FIELD, R.string.icon_marker); resultMap.put(ICON_CONTENT_DESCRIPTION_ID_FIELD, R.string.icon_marker);
resultMap.put(NAME_FIELD, waypoint.getName()); resultMap.put(NAME_FIELD, waypoint.getName());
resultMap.put(CATEGORY_FIELD, statistics ? null : waypoint.getCategory()); resultMap.put(SHARED_OWNER_FIELD, sharedOwner);
// Display the marker's track name in the total time field // Display the marker's track name in the total time field
resultMap.put(TOTAL_TIME_FIELD, trackName == null ? null resultMap.put(TOTAL_TIME_FIELD, trackName == null ? null
: getString(R.string.search_list_marker_track_location, trackName)); : getString(R.string.search_list_marker_track_location, trackName));
resultMap.put(TOTAL_DISTANCE_FIELD, null); resultMap.put(TOTAL_DISTANCE_FIELD, null);
resultMap.put(PHOTO_URL_FIELD, waypoint.getPhotoUrl());
resultMap.put(START_TIME_FIELD, waypoint.getLocation().getTime()); resultMap.put(START_TIME_FIELD, waypoint.getLocation().getTime());
resultMap.put(CATEGORY_FIELD, statistics ? null : waypoint.getCategory());
resultMap.put(DESCRIPTION_FIELD, statistics ? null : waypoint.getDescription()); resultMap.put(DESCRIPTION_FIELD, statistics ? null : waypoint.getDescription());
resultMap.put(SHARED_OWNER_FIELD, sharedOwner);
resultMap.put(TRACK_ID_FIELD, waypoint.getTrackId()); resultMap.put(TRACK_ID_FIELD, waypoint.getTrackId());
resultMap.put(MARKER_ID_FIELD, waypoint.getId()); resultMap.put(MARKER_ID_FIELD, waypoint.getId());
} }
@@ -515,13 +520,14 @@ public class SearchListActivity extends AbstractSendToGoogleActivity implements
resultMap.put(ICON_ID_FIELD, TrackIconUtils.getIconDrawable(icon)); resultMap.put(ICON_ID_FIELD, TrackIconUtils.getIconDrawable(icon));
resultMap.put(ICON_CONTENT_DESCRIPTION_ID_FIELD, R.string.icon_track); resultMap.put(ICON_CONTENT_DESCRIPTION_ID_FIELD, R.string.icon_track);
resultMap.put(NAME_FIELD, track.getName()); resultMap.put(NAME_FIELD, track.getName());
resultMap.put(CATEGORY_FIELD, category); resultMap.put(SHARED_OWNER_FIELD, track.getSharedOwner());
resultMap.put(TOTAL_TIME_FIELD, StringUtils.formatElapsedTime(tripStatitics.getTotalTime())); resultMap.put(TOTAL_TIME_FIELD, StringUtils.formatElapsedTime(tripStatitics.getTotalTime()));
resultMap.put(TOTAL_DISTANCE_FIELD, resultMap.put(TOTAL_DISTANCE_FIELD,
StringUtils.formatDistance(this, tripStatitics.getTotalDistance(), metricUnits)); StringUtils.formatDistance(this, tripStatitics.getTotalDistance(), metricUnits));
resultMap.put(PHOTO_URL_FIELD, null);
resultMap.put(START_TIME_FIELD, tripStatitics.getStartTime()); resultMap.put(START_TIME_FIELD, tripStatitics.getStartTime());
resultMap.put(CATEGORY_FIELD, category);
resultMap.put(DESCRIPTION_FIELD, track.getDescription()); resultMap.put(DESCRIPTION_FIELD, track.getDescription());
resultMap.put(SHARED_OWNER_FIELD, track.getSharedOwner());
resultMap.put(TRACK_ID_FIELD, track.getId()); resultMap.put(TRACK_ID_FIELD, track.getId());
resultMap.put(MARKER_ID_FIELD, null); resultMap.put(MARKER_ID_FIELD, null);
} }
@@ -20,6 +20,7 @@ import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TrackDataHub; import com.google.android.apps.mytracks.content.TrackDataHub;
import com.google.android.apps.mytracks.content.Waypoint; import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
import com.google.android.apps.mytracks.content.WaypointCreationRequest; import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.fragments.ChartFragment; import com.google.android.apps.mytracks.fragments.ChartFragment;
import com.google.android.apps.mytracks.fragments.ConfirmDeleteDialogFragment; import com.google.android.apps.mytracks.fragments.ConfirmDeleteDialogFragment;
@@ -36,6 +37,7 @@ import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection
import com.google.android.apps.mytracks.settings.SettingsActivity; import com.google.android.apps.mytracks.settings.SettingsActivity;
import com.google.android.apps.mytracks.util.AnalyticsUtils; import com.google.android.apps.mytracks.util.AnalyticsUtils;
import com.google.android.apps.mytracks.util.ApiAdapterFactory; import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.FileUtils;
import com.google.android.apps.mytracks.util.GoogleFeedbackUtils; import com.google.android.apps.mytracks.util.GoogleFeedbackUtils;
import com.google.android.apps.mytracks.util.IntentUtils; import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils; import com.google.android.apps.mytracks.util.PreferencesUtils;
@@ -46,10 +48,15 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment;
import android.os.Parcelable; import android.os.Parcelable;
import android.provider.MediaStore;
import android.support.v4.app.TaskStackBuilder; import android.support.v4.app.TaskStackBuilder;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.MotionEvent; import android.view.MotionEvent;
@@ -57,6 +64,12 @@ import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.widget.TabHost; import android.widget.TabHost;
import android.widget.TabHost.TabSpec; import android.widget.TabHost.TabSpec;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
/** /**
* An activity to show the track detail. * An activity to show the track detail.
@@ -69,9 +82,15 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity implements
public static final String EXTRA_TRACK_ID = "track_id"; public static final String EXTRA_TRACK_ID = "track_id";
public static final String EXTRA_MARKER_ID = "marker_id"; public static final String EXTRA_MARKER_ID = "marker_id";
private static final String TAG = TrackDetailActivity.class.getSimpleName();
private static final String CURRENT_TAB_TAG_KEY = "current_tab_tag_key"; private static final String CURRENT_TAB_TAG_KEY = "current_tab_tag_key";
private static final String PHOTO_URI_KEY = "photo_uri_key";
private static final String HAS_PHOTO_KEY = "has_photo_key";
// The following are set in onCreate // The following are set in onCreate
private boolean hasCamera;
private Uri photoUri;
private boolean hasPhoto;
private MyTracksProviderUtils myTracksProviderUtils; private MyTracksProviderUtils myTracksProviderUtils;
private SharedPreferences sharedPreferences; private SharedPreferences sharedPreferences;
private TrackRecordingServiceConnection trackRecordingServiceConnection; private TrackRecordingServiceConnection trackRecordingServiceConnection;
@@ -91,6 +110,7 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity implements
private String sensorType = PreferencesUtils.SENSOR_TYPE_DEFAULT; private String sensorType = PreferencesUtils.SENSOR_TYPE_DEFAULT;
private MenuItem insertMarkerMenuItem; private MenuItem insertMarkerMenuItem;
private MenuItem insertPhotoMenuItem;
private MenuItem playMenuItem; private MenuItem playMenuItem;
private MenuItem shareMenuItem; private MenuItem shareMenuItem;
private MenuItem exportMenuItem; private MenuItem exportMenuItem;
@@ -107,6 +127,19 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity implements
@Override @Override
public void run() { public void run() {
trackController.update(trackId == recordingTrackId, recordingTrackPaused); trackController.update(trackId == recordingTrackId, recordingTrackPaused);
if (hasPhoto && photoUri != null) {
WaypointCreationRequest waypointCreationRequest = new WaypointCreationRequest(
WaypointType.WAYPOINT, false, null, null, null, null, photoUri.toString());
long id = TrackRecordingServiceConnectionUtils.addMarker(
TrackDetailActivity.this, trackRecordingServiceConnection, waypointCreationRequest);
hasPhoto = false;
if (id != -1L) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(photoUri);
sendBroadcast(mediaScanIntent);
}
}
} }
}); });
} }
@@ -182,6 +215,10 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity implements
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
hasCamera = getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
photoUri = savedInstanceState != null ? (Uri) savedInstanceState.getParcelable(PHOTO_URI_KEY) : null;
hasPhoto = savedInstanceState != null ? savedInstanceState.getBoolean(HAS_PHOTO_KEY, false) : false;
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(this); myTracksProviderUtils = MyTracksProviderUtils.Factory.get(this);
handleIntent(getIntent()); handleIntent(getIntent());
@@ -266,6 +303,19 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity implements
protected void onSaveInstanceState(Bundle outState) { protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
outState.putString(CURRENT_TAB_TAG_KEY, tabHost.getCurrentTabTag()); outState.putString(CURRENT_TAB_TAG_KEY, tabHost.getCurrentTabTag());
if (photoUri != null) {
outState.putParcelable(PHOTO_URI_KEY, photoUri);
}
outState.putBoolean(HAS_PHOTO_KEY, hasPhoto);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAMERA_REQUEST_CODE) {
hasPhoto = resultCode == RESULT_OK;
} else {
super.onActivityResult(requestCode, resultCode, data);
}
} }
@Override @Override
@@ -309,6 +359,7 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity implements
.setVisible(ApiAdapterFactory.getApiAdapter().isGoogleFeedbackAvailable()); .setVisible(ApiAdapterFactory.getApiAdapter().isGoogleFeedbackAvailable());
insertMarkerMenuItem = menu.findItem(R.id.track_detail_insert_marker); insertMarkerMenuItem = menu.findItem(R.id.track_detail_insert_marker);
insertPhotoMenuItem = menu.findItem(R.id.track_detail_insert_photo);
playMenuItem = menu.findItem(R.id.track_detail_play); playMenuItem = menu.findItem(R.id.track_detail_play);
shareMenuItem = menu.findItem(R.id.track_detail_share); shareMenuItem = menu.findItem(R.id.track_detail_share);
@@ -338,6 +389,36 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity implements
.putExtra(MarkerEditActivity.EXTRA_TRACK_ID, trackId); .putExtra(MarkerEditActivity.EXTRA_TRACK_ID, trackId);
startActivity(intent); startActivity(intent);
return true; return true;
case R.id.track_detail_insert_photo:
try {
if (!FileUtils.isExternalStorageWriteable()) {
Toast.makeText(this, R.string.external_storage_not_writable, Toast.LENGTH_LONG).show();
return false;
}
File dir = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
FileUtils.SDCARD_TOP_DIR);
FileUtils.ensureDirectoryExists(dir);
String fileName = SimpleDateFormat.getDateTimeInstance().format(new Date());
File file = new File(dir, FileUtils.buildUniqueFileName(dir, fileName, "jpeg"));
if (file.exists()) {
Toast.makeText(this, R.string.marker_insert_photo_error, Toast.LENGTH_LONG).show();
return false;
}
file.createNewFile();
photoUri = Uri.fromFile(file);
intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE).putExtra(
MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(intent, CAMERA_REQUEST_CODE);
} catch (IOException e) {
Log.e(TAG, "Unable to insert photo marker", e);
return false;
}
return true;
case R.id.track_detail_play: case R.id.track_detail_play:
confirmPlay(new long[] {trackId}); confirmPlay(new long[] {trackId});
return true; return true;
@@ -513,6 +594,9 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity implements
if (insertMarkerMenuItem != null) { if (insertMarkerMenuItem != null) {
insertMarkerMenuItem.setVisible(isRecording && !isPaused); insertMarkerMenuItem.setVisible(isRecording && !isPaused);
} }
if (insertPhotoMenuItem != null) {
insertPhotoMenuItem.setVisible(hasCamera && isRecording && !isPaused);
}
if (playMenuItem != null) { if (playMenuItem != null) {
playMenuItem.setVisible(!isRecording); playMenuItem.setVisible(!isRecording);
} }
@@ -361,28 +361,28 @@ public class TrackListActivity extends AbstractSendToGoogleActivity
int idIndex = cursor.getColumnIndex(TracksColumns._ID); int idIndex = cursor.getColumnIndex(TracksColumns._ID);
int iconIndex = cursor.getColumnIndex(TracksColumns.ICON); int iconIndex = cursor.getColumnIndex(TracksColumns.ICON);
int nameIndex = cursor.getColumnIndex(TracksColumns.NAME); int nameIndex = cursor.getColumnIndex(TracksColumns.NAME);
int categoryIndex = cursor.getColumnIndex(TracksColumns.CATEGORY); int sharedOwnerIndex = cursor.getColumnIndex(TracksColumns.SHAREDOWNER);
int totalTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.TOTALTIME); int totalTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.TOTALTIME);
int totalDistanceIndex = cursor.getColumnIndexOrThrow(TracksColumns.TOTALDISTANCE); int totalDistanceIndex = cursor.getColumnIndexOrThrow(TracksColumns.TOTALDISTANCE);
int startTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.STARTTIME); int startTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.STARTTIME);
int categoryIndex = cursor.getColumnIndex(TracksColumns.CATEGORY);
int descriptionIndex = cursor.getColumnIndex(TracksColumns.DESCRIPTION); int descriptionIndex = cursor.getColumnIndex(TracksColumns.DESCRIPTION);
int sharedOwnerIndex = cursor.getColumnIndex(TracksColumns.SHAREDOWNER);
boolean isRecording = cursor.getLong(idIndex) == recordingTrackId; boolean isRecording = cursor.getLong(idIndex) == recordingTrackId;
String icon = cursor.getString(iconIndex); String icon = cursor.getString(iconIndex);
int iconId = TrackIconUtils.getIconDrawable(icon); int iconId = TrackIconUtils.getIconDrawable(icon);
String name = cursor.getString(nameIndex); String name = cursor.getString(nameIndex);
String category = icon != null && !icon.equals("") ? null : cursor.getString(categoryIndex); String sharedOwner = cursor.getString(sharedOwnerIndex);
String totalTime = StringUtils.formatElapsedTime(cursor.getLong(totalTimeIndex)); String totalTime = StringUtils.formatElapsedTime(cursor.getLong(totalTimeIndex));
String totalDistance = StringUtils.formatDistance( String totalDistance = StringUtils.formatDistance(
TrackListActivity.this, cursor.getDouble(totalDistanceIndex), metricUnits); TrackListActivity.this, cursor.getDouble(totalDistanceIndex), metricUnits);
long startTime = cursor.getLong(startTimeIndex); long startTime = cursor.getLong(startTimeIndex);
String category = icon != null && !icon.equals("") ? null : cursor.getString(categoryIndex);
String description = cursor.getString(descriptionIndex); String description = cursor.getString(descriptionIndex);
String sharedOwner = cursor.getString(sharedOwnerIndex);
ListItemUtils.setListItem(TrackListActivity.this, view, isRecording, recordingTrackPaused, ListItemUtils.setListItem(TrackListActivity.this, view, isRecording, recordingTrackPaused,
iconId, R.string.icon_track, name, category, totalTime, totalDistance, startTime, iconId, R.string.icon_track, name, sharedOwner, totalTime, totalDistance, null,
description, sharedOwner); startTime, category, description);
} }
}; };
listView.setAdapter(sectionResourceCursorAdapter); listView.setAdapter(sectionResourceCursorAdapter);
@@ -49,7 +49,7 @@ import java.util.ArrayList;
public class MyTracksProvider extends ContentProvider { public class MyTracksProvider extends ContentProvider {
private static final String TAG = MyTracksProvider.class.getSimpleName(); private static final String TAG = MyTracksProvider.class.getSimpleName();
private static final int DATABASE_VERSION = 21; private static final int DATABASE_VERSION = 22;
@VisibleForTesting @VisibleForTesting
static final String DATABASE_NAME = "mytracks.db"; static final String DATABASE_NAME = "mytracks.db";
@@ -124,6 +124,12 @@ public class MyTracksProvider extends ContentProvider {
db.execSQL("ALTER TABLE " + TracksColumns.TABLE_NAME + " ADD " + TracksColumns.SHAREDOWNER db.execSQL("ALTER TABLE " + TracksColumns.TABLE_NAME + " ADD " + TracksColumns.SHAREDOWNER
+ " STRING"); + " STRING");
} }
if (oldVersion <= 21) {
Log.w(TAG, "Upgrade DB: Adding photo url column.");
db.execSQL("ALTER TABLE " + WaypointsColumns.TABLE_NAME + " ADD " + WaypointsColumns.PHOTOURL
+ " STRING");
}
} }
} }
} }
@@ -0,0 +1,209 @@
/*
* 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.MarkerEditActivity;
import com.google.android.apps.mytracks.TrackDetailActivity;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.PhotoUtils;
import com.google.android.apps.mytracks.util.StatsUtils;
import com.google.android.maps.mytracks.R;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
/**
* A fragment to show marker details.
*
* @author Jimmy Shih
*/
public class MarkerDetailFragment extends Fragment {
private static final String TAG = MarkerDetailFragment.class.getSimpleName();
private static final String KEY_MARKER_ID = "markerId";
public static MarkerDetailFragment newInstance(long markerId) {
MarkerDetailFragment fragment = new MarkerDetailFragment();
Bundle bundle = new Bundle();
bundle.putLong(KEY_MARKER_ID, markerId);
fragment.setArguments(bundle);
return fragment;
}
private MyTracksProviderUtils myTracksProviderUtils;
private Waypoint waypoint;
private Bitmap bitmap;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
long markerId = getArguments().getLong(KEY_MARKER_ID);
if (markerId == -1L) {
Log.d(TAG, "invalid marker id");
getFragmentManager().popBackStack();
return;
}
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(getActivity());
}
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setHasOptionsMenu(true);
return inflater.inflate(R.layout.marker_detail_fragment, container, false);
};
@Override
public void onResume() {
super.onResume();
// Need to update the waypoint in case returning after an edit
updateWaypoint(true);
update();
}
public void onPause() {
super.onPause();
if (bitmap != null) {
bitmap.recycle();
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.marker_detail, menu);
updateWaypoint(false);
Track track = myTracksProviderUtils.getTrack(waypoint.getTrackId());
boolean isSharedWithMe = track != null ? track.isSharedWithMe() : true;
menu.findItem(R.id.marker_detail_edit).setVisible(!isSharedWithMe);
menu.findItem(R.id.marker_detail_delete).setVisible(!isSharedWithMe);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
long markerId = getArguments().getLong(KEY_MARKER_ID);
FragmentActivity fragmentActivity = getActivity();
Intent intent;
switch (item.getItemId()) {
case R.id.marker_detail_show_on_map:
intent = IntentUtils.newIntent(fragmentActivity, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.EXTRA_MARKER_ID, markerId);
startActivity(intent);
return true;
case R.id.marker_detail_edit:
intent = IntentUtils.newIntent(fragmentActivity, MarkerEditActivity.class)
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, markerId);
startActivity(intent);
return true;
case R.id.marker_detail_delete:
DeleteMarkerDialogFragment.newInstance(new long[] { markerId })
.show(getChildFragmentManager(), DeleteMarkerDialogFragment.DELETE_MARKER_DIALOG_TAG);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/**
* Updates the waypoint.
*
* @param refresh true to always update
*/
private void updateWaypoint(boolean refresh) {
if (refresh || waypoint == null) {
waypoint = myTracksProviderUtils.getWaypoint(getArguments().getLong(KEY_MARKER_ID));
if (waypoint == null) {
Log.d(TAG, "waypoint is null");
getFragmentManager().popBackStack();
}
}
}
/**
* Updates the UI.
*/
private void update() {
View waypointSection = getView().findViewById(R.id.marker_detail_waypoint_section);
View statisticsSection = getView().findViewById(R.id.marker_detail_statistics_section);
if (waypoint.getType() == WaypointType.WAYPOINT) {
waypointSection.setVisibility(View.VISIBLE);
statisticsSection.setVisibility(View.GONE);
ImageView imageView = (ImageView) getView().findViewById(R.id.marker_detail_waypoint_photo);
String photoUrl = waypoint.getPhotoUrl();
if (photoUrl == null || photoUrl.equals("")) {
imageView.setVisibility(View.GONE);
} else {
imageView.setVisibility(View.VISIBLE);
Display defaultDisplay = getActivity().getWindowManager().getDefaultDisplay();
@SuppressWarnings("deprecation")
int displayWidth = defaultDisplay.getWidth();
@SuppressWarnings("deprecation")
int displayHeight = defaultDisplay.getHeight();
bitmap = PhotoUtils.setImageVew(
imageView, Uri.parse(photoUrl), displayWidth, displayHeight, true);
}
TextView name = (TextView) getView().findViewById(R.id.marker_detail_waypoint_name);
name.setText(getString(R.string.generic_name_line, waypoint.getName()));
TextView markerType = (TextView) getView()
.findViewById(R.id.marker_detail_waypoint_marker_type);
markerType.setText(
getString(R.string.marker_detail_waypoint_marker_type, waypoint.getCategory()));
TextView description = (TextView) getView()
.findViewById(R.id.marker_detail_waypoint_description);
description.setText(getString(R.string.generic_description_line, waypoint.getDescription()));
} else {
waypointSection.setVisibility(View.GONE);
statisticsSection.setVisibility(View.VISIBLE);
TextView name = (TextView) getView().findViewById(R.id.marker_detail_statistics_name);
name.setText(getString(R.string.generic_name_line, waypoint.getName()));
StatsUtils.setTripStatisticsValues(getActivity(), waypoint.getTripStatistics());
StatsUtils.setLocationValues(getActivity(), waypoint.getLocation(), false);
}
}
}
@@ -282,7 +282,7 @@ abstract class AbstractImporter extends DefaultHandler {
// Insert waypoint // Insert waypoint
Waypoint newWaypoint = new Waypoint(waypoint.getName(), waypointDescription, Waypoint newWaypoint = new Waypoint(waypoint.getName(), waypointDescription,
waypoint.getCategory(), icon, track.getId(), waypoint.getType(), length, duration, waypoint.getCategory(), icon, track.getId(), waypoint.getType(), length, duration,
-1L, -1L, trackPoint, tripStatistics); -1L, -1L, trackPoint, tripStatistics, "");
myTracksProviderUtils.insertWaypoint(newWaypoint); myTracksProviderUtils.insertWaypoint(newWaypoint);
} }
waypoint = null; waypoint = null;
@@ -584,7 +584,7 @@ abstract class AbstractImporter extends DefaultHandler {
waypointLocation.setLongitude(180); waypointLocation.setLongitude(180);
Waypoint waypoint = new Waypoint(waypointName, waypointDescription, waypointCategory, icon, Waypoint waypoint = new Waypoint(waypointName, waypointDescription, waypointCategory, icon,
track.getId(), WaypointType.STATISTICS, length, duration, -1L, -1L, waypointLocation, track.getId(), WaypointType.STATISTICS, length, duration, -1L, -1L, waypointLocation,
tripStatistics); tripStatistics, "");
myTracksProviderUtils.insertWaypoint(waypoint); myTracksProviderUtils.insertWaypoint(waypoint);
} }
@@ -499,9 +499,13 @@ public class TrackRecordingService extends Service {
duration = 0L; duration = 0L;
} }
String photoUrl = waypointCreationRequest.getPhotoUrl() != null ? waypointCreationRequest
.getPhotoUrl()
: "";
// Insert waypoint // Insert waypoint
Waypoint waypoint = new Waypoint(name, description, category, icon, recordingTrackId, Waypoint waypoint = new Waypoint(name, description, category, icon, recordingTrackId,
waypointType, length, duration, -1L, -1L, location, tripStatistics); waypointType, length, duration, -1L, -1L, location, tripStatistics, photoUrl);
Uri uri = myTracksProviderUtils.insertWaypoint(waypoint); Uri uri = myTracksProviderUtils.insertWaypoint(waypoint);
return Long.parseLong(uri.getLastPathSegment()); return Long.parseLong(uri.getLastPathSegment());
} }
@@ -37,8 +37,7 @@ public class FileUtils {
* Name of the top-level directory inside the SD card where our files will be * Name of the top-level directory inside the SD card where our files will be
* read from/written to. * read from/written to.
*/ */
@VisibleForTesting public static final String SDCARD_TOP_DIR = "MyTracks";
static final String SDCARD_TOP_DIR = "MyTracks";
/** /**
* The maximum FAT32 path length. See the FAT32 spec at * The maximum FAT32 path length. See the FAT32 spec at
@@ -18,8 +18,11 @@ package com.google.android.apps.mytracks.util;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.net.Uri;
import android.text.format.DateUtils; import android.text.format.DateUtils;
import android.view.Display;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
@@ -38,23 +41,25 @@ public class ListItemUtils {
/** /**
* Sets a list item. * Sets a list item.
* *
* @param context the context * @param activity the activity
* @param view the list item view * @param view the list item view
* @param isRecording true if recording * @param isRecording true if recording
* @param isPaused true if paused * @param isPaused true if paused
* @param name the name value
* @param iconId the icon id * @param iconId the icon id
* @param iconContentDescriptionId the icon content description id * @param iconContentDescriptionId the icon content description id
* @param category the category value * @param name the name value
* @param sharedOwner if shared with me track, the owner, else null
* @param totalTime the total time value * @param totalTime the total time value
* @param totalDistance the total distance value * @param totalDistance the total distance value
* @param photoUrl the photo url
* @param startTime the start time value * @param startTime the start time value
* @param category the category value
* @param description the description value * @param description the description value
* @param sharedOwner if shared with me track, the owner, else null
*/ */
public static void setListItem(Context context, View view, boolean isRecording, boolean isPaused, public static void setListItem(Activity activity, View view, boolean isRecording,
int iconId, int iconContentDescriptionId, String name, String category, String totalTime, boolean isPaused, int iconId, int iconContentDescriptionId, String name, String sharedOwner,
String totalDistance, long startTime, String description, String sharedOwner) { String totalTime, String totalDistance, String photoUrl, long startTime, String category,
String description) {
if (isRecording) { if (isRecording) {
iconId = isPaused ? R.drawable.ic_track_paused : R.drawable.ic_track_recording; iconId = isPaused ? R.drawable.ic_track_paused : R.drawable.ic_track_recording;
@@ -64,29 +69,45 @@ public class ListItemUtils {
ImageView iconImageView = (ImageView) view.findViewById(R.id.list_item_icon); ImageView iconImageView = (ImageView) view.findViewById(R.id.list_item_icon);
iconImageView.setImageResource(iconId); iconImageView.setImageResource(iconId);
iconImageView.setContentDescription(context.getString(iconContentDescriptionId)); iconImageView.setContentDescription(activity.getString(iconContentDescriptionId));
// Set name
TextView nameTextView = (TextView) view.findViewById(R.id.list_item_name); TextView nameTextView = (TextView) view.findViewById(R.id.list_item_name);
nameTextView.setText(name); nameTextView.setText(name);
// Set sharedOwner/totalTime/totalDistance
TextView timeDistanceTextView = (TextView) view.findViewById(R.id.list_item_time_distance); TextView timeDistanceTextView = (TextView) view.findViewById(R.id.list_item_time_distance);
if (isRecording) { if (isRecording) {
timeDistanceTextView.setTextColor(context.getResources() timeDistanceTextView.setTextColor(activity.getResources()
.getColor(isPaused ? android.R.color.white : R.color.recording_text)); .getColor(isPaused ? android.R.color.white : R.color.recording_text));
} else { } else {
// Need to match the style set in list_item.xml // Need to match the style set in list_item.xml
timeDistanceTextView.setTextAppearance(context, R.style.TextSmall); timeDistanceTextView.setTextAppearance(activity, R.style.TextSmall);
} }
setTextView(timeDistanceTextView, setTextView(timeDistanceTextView,
getTimeDistance(context, isRecording, isPaused, sharedOwner, totalTime, totalDistance)); getTimeDistance(activity, isRecording, isPaused, sharedOwner, totalTime, totalDistance));
String[] startTimeDisplay = getStartTime(isRecording, context, startTime); // Set photoUrl
ImageView photo = (ImageView) view.findViewById(R.id.list_item_photo);
if (photoUrl == null || photoUrl.equals("")) {
photo.setVisibility(View.GONE);
} else {
photo.setVisibility(View.VISIBLE);
Display defaultDisplay = activity.getWindowManager().getDefaultDisplay();
// Set the initial width to 35% of the display width
int width = (int) (defaultDisplay.getWidth() * .35);
PhotoUtils.setImageVew(photo, Uri.parse(photoUrl), width, 0, false);
}
// Set date/time
String[] startTimeDisplay = getStartTime(isRecording, activity, startTime);
TextView dateTextView = (TextView) view.findViewById(R.id.list_item_date); TextView dateTextView = (TextView) view.findViewById(R.id.list_item_date);
setTextView(dateTextView, startTimeDisplay[0]); setTextView(dateTextView, startTimeDisplay[0]);
TextView timeTextView = (TextView) view.findViewById(R.id.list_item_time); TextView timeTextView = (TextView) view.findViewById(R.id.list_item_time);
setTextView(timeTextView, startTimeDisplay[1]); setTextView(timeTextView, startTimeDisplay[1]);
// Set category/description
TextView descriptionTextView = (TextView) view.findViewById(R.id.list_item_description); TextView descriptionTextView = (TextView) view.findViewById(R.id.list_item_description);
setTextView(descriptionTextView, getDescription(isRecording, category, description)); setTextView(descriptionTextView, getDescription(isRecording, category, description));
} }
@@ -0,0 +1,160 @@
/*
* 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.util;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.util.Log;
import android.widget.ImageView;
import java.io.IOException;
/**
* Utilities for photos.
*
* @author Jimmy Shih
*/
public class PhotoUtils {
private static final String TAG = PhotoUtils.class.getSimpleName();
private PhotoUtils() {}
/**
* Sets an image view.
*
* @param imageView the image view
* @param uri the image uri
* @param displayWidth the display width
* @param displayHeight the display height
* @param fitWithIn true to fit within the display area. False to crop and fill
* the display area.
*/
public static Bitmap setImageVew(
ImageView imageView, Uri uri, int displayWidth, int displayHeight, boolean fitWithIn) {
// Get the image dimensions
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(uri.getPath(), options);
// Set targetWidth and targetHeight
int targetWidth = displayWidth;
int targetHeight = displayHeight;
if (targetHeight == 0) {
targetHeight = (int) (targetWidth * ((float) options.outHeight / (float) options.outWidth));
imageView.getLayoutParams().height = targetHeight;
}
// Set imageWidth and imageHeight based on image rotation
int rotation = getRotation(uri);
int imageWidth;
int imageHeight;
if (rotation == 0 || rotation == 180) {
imageWidth = options.outWidth;
imageHeight = options.outHeight;
} else {
imageWidth = options.outHeight;
imageHeight = options.outWidth;
}
// Get a scaled down version of the image
options.inJustDecodeBounds = false;
options.inSampleSize = getInSampleSize(
imageWidth, imageHeight, targetWidth, targetHeight, fitWithIn);
options.inPurgeable = true;
Bitmap scaledBitmap = BitmapFactory.decodeFile(uri.getPath(), options);
// Get the final bitmap after rotating the scaled down image
Bitmap bitmap;
if (rotation == 0) {
bitmap = scaledBitmap;
} else {
Matrix matrix = new Matrix();
matrix.postRotate(rotation);
bitmap = Bitmap.createBitmap(
scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
scaledBitmap.recycle();
}
imageView.setImageBitmap(bitmap);
return bitmap;
}
/**
* Gets the image rotation
*
* @param uri the image uri
*/
private static int getRotation(Uri uri) {
try {
ExifInterface exifInterface = new ExifInterface(uri.getPath());
switch (exifInterface.getAttributeInt(
ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)) {
case ExifInterface.ORIENTATION_ROTATE_90:
return 90;
case ExifInterface.ORIENTATION_ROTATE_180:
return 180;
case ExifInterface.ORIENTATION_ROTATE_270:
return 270;
default:
return 0;
}
} catch (IOException e) {
Log.e(TAG, "Unable to get photo orientation", e);
return 0;
}
}
/**
* Gets the in sample size.
*
* @param imageWidth the image width
* @param imageHeight the image height
* @param targetWidth the target width
* @param targetHeight the target height
* @param fitWithin true to fit within the target area. False to crop and fill
* all target area.
*/
private static int getInSampleSize(
int imageWidth, int imageHeight, int targetWidth, int targetHeight, boolean fitWithin) {
float widthRatio = 1;
if (imageWidth > targetWidth) {
widthRatio = (float) imageWidth / (float) targetWidth;
}
float heightRatio = 1;
if (imageHeight > targetHeight) {
heightRatio = (float) imageHeight / (float) targetHeight;
}
/*
* To fit within the target area, return the larger sample ratio so the
* image will not be larger than the target dimensions. To crop and fill the
* target area, return the smaller sample ratio so the image will be greater
* than the target dimensions. Use Math.floor to not under sample.
*/
return (int) Math.floor(
fitWithin ? Math.max(widthRatio, heightRatio) : Math.min(widthRatio, heightRatio));
}
}
@@ -170,7 +170,7 @@ public class TrackRecordingServiceConnectionUtils {
/** /**
* Adds a marker. * Adds a marker.
*/ */
public static void addMarker(Context context, public static long addMarker(Context context,
TrackRecordingServiceConnection trackRecordingServiceConnection, TrackRecordingServiceConnection trackRecordingServiceConnection,
WaypointCreationRequest waypointCreationRequest) { WaypointCreationRequest waypointCreationRequest) {
ITrackRecordingService trackRecordingService = trackRecordingServiceConnection ITrackRecordingService trackRecordingService = trackRecordingServiceConnection
@@ -179,9 +179,10 @@ public class TrackRecordingServiceConnectionUtils {
Log.d(TAG, "Unable to add marker, no track recording service"); Log.d(TAG, "Unable to add marker, no track recording service");
} else { } else {
try { try {
if (trackRecordingService.insertWaypoint(waypointCreationRequest) != -1L) { long markerId = trackRecordingService.insertWaypoint(waypointCreationRequest);
if (markerId != -1L) {
Toast.makeText(context, R.string.marker_add_success, Toast.LENGTH_SHORT).show(); Toast.makeText(context, R.string.marker_add_success, Toast.LENGTH_SHORT).show();
return; return markerId;
} }
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Unable to add marker", e); Log.e(TAG, "Unable to add marker", e);
@@ -190,5 +191,6 @@ public class TrackRecordingServiceConnectionUtils {
} }
} }
Toast.makeText(context, R.string.marker_add_error, Toast.LENGTH_LONG).show(); Toast.makeText(context, R.string.marker_add_error, Toast.LENGTH_LONG).show();
return -1L;
} }
} }
@@ -363,7 +363,8 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
int elevationGainIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.ELEVATIONGAIN); int elevationGainIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.ELEVATIONGAIN);
int minGradeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.MINGRADE); int minGradeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.MINGRADE);
int maxGradeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.MAXGRADE); int maxGradeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.MAXGRADE);
int photoUrlIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.PHOTOURL);
Waypoint waypoint = new Waypoint(); Waypoint waypoint = new Waypoint();
if (!cursor.isNull(idIndex)) { if (!cursor.isNull(idIndex)) {
@@ -468,6 +469,10 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
if (hasTripStatistics) { if (hasTripStatistics) {
waypoint.setTripStatistics(tripStatistics); waypoint.setTripStatistics(tripStatistics);
} }
if (!cursor.isNull(photoUrlIndex)) {
waypoint.setPhotoUrl(cursor.getString(photoUrlIndex));
}
return waypoint; return waypoint;
} }
@@ -672,6 +677,8 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
values.put(WaypointsColumns.MINGRADE, tripStatistics.getMinGrade()); values.put(WaypointsColumns.MINGRADE, tripStatistics.getMinGrade());
values.put(WaypointsColumns.MAXGRADE, tripStatistics.getMaxGrade()); values.put(WaypointsColumns.MAXGRADE, tripStatistics.getMaxGrade());
} }
values.put(WaypointsColumns.PHOTOURL, waypoint.getPhotoUrl());
return values; return values;
} }
@@ -47,12 +47,13 @@ public final class Waypoint implements Parcelable {
private long stopId = -1L; private long stopId = -1L;
private Location location = null; private Location location = null;
private TripStatistics tripStatistics = null; private TripStatistics tripStatistics = null;
private String photoUrl = "";
public Waypoint() {} public Waypoint() {}
public Waypoint(String name, String description, String category, String icon, long trackId, public Waypoint(String name, String description, String category, String icon, long trackId,
WaypointType type, double length, long duration, long startId, long stopId, Location location, WaypointType type, double length, long duration, long startId, long stopId, Location location,
TripStatistics tripStatistics) { TripStatistics tripStatistics, String photoUrl) {
this.name = name; this.name = name;
this.description = description; this.description = description;
this.category = category; this.category = category;
@@ -65,6 +66,7 @@ public final class Waypoint implements Parcelable {
this.stopId = stopId; this.stopId = stopId;
this.location = location; this.location = location;
this.tripStatistics = tripStatistics; this.tripStatistics = tripStatistics;
this.photoUrl = photoUrl;
} }
private Waypoint(Parcel source) { private Waypoint(Parcel source) {
@@ -89,6 +91,7 @@ public final class Waypoint implements Parcelable {
if (hasStats > 0) { if (hasStats > 0) {
tripStatistics = source.readParcelable(classLoader); tripStatistics = source.readParcelable(classLoader);
} }
photoUrl = source.readString();
} }
@Override @Override
@@ -117,6 +120,7 @@ public final class Waypoint implements Parcelable {
if (tripStatistics != null) { if (tripStatistics != null) {
dest.writeParcelable(tripStatistics, 0); dest.writeParcelable(tripStatistics, 0);
} }
dest.writeString(photoUrl);
} }
public static final Parcelable.Creator<Waypoint> CREATOR = new Parcelable.Creator<Waypoint>() { public static final Parcelable.Creator<Waypoint> CREATOR = new Parcelable.Creator<Waypoint>() {
@@ -233,5 +237,13 @@ public final class Waypoint implements Parcelable {
public void setTripStatistics(TripStatistics tripStatistics) { public void setTripStatistics(TripStatistics tripStatistics) {
this.tripStatistics = tripStatistics; this.tripStatistics = tripStatistics;
}
public String getPhotoUrl() {
return photoUrl;
}
public void setPhotoUrl(String photoUrl) {
this.photoUrl = photoUrl;
} }
} }
@@ -34,6 +34,7 @@ public class WaypointCreationRequest implements Parcelable {
private String category; private String category;
private String description; private String description;
private String iconUrl; private String iconUrl;
private String photoUrl;
public final static WaypointCreationRequest DEFAULT_WAYPOINT = new WaypointCreationRequest( public final static WaypointCreationRequest DEFAULT_WAYPOINT = new WaypointCreationRequest(
WaypointType.WAYPOINT, false); WaypointType.WAYPOINT, false);
@@ -43,17 +44,18 @@ public class WaypointCreationRequest implements Parcelable {
WaypointType.STATISTICS, true); WaypointType.STATISTICS, true);
private WaypointCreationRequest(WaypointType type, boolean isTrackStatistics) { private WaypointCreationRequest(WaypointType type, boolean isTrackStatistics) {
this(type, isTrackStatistics, null, null, null, null); this(type, isTrackStatistics, null, null, null, null, null);
} }
public WaypointCreationRequest(WaypointType type, boolean isTrackStatistics, String name, public WaypointCreationRequest(WaypointType type, boolean isTrackStatistics, String name,
String category, String description, String iconUrl) { String category, String description, String iconUrl, String photoUrl) {
this.type = type; this.type = type;
this.isTrackStatistics = isTrackStatistics; this.isTrackStatistics = isTrackStatistics;
this.name = name; this.name = name;
this.category = category; this.category = category;
this.description = description; this.description = description;
this.iconUrl = iconUrl; this.iconUrl = iconUrl;
this.photoUrl = photoUrl;
} }
public static class Creator implements Parcelable.Creator<WaypointCreationRequest> { public static class Creator implements Parcelable.Creator<WaypointCreationRequest> {
@@ -66,6 +68,7 @@ public class WaypointCreationRequest implements Parcelable {
source.readString(), source.readString(),
source.readString(), source.readString(),
source.readString(), source.readString(),
source.readString(),
source.readString()); source.readString());
return request; return request;
} }
@@ -90,6 +93,7 @@ public class WaypointCreationRequest implements Parcelable {
parcel.writeString(category); parcel.writeString(category);
parcel.writeString(description); parcel.writeString(description);
parcel.writeString(iconUrl); parcel.writeString(iconUrl);
parcel.writeString(photoUrl);
} }
public WaypointType getType() { public WaypointType getType() {
@@ -115,4 +119,8 @@ public class WaypointCreationRequest implements Parcelable {
public String getIconUrl() { public String getIconUrl() {
return iconUrl; return iconUrl;
} }
public String getPhotoUrl() {
return photoUrl;
}
} }
@@ -70,6 +70,8 @@ public interface WaypointsColumns extends BaseColumns {
public static final String ELEVATIONGAIN = "elevationgain"; // elevation gain public static final String ELEVATIONGAIN = "elevationgain"; // elevation gain
public static final String MINGRADE = "mingrade"; // min grade public static final String MINGRADE = "mingrade"; // min grade
public static final String MAXGRADE = "maxgrade"; // max grade public static final String MAXGRADE = "maxgrade"; // max grade
public static final String PHOTOURL = "photoUrl"; // url for the photo
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " ("
+ _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
@@ -101,7 +103,8 @@ public interface WaypointsColumns extends BaseColumns {
+ MAXELEVATION + " FLOAT, " + MAXELEVATION + " FLOAT, "
+ ELEVATIONGAIN + " FLOAT, " + ELEVATIONGAIN + " FLOAT, "
+ MINGRADE + " FLOAT, " + MINGRADE + " FLOAT, "
+ MAXGRADE + " FLOAT" + MAXGRADE + " FLOAT, "
+ PHOTOURL + " STRING"
+ ");"; + ");";
public static final String[] COLUMNS = { public static final String[] COLUMNS = {
@@ -134,7 +137,8 @@ public interface WaypointsColumns extends BaseColumns {
MAXELEVATION, MAXELEVATION,
ELEVATIONGAIN, ELEVATIONGAIN,
MINGRADE, MINGRADE,
MAXGRADE MAXGRADE,
PHOTOURL
}; };
public static final byte[] COLUMN_TYPES = { public static final byte[] COLUMN_TYPES = {
@@ -167,6 +171,7 @@ public interface WaypointsColumns extends BaseColumns {
FLOAT_TYPE_ID, // max elevation FLOAT_TYPE_ID, // max elevation
FLOAT_TYPE_ID, // elevation gain FLOAT_TYPE_ID, // elevation gain
FLOAT_TYPE_ID, // min grade FLOAT_TYPE_ID, // min grade
FLOAT_TYPE_ID // max grade FLOAT_TYPE_ID, // max grade
STRING_TYPE_ID // photo url
}; };
} }
@@ -43,7 +43,7 @@ public class WaypointCreationRequestTest extends AndroidTestCase {
public void testAllAttributesParceling() { public void testAllAttributesParceling() {
WaypointCreationRequest original = new WaypointCreationRequest( WaypointCreationRequest original = new WaypointCreationRequest(
WaypointType.WAYPOINT, false, "name", "category", "description", "img.png"); WaypointType.WAYPOINT, false, "name", "category", "description", "img.png", null);
Parcel p = Parcel.obtain(); Parcel p = Parcel.obtain();
original.writeToParcel(p, 0); original.writeToParcel(p, 0);
p.setDataPosition(0); p.setDataPosition(0);