Move the track context menu to the main menu.

Use sharedPreferenceChangeListener to listen when
a new recording has started to update the view like the action items.
This commit is contained in:
Jimmy Shih
2012-03-29 18:02:28 -07:00
parent 246b13da4b
commit 9ff1af221b
22 changed files with 543 additions and 735 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

-19
View File
@@ -59,23 +59,4 @@ limitations under the License.
android:minHeight="80dp" android:minHeight="80dp"
android:layout_gravity="center"/> android:layout_gravity="center"/>
</LinearLayout> </LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_gravity="center"
android:paddingTop="10dp">
<LinearLayout
android:layout_width = "wrap_content"
android:layout_height= "wrap_content"
android:layout_weight="1"/>
<ImageButton
android:id="@+id/showOptions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:visibility="visible"
android:src="@android:drawable/ic_menu_more"/>
</LinearLayout>
</RelativeLayout> </RelativeLayout>
+51 -23
View File
@@ -15,43 +15,74 @@ See the License for the specific language governing permissions and
limitations under the License. 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
android:icon="@drawable/menu_record_track"
android:id="@+id/menu_record_track"
android:showAsAction="always"
android:title="@string/menu_record_track"/>
<item <item
android:icon="@drawable/menu_stop_recording" android:icon="@drawable/menu_stop_recording"
android:id="@+id/menu_stop_recording" android:id="@+id/menu_stop_recording"
android:showAsAction="always" android:showAsAction="always"
android:title="@string/menu_stop_recording"/> android:title="@string/menu_stop_recording"/>
<item
android:icon="@drawable/menu_insert_marker"
android:id="@+id/menu_insert_marker"
android:showAsAction="always"
android:title="@string/menu_insert_marker"/>
<item
android:icon="@drawable/menu_play"
android:id="@+id/menu_play"
android:showAsAction="always"
android:title="@string/menu_play"/>
<item
android:icon="@drawable/menu_share"
android:id="@+id/menu_share"
android:showAsAction="always"
android:title="@string/menu_share">
<menu>
<item
android:id="@+id/menu_share_map"
android:title="@string/menu_share_map"/>
<item
android:id="@+id/menu_share_fusion_table"
android:title="@string/menu_share_fusion_table"/>
<item android:id="@+id/menu_share_gpx"/>
<item android:id="@+id/menu_share_kml"/>
<item android:id="@+id/menu_share_csv"/>
<item android:id="@+id/menu_share_tcx"/>
</menu>
</item>
<item <item
android:icon="@drawable/ic_menu_waypoints" android:icon="@drawable/ic_menu_waypoints"
android:id="@+id/menu_markers" android:id="@+id/menu_markers"
android:showAsAction="ifRoom"
android:title="@string/menu_markers"/> android:title="@string/menu_markers"/>
<item <item
android:icon="@drawable/ic_menu_chartsettings" android:id="@+id/menu_send_google"
android:id="@+id/menu_chart_settings" android:title="@string/menu_send_google"/>
android:showAsAction="ifRoom" <item
android:title="@string/menu_chart_settings" android:id="@+id/menu_save"
android:visible="false"/> android:title="@string/menu_save">
<menu>
<item android:id="@+id/menu_save_gpx"/>
<item android:id="@+id/menu_save_kml"/>
<item android:id="@+id/menu_save_csv"/>
<item android:id="@+id/menu_save_tcx"/>
</menu>
</item>
<item
android:id="@+id/menu_edit"
android:title="@string/menu_edit"/>
<item
android:id="@+id/menu_delete"
android:title="@string/menu_delete"/>
<item <item
android:icon="@android:drawable/ic_menu_mylocation" android:icon="@android:drawable/ic_menu_mylocation"
android:id="@+id/menu_my_location" android:id="@+id/menu_my_location"
android:showAsAction="ifRoom" android:title="@string/menu_my_location"/>
android:title="@string/menu_my_location"
android:visible="false"/>
<item <item
android:icon="@android:drawable/ic_menu_mapmode" android:icon="@android:drawable/ic_menu_mapmode"
android:id="@+id/menu_satellite_mode" android:id="@+id/menu_satellite_mode"
android:showAsAction="ifRoom" android:title="@string/menu_satellite_mode"/>
android:title="@string/menu_satellite_mode"
android:visible="false"/>
<item <item
android:icon="@drawable/menu_search" android:icon="@drawable/ic_menu_chartsettings"
android:id="@+id/menu_search" android:id="@+id/menu_chart_settings"
android:title="@string/menu_search"/> android:title="@string/menu_chart_settings"/>
<item <item
android:icon="@drawable/ic_menu_sensorstatus" android:icon="@drawable/ic_menu_sensorstatus"
android:id="@+id/menu_sensor_state" android:id="@+id/menu_sensor_state"
@@ -60,9 +91,6 @@ limitations under the License.
android:icon="@drawable/menu_settings" android:icon="@drawable/menu_settings"
android:id="@+id/menu_settings" android:id="@+id/menu_settings"
android:title="@string/menu_settings"/> android:title="@string/menu_settings"/>
<item
android:id="@+id/menu_aggregated_statistics"
android:title="@string/menu_aggregated_statistics"/>
<item <item
android:icon="@drawable/menu_help" android:icon="@drawable/menu_help"
android:id="@+id/menu_help" android:id="@+id/menu_help"
+97 -146
View File
@@ -977,10 +977,25 @@ limitations under the License.
translation_description="In the menu, to delete all the tracks."> translation_description="In the menu, to delete all the tracks.">
Delete all Delete all
</string> </string>
<string name="menu_delete"
translation_description="In the menu, to delete a track or a marker.">
Delete
</string>
<string name="menu_edit"
translation_description="In the menu, to edit a track or a marker.">
Edit
</string>
<string name="menu_export_all" <string name="menu_export_all"
translation_description="In the menu, to export all the tracks to the SD card."> translation_description="In the menu, to export all the tracks to the SD card.">
Export all Export all
</string> </string>
<string name="menu_export_all_format"
translation_description="Under the 'Export all' menu option, the option to export all tracks as
a certain file format.
%1$s: file format. 'GPX', 'KML', 'CSV', or 'TCX'.">
Export as %1$s
</string>
<string name="menu_help" <string name="menu_help"
translation_description="In the menu, to go to the help page."> translation_description="In the menu, to go to the help page.">
Help Help
@@ -989,6 +1004,10 @@ limitations under the License.
translation_description="In the menu, to import all the tracks from the SD card."> translation_description="In the menu, to import all the tracks from the SD card.">
Import all Import all
</string> </string>
<string name="menu_insert_marker"
translation_description="In the menu, to insert a marker.">
Insert marker
</string>
<string name="menu_map_mode" <string name="menu_map_mode"
translation_description="In the menu, to switch the display to the map mode."> translation_description="In the menu, to switch the display to the map mode.">
Map mode Map mode
@@ -1001,6 +1020,10 @@ limitations under the License.
translation_description="In the menu, to display the user's current location."> translation_description="In the menu, to display the user's current location.">
My location My location
</string> </string>
<string name="menu_play"
translation_description="In the menu, to play a track.">
Play
</string>
<string name="menu_record_track" <string name="menu_record_track"
translation_description="In the menu, to start recording a track."> translation_description="In the menu, to start recording a track.">
Record track Record track
@@ -1009,10 +1032,25 @@ limitations under the License.
translation_description="In the menu, to switch the display to the satellite mode."> translation_description="In the menu, to switch the display to the satellite mode.">
Satellite mode Satellite mode
</string> </string>
<string name="menu_save"
translation_description="In the menu, to save a track to the SD card.">
Save to SD card...
</string>
<string name="menu_save_format"
translation_description="Under the 'Save to SD card...' menu option, the option to save a track
as a certain file format.
%1$s: file format. 'GPX', 'KML', 'CSV', or 'TCX'.">
As a %1$s file
</string>
<string name="menu_search" <string name="menu_search"
translation_description="In the menu, to start a textual search for tracks or waypoints."> translation_description="In the menu, to start a textual search for tracks or waypoints.">
Search Search
</string> </string>
<string name="menu_send_google"
translation_description="In the menu, to send a track to Google.">
Send to Google...
</string>
<string name="menu_sensor_state" <string name="menu_sensor_state"
translation_description="In the menu, to go to the sensor state page."> translation_description="In the menu, to go to the sensor state page.">
Sensor state Sensor state
@@ -1025,6 +1063,30 @@ limitations under the License.
translation_description="In the menu, to stop recording a track."> translation_description="In the menu, to stop recording a track.">
Stop recording Stop recording
</string> </string>
<string name="menu_share"
translation_description="In the menu, to share a track with friends through other
applications.">
Share with friends...
</string>
<string name="menu_share_file"
translation_description="Under the 'Share with friends...' menu option, the option to share a
track as a certain file format.
%1$s: file format. 'GPX', 'KML', 'CSV', or 'TCX'.">
A %1$s file
</string>
<string name="menu_share_fusion_table"
translation_description="Under the 'Share with friends...' menu option, the option to save a
track to Google Fusion Tables and share the Fusion Table url with friends. 'Fusion Table' in
this context means a Google Fusion Table.">
Fusion Table
</string>
<string name="menu_share_map"
translation_description="Under the 'Share with friends...' menu option, the option to save a
track to Google Maps and share the Map url with friends. 'Map' in this context means a Google
Map.">
Map
</string>
<!-- My Location --> <!-- My Location -->
<string name="my_location_approximate_location" <string name="my_location_approximate_location"
@@ -1196,6 +1258,13 @@ limitations under the License.
search results."> search results.">
No tracks or waypoints matched your search. No tracks or waypoints matched your search.
</string> </string>
<string name="search_track_location"
translation_description="In the 'Search Result' page, the text field indicating the track that a
waypoint belongs to.
%1$s: track name. E.g., 'Grand Canyon trail'">
In track \'%1$s\'.
</string>
<string name="search_voice_prompt" <string name="search_voice_prompt"
translation_description="Prompt shown when the user activates voice search, asking him to speak translation_description="Prompt shown when the user activates voice search, asking him to speak
what will be searched for."> what will be searched for.">
@@ -2233,7 +2302,22 @@ limitations under the License.
Total time Total time
</string> </string>
<!-- Track Edit --> <!-- Track -->
<string name="track_detail_delete_confirm_message"
translation_description="When deleting a track, the confirmation message informing the user that
the track and its markers will be permanently deleted from the phone.">
The track and its markers will be permanently deleted from the phone.
</string>
<string name="track_detail_install_earth_message"
translation_description="When playing a track, the message informing the user that he needs
Google Earth to play the track and asking him if he wants to install Google Earth from the
Android Market.">
You need Google Earth to play the track. Do you want to install from the Market?
</string>
<string name="track_icon_description"
translation_description="The accessibility description for the track icon.">
Track
</string>
<string name="track_edit_activity_type" <string name="track_edit_activity_type"
translation_description="In the page to edit a track, the title for the text field to edit the translation_description="In the page to edit a track, the title for the text field to edit the
activity type, including some examples of activity types."> activity type, including some examples of activity types.">
@@ -2258,165 +2342,32 @@ limitations under the License.
track name."> track name.">
Track name Track name
</string> </string>
<!-- Track -->
<string name="track_icon_description"
translation_description="The accessibility description for the track icon.">
Track
</string>
<string name="track_list_clear_map"
translation_description="In the context menu for a track, the menu option to clear the map of
any track.
Screenshot: track_list_context_menu.png">
Clear map
</string>
<string name="track_list_context_menu_title"
translation_description="In the context menu for a track, the title indicating that all the menu
options below are for this track.
Screenshot: track_list_context_menu.png">
This track
</string>
<string name="track_list_delete_all_confirm_message" <string name="track_list_delete_all_confirm_message"
translation_description="In the 'Tracks' page, when pressing the 'Delete all' button, the translation_description="When deleting all the tracks, the confirmation dialog message informing
confirmation dialog message informing the user that all tracks and markers will be permanently the user that all tracks and markers will be permanently deleted from the phone.">
deleted from the phone.
Screenshot: track_list_delete_all_confirm_message.png">
All tracks and markers will be permanently deleted from the phone. All tracks and markers will be permanently deleted from the phone.
</string> </string>
<string name="track_list_delete_track" <string name="track_list_record_error"
translation_description="In the context menu for a track, the menu option to delete the translation_description="When starting a new track recording, the error message informing the
track from the phone. user not able to record and asking the user to try again.">
Unable to start recording. No GPS location. Try again.
Screenshot: track_list_context_menu.png">
Delete from phone...
</string> </string>
<string name="track_list_delete_track_confirm_message" <string name="track_list_record_success"
translation_description="In the context menu for a track, when pressing the 'Delete from translation_description="When starting a new track recording, a status message indicating
phone...' option, the confirmation dialog message informing the user that the track and its success.">
markers will be permanently deleted from the phone. Now recording a new track.
Screenshot: track_list_delete_track_confirm_message.png">
The track and its markers will be permanently deleted from the phone.
</string>
<string name="track_list_edit_track"
translation_description="In the context menu for a track, the menu option to edit the track's
metadata (e.g., name, activity type, etc.).
Screenshot: track_list_context_menu.png">
Edit
</string>
<string name="track_list_export_file"
translation_description="In the 'Tracks' page, after pressing the 'Export all' button, the menu
option to export all the tracks as a certain file format
%1$s: file format. 'GPX', 'KML', 'CSV', or 'TCX'.
Screenshot: track_list_export_file.png">
Export as %1$s
</string>
<string name="track_list_play"
translation_description="In the context menu for a track, the menu option to play the track.">
Play
</string>
<string name="track_list_play_install_earth_message"
translation_description="After pressing the menu option to play a track, the message informing
the user that he needs Google Earth to play the track and asking him if he wants to install
Google Earth from the Android Market.">
You need Google Earth to play the track. Do you want to install from the Market?
</string>
<string name="track_list_save_file"
translation_description="In the context menu for a track, under the 'Save to SD card...'
option, the menu option to save the track as a certain file format.
%1$s: file format. 'GPX', 'KML', 'CSV', or 'TCX'.
Screenshot: track_list_save_file.png">
As a %1$s file
</string>
<string name="track_list_save_sd"
translation_description="In the context menu for a track, the menu option to save the track to
the SD card.
Screenshot: track_list_context_menu.png">
Save to SD card...
</string>
<string name="track_list_send_google"
translation_description="In the context menu for a track, the menu option to send the track to
Google.
Screenshot: track_list_context_menu.png">
Send to Google...
</string>
<string name="track_list_share_file"
translation_description="In the context menu for a track, under the 'Share with friends...'
option, the menu option to share the track as a certain file format.
%1$s: file format. 'GPX', 'KML', 'CSV', or 'TCX'.
Screenshot: track_list_share_options.png">
A %1$s file
</string>
<string name="track_list_share_fusion_table"
translation_description="In the context menu for a track, under the 'Share with friends...'
option, the menu option to save a track to Google Fusion Tables and share the Fusion Table
with friends. 'Fusion Table' in this context means a Google Fusion Table.">
Fusion Table
</string>
<string name="track_list_share_map"
translation_description="In the context menu for a track, under the 'Share with friends...'
option, the menu option to save a track to Google Maps and share the Map with friends. 'Map'
in this context means a Google Map.">
Map
</string>
<string name="track_list_share_track"
translation_description="In the context menu for a track, the menu option to share the track
with friends through other applications.
Screenshot: track_list_context_menu.png">
Share with friends...
</string>
<string name="track_list_show_on_map"
translation_description="In the context menu for a track, the menu option to show the track on
the map.
Screenshot: track_list_show_on_map.png">
Show on map
</string>
<string name="track_list_track_name"
translation_description="In the 'Search Result' page, the text field indicating the track that a
waypoint belongs to.
%1$s: track name. E.g., 'Grand Canyon trail'">
In track \'%1$s\'.
</string> </string>
<string name="track_name_format" <string name="track_name_format"
translation_description="When creating a new track, the string format to name the track. translation_description="When creating a new track, the string format to name the track.
%1$d: track number. E.g., '1'. %1$d: track number. E.g., '1'.">
Screenshot: track_name_format.png">
Track %1$d Track %1$d
</string> </string>
<string name="track_record_error"
translation_description="When starting a recording, message when not able to start due to no GPS
location and asking the user to try again.
Screenshot: track_record_error.png">
Unable to start recording. No GPS location. Try again.
</string>
<string name="track_record_notification" <string name="track_record_notification"
translation_description="When recording a track, the message on the My Tracks notification translation_description="When recording a track, the message on the My Tracks notification
informing the user that My Tracks is actively recording his track. informing the user that My Tracks is actively recording his track.">
Screenshot: track_record_notification.png">
Recording your track... Recording your track...
</string> </string>
<string name="track_record_success"
translation_description="When starting a new track recording, a status message indicating
success.
Screenshot: track_record_success.png">
Now recording a new track.
</string>
<!-- Unit --> <!-- Unit -->
<string name="unit_feet" <string name="unit_feet"
@@ -41,24 +41,10 @@ public abstract class Constants {
/* /*
* Context menu ids. Sorted alphabetically. * Context menu ids. Sorted alphabetically.
*/ */
public static final int MENU_CLEAR_MAP = 100; public static final int MENU_DELETE = 100;
public static final int MENU_DELETE = 101; public static final int MENU_EDIT = 101;
public static final int MENU_EDIT = 102; public static final int MENU_SHOW = 102;
public static final int MENU_PLAY = 103;
public static final int MENU_SAVE_CSV_FILE = 104;
public static final int MENU_SAVE_GPX_FILE = 105;
public static final int MENU_SAVE_KML_FILE = 106;
public static final int MENU_SAVE_TCX_FILE = 107;
public static final int MENU_SEND_TO_GOOGLE = 108;
public static final int MENU_SHARE = 109;
public static final int MENU_SHARE_CSV_FILE = 110;
public static final int MENU_SHARE_FUSION_TABLE = 111;
public static final int MENU_SHARE_GPX_FILE = 112;
public static final int MENU_SHARE_KML_FILE = 113;
public static final int MENU_SHARE_MAP = 114;
public static final int MENU_SHARE_TCX_FILE = 115;
public static final int MENU_SHOW = 116;
public static final int MENU_WRITE_TO_SD_CARD = 117;
/* /*
* Main screen tab tags: * Main screen tab tags:
*/ */
@@ -23,42 +23,23 @@ import com.google.android.apps.mytracks.content.TrackDataHub;
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType; import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
import com.google.android.apps.mytracks.content.TrackDataListener; import com.google.android.apps.mytracks.content.TrackDataListener;
import com.google.android.apps.mytracks.content.Waypoint; import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.io.file.SaveActivity;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.io.sendtogoogle.UploadServiceChooserActivity;
import com.google.android.apps.mytracks.stats.TripStatistics; import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.ApiAdapterFactory; import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.apps.mytracks.util.GeoRect; import com.google.android.apps.mytracks.util.GeoRect;
import com.google.android.apps.mytracks.util.LocationUtils; import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.PlayTrackUtils;
import com.google.android.maps.GeoPoint; import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapController; import com.google.android.maps.MapController;
import com.google.android.maps.MapView; import com.google.android.maps.MapView;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.location.Location; import android.location.Location;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcelable;
import android.provider.Settings; import android.provider.Settings;
import android.speech.tts.TextToSpeech; import android.speech.tts.TextToSpeech;
import android.util.Log; import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.SubMenu;
import android.view.View; import android.view.View;
import android.view.View.OnCreateContextMenuListener;
import android.widget.ImageButton;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
@@ -76,9 +57,6 @@ public class MapActivity extends com.google.android.maps.MapActivity
implements View.OnTouchListener, View.OnClickListener, implements View.OnTouchListener, View.OnClickListener,
TrackDataListener { TrackDataListener {
private static final int DIALOG_INSTALL_EARTH_ID = 0;
private static final int DIALOG_DELETE_CURRENT_ID = 1;
// Saved instance state keys: // Saved instance state keys:
// --------------------------- // ---------------------------
@@ -133,7 +111,6 @@ public class MapActivity extends com.google.android.maps.MapActivity
private LinearLayout messagePane; private LinearLayout messagePane;
private TextView messageText; private TextView messageText;
private LinearLayout busyPane; private LinearLayout busyPane;
private ImageButton optionsBtn;
/** /**
* We are not displaying driving directions. Just an arbitrary track that is * We are not displaying driving directions. Just an arbitrary track that is
@@ -185,10 +162,6 @@ public class MapActivity extends com.google.android.maps.MapActivity
messagePane = (LinearLayout) findViewById(R.id.messagepane); messagePane = (LinearLayout) findViewById(R.id.messagepane);
messageText = (TextView) findViewById(R.id.messagetext); messageText = (TextView) findViewById(R.id.messagetext);
busyPane = (LinearLayout) findViewById(R.id.busypane); busyPane = (LinearLayout) findViewById(R.id.busypane);
optionsBtn = (ImageButton) findViewById(R.id.showOptions);
optionsBtn.setOnCreateContextMenuListener(contextMenuListener);
optionsBtn.setOnClickListener(this);
} }
@Override @Override
@@ -243,45 +216,6 @@ public class MapActivity extends com.google.android.maps.MapActivity
super.onPause(); super.onPause();
} }
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DIALOG_INSTALL_EARTH_ID:
return PlayTrackUtils.createInstallEarthDialog(this);
case DIALOG_DELETE_CURRENT_ID:
return DialogUtils.createConfirmationDialog(this,
R.string.track_list_delete_track_confirm_message,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
long trackId = dataHub.getSelectedTrackId();
MyTracksProviderUtils.Factory.get(MapActivity.this).deleteTrack(trackId);
// If the deleted track was selected, unselect it.
String selectedTrackKey = getString(R.string.selected_track_key);
SharedPreferences sharedPreferences = getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
if (sharedPreferences.getLong(selectedTrackKey, -1L) == trackId) {
Editor editor = sharedPreferences.edit().putLong(selectedTrackKey, -1L);
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
}
}
});
default:
return null;
}
}
// Utility functions:
// -------------------
/**
* Shows the options button if a track is selected, or hide it if not.
*/
private void updateOptionsButton(boolean trackSelected) {
optionsBtn.setVisibility(
trackSelected ? View.VISIBLE : View.INVISIBLE);
}
/** /**
* Tests if a location is visible. * Tests if a location is visible.
* *
@@ -451,8 +385,6 @@ public class MapActivity extends com.google.android.maps.MapActivity
@Override @Override
public void run() { public void run() {
boolean trackSelected = track != null; boolean trackSelected = track != null;
updateOptionsButton(trackSelected);
mapOverlay.setTrackDrawingEnabled(trackSelected); mapOverlay.setTrackDrawingEnabled(trackSelected);
if (trackSelected) { if (trackSelected) {
@@ -473,134 +405,6 @@ public class MapActivity extends com.google.android.maps.MapActivity
}); });
} }
private final OnCreateContextMenuListener contextMenuListener =
new OnCreateContextMenuListener() {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
menu.setHeaderTitle(R.string.track_list_context_menu_title);
menu.add(Menu.NONE, Constants.MENU_EDIT, Menu.NONE, R.string.track_list_edit_track);
if (!dataHub.isRecordingSelected()) {
String saveFileFormat = getString(R.string.track_list_save_file);
String shareFileFormat = getString(R.string.track_list_share_file);
String fileTypes[] = getResources().getStringArray(R.array.file_types);
menu.add(Menu.NONE, Constants.MENU_PLAY, Menu.NONE, R.string.track_list_play);
menu.add(Menu.NONE, Constants.MENU_SEND_TO_GOOGLE, Menu.NONE,
R.string.track_list_send_google);
SubMenu share = menu.addSubMenu(
Menu.NONE, Constants.MENU_SHARE, Menu.NONE, R.string.track_list_share_track);
share.add(
Menu.NONE, Constants.MENU_SHARE_MAP, Menu.NONE, R.string.track_list_share_map);
share.add(Menu.NONE, Constants.MENU_SHARE_FUSION_TABLE, Menu.NONE,
R.string.track_list_share_fusion_table);
share.add(Menu.NONE, Constants.MENU_SHARE_GPX_FILE, Menu.NONE,
String.format(shareFileFormat, fileTypes[0]));
share.add(Menu.NONE, Constants.MENU_SHARE_KML_FILE, Menu.NONE,
String.format(shareFileFormat, fileTypes[1]));
share.add(Menu.NONE, Constants.MENU_SHARE_CSV_FILE, Menu.NONE,
String.format(shareFileFormat, fileTypes[2]));
share.add(Menu.NONE, Constants.MENU_SHARE_TCX_FILE, Menu.NONE,
String.format(shareFileFormat, fileTypes[3]));
SubMenu save = menu.addSubMenu(
Menu.NONE, Constants.MENU_WRITE_TO_SD_CARD, Menu.NONE, R.string.track_list_save_sd);
save.add(Menu.NONE, Constants.MENU_SAVE_GPX_FILE, Menu.NONE,
String.format(saveFileFormat, fileTypes[0]));
save.add(Menu.NONE, Constants.MENU_SAVE_KML_FILE, Menu.NONE,
String.format(saveFileFormat, fileTypes[1]));
save.add(Menu.NONE, Constants.MENU_SAVE_CSV_FILE, Menu.NONE,
String.format(saveFileFormat, fileTypes[2]));
save.add(Menu.NONE, Constants.MENU_SAVE_TCX_FILE, Menu.NONE,
String.format(saveFileFormat, fileTypes[3]));
menu.add(Menu.NONE, Constants.MENU_CLEAR_MAP, Menu.NONE, R.string.track_list_clear_map);
menu.add(Menu.NONE, Constants.MENU_DELETE, Menu.NONE, R.string.track_list_delete_track);
}
}
};
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
Intent intent;
long trackId = dataHub.getSelectedTrackId();
switch (item.getItemId()) {
case Constants.MENU_EDIT:
intent = new Intent(this, TrackEditActivity.class)
.putExtra(TrackEditActivity.TRACK_ID, trackId);
startActivity(intent);
return true;
case Constants.MENU_PLAY:
if (PlayTrackUtils.isEarthInstalled(this)) {
PlayTrackUtils.playTrack(this, trackId);
return true;
} else {
showDialog(DIALOG_INSTALL_EARTH_ID);
return true;
}
case Constants.MENU_SEND_TO_GOOGLE:
intent = new Intent(this, UploadServiceChooserActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, new SendRequest(trackId, true, true, true));
startActivity(intent);
return true;
case Constants.MENU_SHARE_MAP:
intent = new Intent(this, UploadServiceChooserActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, new SendRequest(trackId, true, false, false));
startActivity(intent);
return true;
case Constants.MENU_SHARE_FUSION_TABLE:
intent = new Intent(this, UploadServiceChooserActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, new SendRequest(trackId, false, true, false));
startActivity(intent);
return true;
case Constants.MENU_SHARE_GPX_FILE:
startSaveActivity(trackId, TrackFileFormat.GPX, true);
return true;
case Constants.MENU_SHARE_KML_FILE:
startSaveActivity(trackId, TrackFileFormat.KML, true);
return true;
case Constants.MENU_SHARE_CSV_FILE:
startSaveActivity(trackId, TrackFileFormat.CSV, true);
return true;
case Constants.MENU_SHARE_TCX_FILE:
startSaveActivity(trackId, TrackFileFormat.TCX, true);
return true;
case Constants.MENU_SAVE_GPX_FILE:
startSaveActivity(trackId, TrackFileFormat.GPX, false);
return true;
case Constants.MENU_SAVE_KML_FILE:
startSaveActivity(trackId, TrackFileFormat.KML, false);
return true;
case Constants.MENU_SAVE_CSV_FILE:
startSaveActivity(trackId, TrackFileFormat.CSV, false);
return true;
case Constants.MENU_SAVE_TCX_FILE:
startSaveActivity(trackId, TrackFileFormat.TCX, false);
return true;
case Constants.MENU_CLEAR_MAP:
dataHub.unloadCurrentTrack();
return true;
case Constants.MENU_DELETE:
showDialog(DIALOG_DELETE_CURRENT_ID);
return true;
default:
return super.onMenuItemSelected(featureId, item);
}
}
/**
* Starts the {@link SaveActivity} to save a track.
*
* @param trackId the track id
* @param trackFileFormat the track file format
* @param shareTrack true to share the track after saving
*/
private void startSaveActivity(
long trackId, TrackFileFormat trackFileFormat, boolean shareTrack) {
Intent intent = new Intent(this, SaveActivity.class)
.putExtra(SaveActivity.EXTRA_TRACK_ID, trackId)
.putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) trackFileFormat)
.putExtra(SaveActivity.EXTRA_SHARE_TRACK, shareTrack);
startActivity(intent);
}
/** /**
* Returns whether the map is currently in satellite view mode. * Returns whether the map is currently in satellite view mode.
*/ */
@@ -619,8 +423,6 @@ public class MapActivity extends com.google.android.maps.MapActivity
public void onClick(View v) { public void onClick(View v) {
if (v == messagePane) { if (v == messagePane) {
startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)); startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
} else if (v == optionsBtn) {
optionsBtn.performLongClick();
} }
} }
@@ -189,7 +189,7 @@ public class SearchActivity extends ListActivity {
resultMap.put(DESCRIPTION_FIELD, waypoint.getDescription()); resultMap.put(DESCRIPTION_FIELD, waypoint.getDescription());
resultMap.put(CATEGORY_FIELD, waypoint.getCategory()); resultMap.put(CATEGORY_FIELD, waypoint.getCategory());
// In the same place as we show time for tracks, show the track name for waypoints. // In the same place as we show time for tracks, show the track name for waypoints.
resultMap.put(TIME_FIELD, getString(R.string.track_list_track_name, trackName)); resultMap.put(TIME_FIELD, getString(R.string.search_track_location, trackName));
resultMap.put(STATS_FIELD, StringUtils.formatDateTime(this, waypoint.getLocation().getTime())); resultMap.put(STATS_FIELD, StringUtils.formatDateTime(this, waypoint.getLocation().getTime()));
resultMap.put(TRACK_ID_FIELD, waypoint.getTrackId()); resultMap.put(TRACK_ID_FIELD, waypoint.getTrackId());
resultMap.put(WAYPOINT_ID_FIELD, waypoint.getId()); resultMap.put(WAYPOINT_ID_FIELD, waypoint.getId());
@@ -18,25 +18,33 @@ package com.google.android.apps.mytracks;
import static com.google.android.apps.mytracks.Constants.CHART_TAB_TAG; import static com.google.android.apps.mytracks.Constants.CHART_TAB_TAG;
import static com.google.android.apps.mytracks.Constants.MAP_TAB_TAG; import static com.google.android.apps.mytracks.Constants.MAP_TAB_TAG;
import static com.google.android.apps.mytracks.Constants.STATS_TAB_TAG; import static com.google.android.apps.mytracks.Constants.STATS_TAB_TAG;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
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.WaypointCreationRequest; import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.io.file.SaveActivity;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.io.sendtogoogle.UploadServiceChooserActivity;
import com.google.android.apps.mytracks.services.ITrackRecordingService; import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.services.ServiceUtils; import com.google.android.apps.mytracks.services.ServiceUtils;
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection; import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
import com.google.android.apps.mytracks.util.ApiAdapterFactory; import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.apps.mytracks.util.PlayTrackUtils;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import com.google.common.annotations.VisibleForTesting;
import android.app.Dialog;
import android.app.TabActivity; import android.app.TabActivity;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcelable;
import android.os.RemoteException; import android.os.RemoteException;
import android.speech.tts.TextToSpeech; import android.speech.tts.TextToSpeech;
import android.util.Log; import android.util.Log;
@@ -62,20 +70,23 @@ public class TrackDetailActivity extends TabActivity implements OnTouchListener
public static final String TRACK_ID = "track_id"; public static final String TRACK_ID = "track_id";
public static final String WAYPOINT_ID = "waypoint_id"; public static final String WAYPOINT_ID = "waypoint_id";
private MyTracksProviderUtils myTracksProviderUtils; private static final String TAG = TrackDetailActivity.class.getSimpleName();
private static final int DIALOG_INSTALL_EARTH_ID = 0;
private static final int DIALOG_DELETE_CURRENT_ID = 1;
private SharedPreferences sharedPreferences; private SharedPreferences sharedPreferences;
private TrackDataHub trackDataHub; private TrackDataHub trackDataHub;
private TrackRecordingServiceConnection trackRecordingServiceConnection; private TrackRecordingServiceConnection trackRecordingServiceConnection;
private NavControls navControls; private NavControls navControls;
private MenuItem recordTrack;
private MenuItem stopRecording; private MenuItem stopRecording;
private MenuItem insertMarker;
/** private MenuItem play;
* True if a new track should be created after the track recording service private MenuItem share;
* binds. private MenuItem sendGoogle;
*/ private MenuItem save;
private boolean startNewTrackRequested = false; private MenuItem edit;
private MenuItem delete;
private final Runnable changeTab = new Runnable() { private final Runnable changeTab = new Runnable() {
public void run() { public void run() {
@@ -83,21 +94,22 @@ public class TrackDetailActivity extends TabActivity implements OnTouchListener
} }
}; };
/** /*
* Callback when {@linkk TrackRecordingServiceConnection} binding changes. * Note that sharedPreferenceChangeListener cannot be an anonymous inner
* class. Anonymous inner class will get garbage collected.
*/ */
private final Runnable serviceBindCallback = new Runnable() { private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener =
new OnSharedPreferenceChangeListener() {
@Override @Override
public void run() { public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
synchronized (trackRecordingServiceConnection) { if (key == null) {
ITrackRecordingService service = trackRecordingServiceConnection.getServiceIfBound(); return;
if (startNewTrackRequested && service != null) { }
Log.i(TAG, "Starting recording"); if (key.equals(getString(R.string.recording_track_key))) {
startNewTrackRequested = false; if (isRecording()) {
startRecordingNewTrack(service); trackRecordingServiceConnection.startAndBind();
} else if (startNewTrackRequested) {
Log.w(TAG, "Not yet starting recording");
} }
updateMenu();
} }
} }
}; };
@@ -106,10 +118,10 @@ public class TrackDetailActivity extends TabActivity implements OnTouchListener
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(this);
sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE); sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
trackDataHub = ((MyTracksApplication) getApplication()).getTrackDataHub(); trackDataHub = ((MyTracksApplication) getApplication()).getTrackDataHub();
trackRecordingServiceConnection = new TrackRecordingServiceConnection(this, serviceBindCallback); trackRecordingServiceConnection = new TrackRecordingServiceConnection(this, null);
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM); setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
@@ -119,8 +131,7 @@ public class TrackDetailActivity extends TabActivity implements OnTouchListener
final Resources res = getResources(); final Resources res = getResources();
final TabHost tabHost = getTabHost(); final TabHost tabHost = getTabHost();
tabHost.addTab(tabHost.newTabSpec(MAP_TAB_TAG) tabHost.addTab(tabHost.newTabSpec(MAP_TAB_TAG)
.setIndicator("Map", res.getDrawable( .setIndicator("Map", res.getDrawable(android.R.drawable.ic_menu_mapmode))
android.R.drawable.ic_menu_mapmode))
.setContent(new Intent(this, MapActivity.class))); .setContent(new Intent(this, MapActivity.class)));
tabHost.addTab(tabHost.newTabSpec(STATS_TAB_TAG) tabHost.addTab(tabHost.newTabSpec(STATS_TAB_TAG)
.setIndicator("Stats", res.getDrawable(R.drawable.ic_menu_statistics)) .setIndicator("Stats", res.getDrawable(R.drawable.ic_menu_statistics))
@@ -134,14 +145,10 @@ public class TrackDetailActivity extends TabActivity implements OnTouchListener
tabHost.getTabWidget().setVisibility(View.GONE); tabHost.getTabWidget().setVisibility(View.GONE);
RelativeLayout layout = new RelativeLayout(this); RelativeLayout layout = new RelativeLayout(this);
LayoutParams params = LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
layout.setLayoutParams(params); layout.setLayoutParams(params);
navControls = navControls = new NavControls(this, layout, getResources().obtainTypedArray(R.array.left_icons),
new NavControls(this, layout, getResources().obtainTypedArray(R.array.right_icons), changeTab);
getResources().obtainTypedArray(R.array.left_icons),
getResources().obtainTypedArray(R.array.right_icons),
changeTab);
navControls.show(); navControls.show();
tabHost.addView(layout); tabHost.addView(layout);
layout.setOnTouchListener(this); layout.setOnTouchListener(this);
@@ -152,9 +159,7 @@ public class TrackDetailActivity extends TabActivity implements OnTouchListener
super.onStart(); super.onStart();
trackDataHub.start(); trackDataHub.start();
// Ensure that service is running and bound if we're supposed to be recording if (isRecording()) {
if (ServiceUtils.isRecording(
this, trackRecordingServiceConnection.getServiceIfBound(), sharedPreferences)) {
trackRecordingServiceConnection.startAndBind(); trackRecordingServiceConnection.startAndBind();
} }
@@ -167,15 +172,23 @@ public class TrackDetailActivity extends TabActivity implements OnTouchListener
long waypointId = intent.getLongExtra(WAYPOINT_ID, -1L); long waypointId = intent.getLongExtra(WAYPOINT_ID, -1L);
if (waypointId != -1L) { if (waypointId != -1L) {
Waypoint waypoint = myTracksProviderUtils.getWaypoint(waypointId); Waypoint waypoint = MyTracksProviderUtils.Factory.get(this).getWaypoint(waypointId);
trackId = waypoint.getTrackId(); if (waypoint != null) {
trackId = waypoint.getTrackId();
// Request that the waypoint is shown (now or when the right track is loaded). trackDataHub.loadTrack(trackId);
showWaypoint(trackId, waypointId); MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
// Load the right track, if not loaded already. getTabHost().setCurrentTab(0);
trackDataHub.loadTrack(trackId); mapActivity.showWaypoint(trackId, waypointId);
} else {
Log.e(TAG, "MapActivity is null");
}
return;
}
} }
// No track id or waypoint id, return to the track list activity.
startTrackListActivity();
} }
@Override @Override
@@ -196,98 +209,166 @@ public class TrackDetailActivity extends TabActivity implements OnTouchListener
trackRecordingServiceConnection.unbind(); trackRecordingServiceConnection.unbind();
} }
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DIALOG_INSTALL_EARTH_ID:
return PlayTrackUtils.createInstallEarthDialog(this);
case DIALOG_DELETE_CURRENT_ID:
return DialogUtils.createConfirmationDialog(this,
R.string.track_detail_delete_confirm_message, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
long trackId = trackDataHub.getSelectedTrackId();
MyTracksProviderUtils.Factory.get(TrackDetailActivity.this).deleteTrack(trackId);
startTrackListActivity();
}
});
default:
return null;
}
}
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.track_detail, menu); getMenuInflater().inflate(R.menu.track_detail, menu);
recordTrack = menu.findItem(R.id.menu_record_track); String fileTypes[] = getResources().getStringArray(R.array.file_types);
menu.findItem(R.id.menu_save_gpx).setTitle(getString(R.string.menu_save_format, fileTypes[0]));
menu.findItem(R.id.menu_save_kml).setTitle(getString(R.string.menu_save_format, fileTypes[1]));
menu.findItem(R.id.menu_save_csv).setTitle(getString(R.string.menu_save_format, fileTypes[2]));
menu.findItem(R.id.menu_save_tcx).setTitle(getString(R.string.menu_save_format, fileTypes[3]));
menu.findItem(R.id.menu_share_gpx).setTitle(getString(R.string.menu_share_file, fileTypes[0]));
menu.findItem(R.id.menu_share_kml).setTitle(getString(R.string.menu_share_file, fileTypes[1]));
menu.findItem(R.id.menu_share_csv).setTitle(getString(R.string.menu_share_file, fileTypes[2]));
menu.findItem(R.id.menu_share_tcx).setTitle(getString(R.string.menu_share_file, fileTypes[3]));
stopRecording = menu.findItem(R.id.menu_stop_recording); stopRecording = menu.findItem(R.id.menu_stop_recording);
insertMarker = menu.findItem(R.id.menu_insert_marker);
play = menu.findItem(R.id.menu_play);
share = menu.findItem(R.id.menu_share);
sendGoogle = menu.findItem(R.id.menu_send_google);
save = menu.findItem(R.id.menu_save);
edit = menu.findItem(R.id.menu_edit);
delete = menu.findItem(R.id.menu_delete);
updateMenu();
return true; return true;
} }
@Override @Override
public boolean onPrepareOptionsMenu(Menu menu) { public boolean onPrepareOptionsMenu(Menu menu) {
updateMenuItems(ServiceUtils.isRecording(
this, trackRecordingServiceConnection.getServiceIfBound(), sharedPreferences));
String currentTabTag = getTabHost().getCurrentTabTag(); String currentTabTag = getTabHost().getCurrentTabTag();
menu.findItem(R.id.menu_chart_settings).setVisible(CHART_TAB_TAG.equals(currentTabTag)); menu.findItem(R.id.menu_chart_settings).setVisible(CHART_TAB_TAG.equals(currentTabTag));
menu.findItem(R.id.menu_my_location).setVisible(MAP_TAB_TAG.equals(currentTabTag)); menu.findItem(R.id.menu_my_location).setVisible(MAP_TAB_TAG.equals(currentTabTag));
// Set map or satellite mode // Set map or satellite mode
MapActivity mapActivity = (MapActivity) getLocalActivityManager().getActivity(MAP_TAB_TAG); MapActivity mapActivity = getMapActivity();
boolean isSatelliteMode = mapActivity != null ? mapActivity.isSatelliteView() : false; boolean isSatelliteMode = mapActivity != null ? mapActivity.isSatelliteView() : false;
menu.findItem(R.id.menu_satellite_mode) menu.findItem(R.id.menu_satellite_mode).setVisible(MAP_TAB_TAG.equals(currentTabTag))
.setVisible(MAP_TAB_TAG.equals(currentTabTag))
.setTitle(isSatelliteMode ? R.string.menu_map_mode : R.string.menu_satellite_mode); .setTitle(isSatelliteMode ? R.string.menu_map_mode : R.string.menu_satellite_mode);
return super.onPrepareOptionsMenu(menu); return super.onPrepareOptionsMenu(menu);
} }
/**
* Updates menu item
*
* @param isRecording true if recording
*/
private void updateMenuItems(boolean isRecording) {
if (recordTrack != null) {
recordTrack.setVisible(!isRecording);
}
if (stopRecording != null) {
stopRecording.setVisible(isRecording);
}
}
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
MapActivity mapActivity; MapActivity mapActivity;
Intent intent;
long trackId = trackDataHub.getSelectedTrackId();
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.menu_record_track:
updateMenuItems(true);
startRecording();
return true;
case R.id.menu_stop_recording: case R.id.menu_stop_recording:
updateMenuItems(false); updateMenuItems(false);
stopRecording(); stopRecording();
return true; return true;
case R.id.menu_insert_marker:
// TODO:
return true;
case R.id.menu_play:
if (PlayTrackUtils.isEarthInstalled(this)) {
PlayTrackUtils.playTrack(this, trackId);
} else {
showDialog(DIALOG_INSTALL_EARTH_ID);
}
return true;
case R.id.menu_share_map:
intent = new Intent(this, UploadServiceChooserActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, new SendRequest(trackId, true, false, false));
startActivity(intent);
return true;
case R.id.menu_share_fusion_table:
intent = new Intent(this, UploadServiceChooserActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, new SendRequest(trackId, false, true, false));
startActivity(intent);
return true;
case R.id.menu_share_gpx:
startSaveActivity(trackId, TrackFileFormat.GPX, true);
return true;
case R.id.menu_share_kml:
startSaveActivity(trackId, TrackFileFormat.KML, true);
return true;
case R.id.menu_share_csv:
startSaveActivity(trackId, TrackFileFormat.CSV, true);
return true;
case R.id.menu_share_tcx:
startSaveActivity(trackId, TrackFileFormat.TCX, true);
return true;
case R.id.menu_markers: case R.id.menu_markers:
Intent intent = new Intent(this, WaypointsList.class) intent = new Intent(this, WaypointsList.class)
.putExtra("trackid", trackDataHub.getSelectedTrackId()); .putExtra("trackid", trackDataHub.getSelectedTrackId());
startActivityForResult(intent, Constants.SHOW_WAYPOINT); startActivityForResult(intent, Constants.SHOW_WAYPOINT);
return true; return true;
case R.id.menu_send_google:
intent = new Intent(this, UploadServiceChooserActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, new SendRequest(trackId, true, true, true));
startActivity(intent);
return true;
case R.id.menu_save_gpx:
startSaveActivity(trackId, TrackFileFormat.GPX, false);
return true;
case R.id.menu_save_kml:
startSaveActivity(trackId, TrackFileFormat.KML, false);
return true;
case R.id.menu_save_csv:
startSaveActivity(trackId, TrackFileFormat.CSV, false);
return true;
case R.id.menu_save_tcx:
startSaveActivity(trackId, TrackFileFormat.TCX, false);
return true;
case R.id.menu_edit:
startActivity(new Intent(this, TrackEditActivity.class)
.putExtra(TrackEditActivity.TRACK_ID, trackId));
return true;
case R.id.menu_delete:
showDialog(DIALOG_DELETE_CURRENT_ID);
return true;
case R.id.menu_my_location:
mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.showMyLocation();
}
return true;
case R.id.menu_satellite_mode:
mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.setSatelliteView(!mapActivity.isSatelliteView());
}
return true;
case R.id.menu_chart_settings:
ChartActivity chartActivity = getChartActivity();
if (chartActivity != null) {
chartActivity.showChartSettingsDialog();
}
return true;
case R.id.menu_sensor_state: case R.id.menu_sensor_state:
startActivity(new Intent(this, SensorStateActivity.class)); startActivity(new Intent(this, SensorStateActivity.class));
return true; return true;
case R.id.menu_settings: case R.id.menu_settings:
startActivity(new Intent(this, SettingsActivity.class)); startActivity(new Intent(this, SettingsActivity.class));
return true; return true;
case R.id.menu_aggregated_statistics:
startActivity(new Intent(this, AggregatedStatsActivity.class));
return true;
case R.id.menu_help: case R.id.menu_help:
startActivity(new Intent(this, WelcomeActivity.class)); startActivity(new Intent(this, WelcomeActivity.class));
return true; return true;
case R.id.menu_search:
onSearchRequested();
return true;
case R.id.menu_chart_settings:
ChartActivity chartActivity = (ChartActivity) getLocalActivityManager()
.getActivity(CHART_TAB_TAG);
if (chartActivity != null) {
chartActivity.showChartSettingsDialog();
}
return true;
case R.id.menu_my_location:
mapActivity = (MapActivity) getLocalActivityManager().getActivity(MAP_TAB_TAG);
if (mapActivity != null) {
mapActivity.showMyLocation();
}
return true;
case R.id.menu_satellite_mode:
mapActivity = (MapActivity) getLocalActivityManager().getActivity(MAP_TAB_TAG);
if (mapActivity != null) {
mapActivity.setSatelliteView(!mapActivity.isSatelliteView());
}
return true;
default: default:
return false; return false;
} }
@@ -296,7 +377,7 @@ public class TrackDetailActivity extends TabActivity implements OnTouchListener
@Override @Override
public void onActivityResult(int requestCode, int resultCode, final Intent results) { public void onActivityResult(int requestCode, int resultCode, final Intent results) {
if (requestCode != Constants.SHOW_WAYPOINT) { if (requestCode != Constants.SHOW_WAYPOINT) {
Log.d(TAG, "Warning unhandled request code: " + requestCode); Log.d(TAG, "Invalid request code: " + requestCode);
return; return;
} }
if (results != null) { if (results != null) {
@@ -314,18 +395,30 @@ public class TrackDetailActivity extends TabActivity implements OnTouchListener
@Override @Override
public boolean onTrackballEvent(MotionEvent event) { public boolean onTrackballEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) { if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (ServiceUtils.isRecording(this, trackRecordingServiceConnection.getServiceIfBound(), sharedPreferences)) { if (isRecording()) {
try { ITrackRecordingService trackRecordingService = trackRecordingServiceConnection
insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS); .getServiceIfBound();
} catch (RemoteException e) { if (trackRecordingService == null) {
Log.e(TAG, "Cannot insert statistics marker.", e); Log.e(TAG, "The track recording service is null");
} catch (IllegalStateException e) { return true;
Log.e(TAG, "Cannot insert statistics marker.", e);
} }
boolean success = false;
try {
long waypointId = trackRecordingService.insertWaypoint(
WaypointCreationRequest.DEFAULT_STATISTICS);
if (waypointId != -1L) {
success = true;
}
} catch (RemoteException e) {
Log.e(TAG, "Unable to insert waypoint", e);
}
Toast.makeText(this,
success ? R.string.marker_insert_success : R.string.marker_insert_error,
success ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG)
.show();
return true; return true;
} }
} }
return super.onTrackballEvent(event); return super.onTrackballEvent(event);
} }
@@ -337,85 +430,87 @@ public class TrackDetailActivity extends TabActivity implements OnTouchListener
return false; return false;
} }
private void showWaypoint(long trackId, long waypointId) { /**
MapActivity map = * Updates the menu.
(MapActivity) getLocalActivityManager().getActivity("tab1"); */
if (map != null) { private void updateMenu() {
getTabHost().setCurrentTab(0); updateMenuItems(isRecording());
map.showWaypoint(trackId, waypointId);
} else {
Log.e(TAG, "Couldnt' get map tab");
}
} }
/** /**
* Inserts a waypoint marker. * s Updates the menu items.
* *
* TODO: Merge with WaypointsList#insertWaypoint. * @param isRecording true if recording
*/
private void updateMenuItems(boolean isRecording) {
if (stopRecording != null) {
stopRecording.setVisible(isRecording);
}
if (insertMarker != null) {
insertMarker.setVisible(isRecording);
}
if (play != null) {
play.setVisible(!isRecording);
}
if (share != null) {
share.setVisible(!isRecording);
}
if (sendGoogle != null) {
sendGoogle.setVisible(!isRecording);
}
if (save != null) {
save.setVisible(!isRecording);
}
if (edit != null) {
edit.setVisible(!isRecording);
}
if (delete != null) {
delete.setVisible(!isRecording);
}
}
/**
* Starts the {@link TrackListActivity} and ends this activity.
*/
private void startTrackListActivity() {
Intent intent = new Intent(this, TrackListActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
}
/**
* Starts the {@link SaveActivity} to save a track.
* *
* @return Id of the inserted statistics marker. * @param trackId the track id
* @throws RemoteException If the call on the service failed. * @param trackFileFormat the track file format
* @param shareTrack true to share the track after saving
*/ */
private long insertWaypoint(WaypointCreationRequest request) throws RemoteException { private void startSaveActivity(
ITrackRecordingService trackRecordingService = trackRecordingServiceConnection.getServiceIfBound(); long trackId, TrackFileFormat trackFileFormat, boolean shareTrack) {
if (trackRecordingService == null) { Intent intent = new Intent(this, SaveActivity.class)
throw new IllegalStateException("The recording service is not bound."); .putExtra(SaveActivity.EXTRA_TRACK_ID, trackId)
} .putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) trackFileFormat)
try { .putExtra(SaveActivity.EXTRA_SHARE_TRACK, shareTrack);
long waypointId = trackRecordingService.insertWaypoint(request); startActivity(intent);
if (waypointId >= 0) {
Toast.makeText(this, R.string.marker_insert_success, Toast.LENGTH_LONG).show();
}
return waypointId;
} catch (RemoteException e) {
Toast.makeText(this, R.string.marker_insert_error, Toast.LENGTH_LONG).show();
throw e;
}
}
private void startRecordingNewTrack(
ITrackRecordingService trackRecordingService) {
try {
long recordingTrackId = trackRecordingService.startNewTrack();
// Select the recording track.
trackDataHub.loadTrack(recordingTrackId);
Toast.makeText(this, getString(R.string.track_record_success), Toast.LENGTH_SHORT).show();
// TODO: We catch Exception, because after eliminating the service process
// all exceptions it may throw are no longer wrapped in a RemoteException.
} catch (Exception e) {
Toast.makeText(this, getString(R.string.track_record_error), Toast.LENGTH_SHORT).show();
Log.w(TAG, "Unable to start recording.", e);
}
} }
/** /**
* Starts the track recording service (if not already running) and binds to * Returns true if recording.
* it. Starts recording a new track.
*/ */
@VisibleForTesting private boolean isRecording() {
void startRecording() { return ServiceUtils.isRecording(
synchronized (trackRecordingServiceConnection) { this, trackRecordingServiceConnection.getServiceIfBound(), sharedPreferences);
startNewTrackRequested = true;
trackRecordingServiceConnection.startAndBind();
// Binding was already requested before, it either already happened
// (in which case running the callback manually triggers the actual recording start)
// or it will happen in the future
// (in which case running the callback now will have no effect).
serviceBindCallback.run();
}
} }
/** /**
* Stops the track recording service and unbinds from it. Will display a toast * Stops the recording and the track recording service connection and shows
* "Stopped recording" and pop up the Track Details activity. * {@link TrackEditActivity}.
*/ */
@VisibleForTesting private void stopRecording() {
void stopRecording() { ITrackRecordingService trackRecordingService = trackRecordingServiceConnection
// Save the track id as the shared preference will overwrite the recording track id. .getServiceIfBound();
long currentTrackId = sharedPreferences.getLong(getString(R.string.recording_track_key), -1L);
ITrackRecordingService trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
if (trackRecordingService != null) { if (trackRecordingService != null) {
try { try {
trackRecordingService.endCurrentTrack(); trackRecordingService.endCurrentTrack();
@@ -423,14 +518,28 @@ public class TrackDetailActivity extends TabActivity implements OnTouchListener
Log.e(TAG, "Unable to stop recording.", e); Log.e(TAG, "Unable to stop recording.", e);
} }
} }
trackRecordingServiceConnection.stop(); trackRecordingServiceConnection.stop();
if (currentTrackId > 0) { long recordingTrackId = sharedPreferences.getLong(getString(R.string.recording_track_key), -1L);
if (recordingTrackId != -1L) {
Intent intent = new Intent(this, TrackEditActivity.class) Intent intent = new Intent(this, TrackEditActivity.class)
.putExtra(TrackEditActivity.SHOW_CANCEL, false) .putExtra(TrackEditActivity.SHOW_CANCEL, false)
.putExtra(TrackEditActivity.TRACK_ID, currentTrackId); .putExtra(TrackEditActivity.TRACK_ID, recordingTrackId);
startActivity(intent); startActivity(intent);
} }
} }
/**
* Gets the map activity, can be null.
*/
private MapActivity getMapActivity() {
return (MapActivity) getLocalActivityManager().getActivity(MAP_TAB_TAG);
}
/**
* Gets the chart activity, can be null.
*/
private ChartActivity getChartActivity() {
return (ChartActivity) getLocalActivityManager().getActivity(CHART_TAB_TAG);
}
} }
@@ -35,6 +35,7 @@ import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.database.Cursor; import android.database.Cursor;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcelable; import android.os.Parcelable;
@@ -81,21 +82,57 @@ public class TrackListActivity extends FragmentActivity {
TracksColumns.STARTTIME, TracksColumns.STARTTIME,
TracksColumns.DESCRIPTION }; TracksColumns.DESCRIPTION };
// Callback when the trackRecordingServiceConnection binding changes // Callback when the trackRecordingServiceConnection binding changes.
private final Runnable bindChangedCallback = new Runnable() { private final Runnable bindChangedCallback = new Runnable() {
@Override @Override
public void run() { public void run() {
synchronized (trackRecordingServiceConnection) { if (startNewRecording) {
if (startNewRecording) { ITrackRecordingService service = trackRecordingServiceConnection.getServiceIfBound();
startRecording(); if (service != null) {
try {
recordingTrackId = service.startNewTrack();
startNewRecording = false;
Toast.makeText(
TrackListActivity.this, R.string.track_list_record_success, Toast.LENGTH_SHORT)
.show();
Log.d(TAG, "Started a new recording");
} catch (Exception e) {
Toast.makeText(
TrackListActivity.this, R.string.track_list_record_error, Toast.LENGTH_LONG).show();
Log.d(TAG, "Unable to start a new recording.", e);
}
} else { } else {
updateMenu(); Log.d(TAG, "service not available to start a new recording");
adapter.notifyDataSetChanged();
} }
} }
} }
}; };
/*
* Note that sharedPreferenceChangeListenr cannot be an anonymous inner class.
* Anonymous inner class will get garbage collected.
*/
private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener =
new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (key == null) {
return;
}
if (key.equals(getString(R.string.metric_units_key))) {
metricUnits = preferences.getBoolean(getString(R.string.metric_units_key), true);
}
if (key.equals(getString(R.string.recording_track_key))) {
recordingTrackId = sharedPreferences.getLong(getString(R.string.recording_track_key), -1L);
if (isRecording()) {
trackRecordingServiceConnection.startAndBind();
}
updateMenu();
}
adapter.notifyDataSetChanged();
}
};
private TrackRecordingServiceConnection trackRecordingServiceConnection; private TrackRecordingServiceConnection trackRecordingServiceConnection;
private SharedPreferences sharedPreferences; private SharedPreferences sharedPreferences;
private boolean metricUnits; private boolean metricUnits;
@@ -103,7 +140,7 @@ public class TrackListActivity extends FragmentActivity {
private ListView listView; private ListView listView;
private ResourceCursorAdapter adapter; private ResourceCursorAdapter adapter;
// True to start a new recording // True to start a new recording.
private boolean startNewRecording = false; private boolean startNewRecording = false;
private MenuItem recordTrack; private MenuItem recordTrack;
@@ -124,23 +161,7 @@ public class TrackListActivity extends FragmentActivity {
this, bindChangedCallback); this, bindChangedCallback);
sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE); sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
sharedPreferences.registerOnSharedPreferenceChangeListener( sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (key == null) {
return;
}
if (key.equals(getString(R.string.metric_units_key))) {
metricUnits = preferences.getBoolean(getString(R.string.metric_units_key), true);
}
if (key.equals(getString(R.string.recording_track_key))) {
recordingTrackId = sharedPreferences.getLong(
getString(R.string.recording_track_key), -1L);
}
adapter.notifyDataSetChanged();
}
});
metricUnits = sharedPreferences.getBoolean(getString(R.string.metric_units_key), true); metricUnits = sharedPreferences.getBoolean(getString(R.string.metric_units_key), true);
recordingTrackId = sharedPreferences.getLong(getString(R.string.recording_track_key), -1L); recordingTrackId = sharedPreferences.getLong(getString(R.string.recording_track_key), -1L);
@@ -225,8 +246,7 @@ public class TrackListActivity extends FragmentActivity {
@Override @Override
protected void onStart() { protected void onStart() {
super.onStart(); super.onStart();
if (ServiceUtils.isRecording( if (isRecording()) {
this, trackRecordingServiceConnection.getServiceIfBound(), sharedPreferences)) {
trackRecordingServiceConnection.startAndBind(); trackRecordingServiceConnection.startAndBind();
} }
} }
@@ -237,7 +257,6 @@ public class TrackListActivity extends FragmentActivity {
trackRecordingServiceConnection.bindIfRunning(); trackRecordingServiceConnection.bindIfRunning();
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
@@ -250,9 +269,10 @@ public class TrackListActivity extends FragmentActivity {
if (!CheckUnitsUtils.getCheckUnitsValue(this)) { if (!CheckUnitsUtils.getCheckUnitsValue(this)) {
/* /*
* See bug http://code.google.com/p/android/issues/detail?id=23761. * See bug http://code.google.com/p/android/issues/detail?id=23761.
* Instead of * Cannot use
* new CheckUnitsDialogFragment().show(getSupportFragmentManager(), CHECK_UNITS_DIALOG_TAG) * CheckUnitsDialogFragment().show(getSupportFragmentManager(),
* Need to use commitAllowingStateLoss with the support package. * CHECK_UNITS_DIALOG_TAG). Need to use commitAllowingStateLoss with the
* support package.
*/ */
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(new CheckUnitsDialogFragment(), CHECK_UNITS_DIALOG_TAG); fragmentTransaction.add(new CheckUnitsDialogFragment(), CHECK_UNITS_DIALOG_TAG);
@@ -281,8 +301,7 @@ public class TrackListActivity extends FragmentActivity {
* Updates the menu based on whether My Tracks is recording or not. * Updates the menu based on whether My Tracks is recording or not.
*/ */
private void updateMenu() { private void updateMenu() {
boolean isRecording = ServiceUtils.isRecording( boolean isRecording = isRecording();
this, trackRecordingServiceConnection.getServiceIfBound(), sharedPreferences);
updateMenuItems(isRecording); updateMenuItems(isRecording);
} }
@@ -314,23 +333,11 @@ public class TrackListActivity extends FragmentActivity {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.menu_record_track: case R.id.menu_record_track:
updateMenuItems(true); updateMenuItems(true);
synchronized (trackRecordingServiceConnection) { startRecording();
startNewRecording = true;
trackRecordingServiceConnection.startAndBind();
/*
* If the binding has happened, then invoke the callback to start a
* new recording. If the binding hasn't happened, then invoking the
* callback will have no effect. But when the binding occurs, the
* callback will get invoked.
*/
bindChangedCallback.run();
}
return true; return true;
case R.id.menu_stop_recording: case R.id.menu_stop_recording:
updateMenuItems(false); updateMenuItems(false);
stopRecording(); stopRecording();
trackRecordingServiceConnection.stop();
return true; return true;
case R.id.menu_search: case R.id.menu_search:
return ApiAdapterFactory.getApiAdapter().handleSearchMenuSelection(this); return ApiAdapterFactory.getApiAdapter().handleSearchMenuSelection(this);
@@ -358,27 +365,28 @@ public class TrackListActivity extends FragmentActivity {
} }
} }
/**
* Returns true if recording.
*/
private boolean isRecording() {
return ServiceUtils.isRecording(
this, trackRecordingServiceConnection.getServiceIfBound(), sharedPreferences);
}
/** /**
* Starts a new recording. * Starts a new recording.
*/ */
private void startRecording() { private void startRecording() {
ITrackRecordingService service = trackRecordingServiceConnection.getServiceIfBound(); startNewRecording = true;
if (service != null) { trackRecordingServiceConnection.startAndBind();
try {
recordingTrackId = service.startNewTrack(); /*
startNewRecording = false; * If the binding has happened, then invoke the callback to start a new
adapter.notifyDataSetChanged(); * recording. If the binding hasn't happened, then invoking the callback
Toast.makeText(TrackListActivity.this, R.string.track_record_success, Toast.LENGTH_SHORT) * will have no effect. But when the binding occurs, the callback will get
.show(); * invoked.
Log.d(TAG, "Started a new recording"); */
} catch (Exception e) { bindChangedCallback.run();
Toast.makeText(TrackListActivity.this, R.string.track_record_error, Toast.LENGTH_LONG)
.show();
Log.d(TAG, "Unable to start a new recording.", e);
}
} else {
Log.d(TAG, "service not available to start a new recording");
}
} }
/** /**
@@ -396,17 +404,27 @@ public class TrackListActivity extends FragmentActivity {
startActivity(intent); startActivity(intent);
} }
recordingTrackId = -1L; recordingTrackId = -1L;
adapter.notifyDataSetChanged();
} catch (Exception e) { } catch (Exception e) {
Log.d(TAG, "Unable to stop recording.", e); Log.d(TAG, "Unable to stop recording.", e);
} }
} }
trackRecordingServiceConnection.stop();
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_SEARCH) {
if (ApiAdapterFactory.getApiAdapter().handleSearchKey(search)) {
return true;
}
}
return super.onKeyUp(keyCode, event);
} }
/** /**
* Check Units DialogFragment. * Check Units DialogFragment.
*/ */
private static class CheckUnitsDialogFragment extends DialogFragment { public static class CheckUnitsDialogFragment extends DialogFragment {
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
@@ -438,7 +456,7 @@ public class TrackListActivity extends FragmentActivity {
/** /**
* Delete All DialogFragment. * Delete All DialogFragment.
*/ */
private static class DeleteAllDialogFragment extends DialogFragment { public static class DeleteAllDialogFragment extends DialogFragment {
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
@@ -455,14 +473,13 @@ public class TrackListActivity extends FragmentActivity {
/** /**
* Eula DialogFragment. * Eula DialogFragment.
*/ */
private static class EulaDialogFragment extends DialogFragment { public static class EulaDialogFragment extends DialogFragment {
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity()) return new AlertDialog.Builder(getActivity())
.setCancelable(true) .setCancelable(true)
.setMessage( .setMessage(EulaUtils.getEulaMessage(getActivity()))
EulaUtils.getEulaMessage(getActivity()))
.setNegativeButton(R.string.eula_decline, new DialogInterface.OnClickListener() { .setNegativeButton(R.string.eula_decline, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
@@ -491,15 +508,14 @@ public class TrackListActivity extends FragmentActivity {
/** /**
* Export All DialogFragment. * Export All DialogFragment.
*/ */
private static class ExportAllDialogFragment extends DialogFragment { public static class ExportAllDialogFragment extends DialogFragment {
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
String exportFileFormat = getString(R.string.track_list_export_file);
String fileTypes[] = getResources().getStringArray(R.array.file_types); String fileTypes[] = getResources().getStringArray(R.array.file_types);
String[] choices = new String[fileTypes.length]; String[] choices = new String[fileTypes.length];
for (int i = 0; i < fileTypes.length; i++) { for (int i = 0; i < fileTypes.length; i++) {
choices[i] = String.format(exportFileFormat, fileTypes[i]); choices[i] = getString(R.string.menu_export_all_format, fileTypes[i]);
} }
return new AlertDialog.Builder(getActivity()).setNegativeButton(R.string.generic_cancel, null) return new AlertDialog.Builder(getActivity()).setNegativeButton(R.string.generic_cancel, null)
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() { .setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
@@ -516,15 +532,5 @@ public class TrackListActivity extends FragmentActivity {
.setTitle(R.string.menu_export_all) .setTitle(R.string.menu_export_all)
.create(); .create();
} }
};
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_SEARCH) {
if (ApiAdapterFactory.getApiAdapter().handleSearchKey(search)) {
return true;
}
}
return super.onKeyUp(keyCode, event);
} }
} }
@@ -16,7 +16,7 @@
package com.google.android.apps.mytracks.io.backup; package com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.TrackDetailActivity; import com.google.android.apps.mytracks.TrackListActivity;
import com.google.android.apps.mytracks.util.DialogUtils; import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
@@ -93,7 +93,7 @@ public class RestoreActivity extends Activity {
removeDialog(DIALOG_PROGRESS_ID); removeDialog(DIALOG_PROGRESS_ID);
Toast.makeText(this, messageId, success ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG).show(); Toast.makeText(this, messageId, success ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG).show();
startActivity( startActivity(
new Intent(this, TrackDetailActivity.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)); new Intent(this, TrackListActivity.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
finish(); finish();
} }
@@ -484,9 +484,10 @@ public class TrackRecordingService extends Service {
Notification notification = new Notification( Notification notification = new Notification(
R.drawable.arrow_320, null /* tickerText */, R.drawable.arrow_320, null /* tickerText */,
System.currentTimeMillis()); System.currentTimeMillis());
Intent intent = new Intent(this, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.TRACK_ID, recordingTrackId);
PendingIntent contentIntent = PendingIntent.getActivity( PendingIntent contentIntent = PendingIntent.getActivity(
this, 0 /* requestCode */, new Intent(this, TrackDetailActivity.class), this, 0 /* requestCode */, intent, 0 /* flags */);
0 /* flags */);
notification.setLatestEventInfo(this, getString(R.string.my_tracks_app_name), notification.setLatestEventInfo(this, getString(R.string.my_tracks_app_name),
getString(R.string.track_record_notification), contentIntent); getString(R.string.track_record_notification), contentIntent);
notification.flags += Notification.FLAG_NO_CLEAR; notification.flags += Notification.FLAG_NO_CLEAR;
@@ -93,7 +93,7 @@ public class PlayTrackUtils {
public static Dialog createInstallEarthDialog(final Context context) { public static Dialog createInstallEarthDialog(final Context context) {
return new AlertDialog.Builder(context) return new AlertDialog.Builder(context)
.setCancelable(true) .setCancelable(true)
.setMessage(R.string.track_list_play_install_earth_message) .setMessage(R.string.track_detail_install_earth_message)
.setNegativeButton(android.R.string.cancel, null) .setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override @Override
@@ -146,6 +146,9 @@ public class TrackWidgetProvider
// Make all of the stats open the mytracks activity. // Make all of the stats open the mytracks activity.
Intent intent = new Intent(context, TrackDetailActivity.class); Intent intent = new Intent(context, TrackDetailActivity.class);
if (track != null) {
intent.putExtra(TrackDetailActivity.TRACK_ID, track.getId());
}
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.appwidget_track_statistics, pendingIntent); views.setOnClickPendingIntent(R.id.appwidget_track_statistics, pendingIntent);
@@ -19,15 +19,12 @@ import com.google.android.apps.mytracks.services.ServiceUtils;
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection; import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.Instrumentation.ActivityMonitor;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.Editor;
import android.net.Uri; import android.net.Uri;
import android.test.ActivityInstrumentationTestCase2; import android.test.ActivityInstrumentationTestCase2;
import android.widget.Button;
import java.io.File; import java.io.File;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@@ -112,62 +109,6 @@ public class TrackDetailActivityTest extends ActivityInstrumentationTestCase2<Tr
// TODO: Finish this test. // TODO: Finish this test.
} }
public void testRecording_startAndStop() throws Exception {
assertInitialized();
// Check if not recording.
clearSelectedAndRecordingTracks();
waitForIdle();
assertFalse(isRecording());
assertEquals(-1, getRecordingTrackId());
// Start a new track.
getActivity().startRecording();
serviceConnection.bindIfRunning();
long recordingTrackId = awaitRecordingStatus(5000, true);
assertTrue(recordingTrackId >= 0);
// Wait until we are done and make sure that selectedTrack = recordingTrack.
waitForIdle();
assertEquals(recordingTrackId, getSharedPreferences().getLong(
getActivity().getString(R.string.recording_track_key), -1));
long selectedTrackId = getSharedPreferences().getLong(
getActivity().getString(R.string.selected_track_key), -1);
assertEquals(recordingTrackId, selectedTrackId);
// Watch for MyTracksDetails activity.
ActivityMonitor monitor = getInstrumentation().addMonitor(
TrackEditActivity.class.getName(), null, false);
// Now, stop the track and make sure that it is still selected, but
// no longer recording.
getActivity().stopRecording();
// Check if we got back MyTracksDetails activity.
Activity activity = getInstrumentation().waitForMonitor(monitor);
assertTrue(activity instanceof TrackEditActivity);
// TODO: Update track name and other properties and test if they were
// properly saved.
// Simulate a click on Save button.
final Button save = (Button) activity.findViewById(R.id.track_edit_save);
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
save.performClick();
}
});
// Check the remaining properties.
recordingTrackId = awaitRecordingStatus(5000, false);
assertEquals(-1, recordingTrackId);
assertEquals(recordingTrackId, getRecordingTrackId());
assertEquals(recordingTrackId, getSharedPreferences().getLong(
getActivity().getString(R.string.recording_track_key), -1));
}
private void assertInitialized() { private void assertInitialized() {
assertNotNull(getActivity()); assertNotNull(getActivity());