merge heads

This commit is contained in:
Jimmy Shih
2012-04-02 14:50:06 -07:00
parent 2d05ff98ca
commit 9575401127
15 changed files with 671 additions and 549 deletions
@@ -118,7 +118,7 @@ class MenuManager {
return true;
}
case R.id.menu_tracks: {
activity.startActivityForResult(new Intent(activity, TrackList.class),
activity.startActivityForResult(new Intent(activity, TrackListActivity.class),
Constants.SHOW_TRACK);
return true;
}
@@ -1,462 +0,0 @@
/*
* Copyright 2008 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;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.TracksColumns;
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.ServiceUtils;
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
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.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.View.OnCreateContextMenuListener;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
/**
* A list activity displaying all the recorded tracks. There's a context
* menu (via long press) displaying various options such as showing, editing,
* deleting, sending to Google, or writing to SD card.
*
* @author Leif Hendrik Wilden
*/
public class TrackList extends ListActivity
implements SharedPreferences.OnSharedPreferenceChangeListener,
View.OnClickListener {
private static final int DIALOG_INSTALL_EARTH_ID = 0;
private static final int DIALOG_EXPORT_ALL_ID = 1;
private static final int DIALOG_DELETE_ALL_ID = 2;
private static final int DIALOG_DELETE_CURRENT_ID = 3;
private int contextPosition = -1;
private long trackId = -1;
private ListView listView = null;
private boolean metricUnits = true;
private Cursor tracksCursor = null;
/**
* The id of the currently recording track.
*/
private long recordingTrackId = -1;
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);
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
contextPosition = info.position;
trackId = TrackList.this.listView.getAdapter().getItemId(contextPosition);
menu.add(Menu.NONE, Constants.MENU_SHOW, Menu.NONE, R.string.track_list_show_on_map);
menu.add(Menu.NONE, Constants.MENU_EDIT, Menu.NONE, R.string.track_list_edit_track);
if (!isRecording() || trackId != recordingTrackId) {
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_DELETE, Menu.NONE, R.string.track_list_delete_track);
}
}
};
private final Runnable serviceBindingChanged = new Runnable() {
@Override
public void run() {
updateButtonsEnabled();
}
};
private TrackRecordingServiceConnection serviceConnection;
private SharedPreferences preferences;
@Override
public void onSharedPreferenceChanged(
SharedPreferences sharedPreferences, String key) {
if (key == null) {
return;
}
if (key.equals(getString(R.string.metric_units_key))) {
metricUnits = sharedPreferences.getBoolean(
getString(R.string.metric_units_key), true);
if (tracksCursor != null && !tracksCursor.isClosed()) {
tracksCursor.requery();
}
}
if (key.equals(getString(R.string.recording_track_key))) {
recordingTrackId = sharedPreferences.getLong(
getString(R.string.recording_track_key), -1);
}
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Intent result = new Intent();
result.putExtra("trackid", id);
setResult(Constants.SHOW_TRACK, result);
finish();
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
Intent intent;
switch (item.getItemId()) {
case Constants.MENU_SHOW: {
onListItemClick(null, null, 0, trackId);
return true;
}
case Constants.MENU_EDIT: {
intent = new Intent(this, TrackDetail.class).putExtra(TrackDetail.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(TrackFileFormat.GPX, true);
return true;
case Constants.MENU_SHARE_KML_FILE:
startSaveActivity(TrackFileFormat.KML, true);
return true;
case Constants.MENU_SHARE_CSV_FILE:
startSaveActivity(TrackFileFormat.CSV, true);
return true;
case Constants.MENU_SHARE_TCX_FILE:
startSaveActivity(TrackFileFormat.TCX, true);
return true;
case Constants.MENU_SAVE_GPX_FILE:
startSaveActivity(TrackFileFormat.GPX, false);
return true;
case Constants.MENU_SAVE_KML_FILE:
startSaveActivity(TrackFileFormat.KML, false);
return true;
case Constants.MENU_SAVE_CSV_FILE:
startSaveActivity(TrackFileFormat.CSV, false);
return true;
case Constants.MENU_SAVE_TCX_FILE:
startSaveActivity(TrackFileFormat.TCX, false);
return true;
case Constants.MENU_DELETE:
showDialog(DIALOG_DELETE_CURRENT_ID);
return true;
default:
Log.w(TAG, "Unknown menu item: " + item.getItemId() + "(" + item.getTitle() + ")");
return super.onMenuItemSelected(featureId, item);
}
}
/**
* Starts the {@link SaveActivity} to save trackId.
*
* @param trackFileFormat the track file format
* @param shareTrack true to share the track after saving
*/
private void startSaveActivity(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);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.tracklist_btn_delete_all:
showDialog(DIALOG_DELETE_ALL_ID);
break;
case R.id.tracklist_btn_export_all:
showDialog(DIALOG_EXPORT_ALL_ID);
break;
case R.id.tracklist_btn_import_all:
Intent intent = new Intent(this, ImportActivity.class)
.putExtra(ImportActivity.EXTRA_IMPORT_ALL, true);
startActivity(intent);
break;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// We don't need a window title bar:
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.mytracks_list);
listView = getListView();
listView.setOnCreateContextMenuListener(contextMenuListener);
preferences = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
serviceConnection = new TrackRecordingServiceConnection(this, serviceBindingChanged);
View deleteAll = findViewById(R.id.tracklist_btn_delete_all);
deleteAll.setOnClickListener(this);
View exportAll = findViewById(R.id.tracklist_btn_export_all);
exportAll.setOnClickListener(this);
updateButtonsEnabled();
findViewById(R.id.tracklist_btn_import_all).setOnClickListener(this);
preferences.registerOnSharedPreferenceChangeListener(this);
metricUnits =
preferences.getBoolean(getString(R.string.metric_units_key), true);
recordingTrackId =
preferences.getLong(getString(R.string.recording_track_key), -1);
tracksCursor = getContentResolver().query(
TracksColumns.CONTENT_URI, null, null, null, "_id DESC");
startManagingCursor(tracksCursor);
setListAdapter();
}
@Override
protected void onStart() {
super.onStart();
serviceConnection.bindIfRunning();
}
@Override
protected void onDestroy() {
serviceConnection.unbind();
super.onDestroy();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search_only, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_search:
onSearchRequested();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DIALOG_INSTALL_EARTH_ID:
return PlayTrackUtils.createInstallEarthDialog(this);
case DIALOG_EXPORT_ALL_ID:
String exportFileFormat = getString(R.string.track_list_export_file);
String fileTypes[] = getResources().getStringArray(R.array.file_types);
String[] choices = new String[fileTypes.length];
for (int i = 0; i < fileTypes.length; i++) {
choices[i] = String.format(exportFileFormat, fileTypes[i]);
}
return new AlertDialog.Builder(this)
.setNegativeButton(R.string.generic_cancel, null)
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
int index = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
Intent intent = new Intent(TrackList.this, ExportActivity.class).putExtra(
ExportActivity.EXTRA_TRACK_FILE_FORMAT,
(Parcelable) TrackFileFormat.values()[index]);
TrackList.this.startActivity(intent);
}
})
.setSingleChoiceItems(choices, 0, null)
.setTitle(R.string.track_list_export_all)
.create();
case DIALOG_DELETE_ALL_ID:
return DialogUtils.createConfirmationDialog(this,
R.string.track_list_delete_all_confirm_message, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
MyTracksProviderUtils.Factory.get(TrackList.this).deleteAllTracks();
SharedPreferences sharedPreferences = getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
Editor editor = sharedPreferences.edit();
// TODO: Go through data manager
editor.putLong(getString(R.string.selected_track_key), -1L);
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
}
});
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) {
MyTracksProviderUtils.Factory.get(TrackList.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;
}
}
private void updateButtonsEnabled() {
View deleteAll = findViewById(R.id.tracklist_btn_delete_all);
View exportAll = findViewById(R.id.tracklist_btn_export_all);
boolean notRecording = !isRecording();
deleteAll.setEnabled(notRecording);
exportAll.setEnabled(notRecording);
}
private void setListAdapter() {
// Get a cursor with all tracks
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
this,
R.layout.mytracks_list_item,
tracksCursor,
new String[] { TracksColumns.NAME, TracksColumns.STARTTIME,
TracksColumns.TOTALDISTANCE, TracksColumns.DESCRIPTION,
TracksColumns.CATEGORY },
new int[] { R.id.track_list_item_name, R.id.track_list_item_time,
R.id.track_list_item_stats, R.id.track_list_item_description,
R.id.track_list_item_category });
final int startTimeIdx =
tracksCursor.getColumnIndexOrThrow(TracksColumns.STARTTIME);
final int totalTimeIdx =
tracksCursor.getColumnIndexOrThrow(TracksColumns.TOTALTIME);
final int totalDistanceIdx =
tracksCursor.getColumnIndexOrThrow(TracksColumns.TOTALDISTANCE);
adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
@Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
TextView textView = (TextView) view;
if (columnIndex == startTimeIdx) {
long time = cursor.getLong(startTimeIdx);
textView.setText(StringUtils.formatDateTime(TrackList.this, time));
} else if (columnIndex == totalDistanceIdx) {
double totalDistance = cursor.getDouble(totalDistanceIdx);
long totalTime = cursor.getLong(totalTimeIdx);
String totalDistanceStr = StringUtils.formatTimeDistance(
TrackList.this, totalTime, totalDistance, metricUnits);
textView.setText(totalDistanceStr);
} else {
textView.setText(cursor.getString(columnIndex));
if (textView.getText().length() < 1) {
textView.setVisibility(View.GONE);
} else {
textView.setVisibility(View.VISIBLE);
}
}
return true;
}
});
setListAdapter(adapter);
}
private boolean isRecording() {
return ServiceUtils.isRecording(TrackList.this, serviceConnection.getServiceIfBound(), preferences);
}
}
@@ -0,0 +1,395 @@
/*
* Copyright 2008 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;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.services.ServiceUtils;
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.ResourceCursorAdapter;
import android.widget.TextView;
import android.widget.Toast;
/**
* An activity displaying a list of tracks.
*
* @author Leif Hendrik Wilden
*/
public class TrackListActivity extends Activity {
private static final String TAG = TrackListActivity.class.getSimpleName();
private static final int DIALOG_EXPORT_ALL_ID = 0;
private static final int DIALOG_DELETE_ALL_ID = 1;
// Callback when the trackRecordingServiceConnection binding changes
private final Runnable bindChangedCallback = new Runnable() {
@Override
public void run() {
synchronized (trackRecordingServiceConnection) {
if (startNewRecording) {
startRecording();
} else {
updateMenu();
adapter.notifyDataSetChanged();
}
}
}
};
private TrackRecordingServiceConnection trackRecordingServiceConnection;
private SharedPreferences sharedPreferences;
private boolean metricUnits;
private long recordingTrackId;
private ListView listView;
private ResourceCursorAdapter adapter;
// True to start a new recording
private boolean startNewRecording = false;
private MenuItem recordTrack;
private MenuItem stopRecording;
private MenuItem search;
private MenuItem importAll;
private MenuItem exportAll;
private MenuItem deleteAll;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.track_list);
trackRecordingServiceConnection = new TrackRecordingServiceConnection(
this, bindChangedCallback);
sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
sharedPreferences.registerOnSharedPreferenceChangeListener(
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);
recordingTrackId = sharedPreferences.getLong(getString(R.string.recording_track_key), -1L);
MyTracksProviderUtils myTracksProviderUtils = MyTracksProviderUtils.Factory.get(this);
Cursor trackCursor = myTracksProviderUtils.getTracksCursor(
null, null, TracksColumns._ID + " DESC");
startManagingCursor(trackCursor);
listView = (ListView) findViewById(R.id.track_list);
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
setResult(Constants.SHOW_TRACK, new Intent().putExtra("trackid", id));
finish();
}
});
adapter = new ResourceCursorAdapter(this, R.layout.track_list_item, trackCursor, true) {
@Override
public void bindView(View view, Context context, Cursor cursor) {
int idIndex = cursor.getColumnIndex(TracksColumns._ID);
int nameIndex = cursor.getColumnIndex(TracksColumns.NAME);
int categoryIndex = cursor.getColumnIndex(TracksColumns.CATEGORY);
int timeIndex = cursor.getColumnIndexOrThrow(TracksColumns.TOTALTIME);
int distanceIndex = cursor.getColumnIndexOrThrow(TracksColumns.TOTALDISTANCE);
int startIndex = cursor.getColumnIndexOrThrow(TracksColumns.STARTTIME);
int descriptionIndex = cursor.getColumnIndex(TracksColumns.DESCRIPTION);
boolean isRecording = cursor.getLong(idIndex) == recordingTrackId;
TextView name = (TextView) view.findViewById(R.id.track_list_item_name);
name.setText(cursor.getString(nameIndex));
name.setCompoundDrawablesWithIntrinsicBounds(
isRecording ? R.drawable.menu_record_track : R.drawable.track, 0, 0, 0);
TextView category = (TextView) view.findViewById(R.id.track_list_item_category);
category.setText(cursor.getString(categoryIndex));
TextView time = (TextView) view.findViewById(R.id.track_list_item_time);
time.setText(StringUtils.formatElapsedTime(cursor.getLong(timeIndex)));
time.setVisibility(isRecording ? View.GONE : View.VISIBLE);
TextView distance = (TextView) view.findViewById(R.id.track_list_item_distance);
distance.setText(StringUtils.formatDistance(
TrackListActivity.this, cursor.getDouble(distanceIndex), metricUnits));
distance.setVisibility(isRecording ? View.GONE : View.VISIBLE);
TextView start = (TextView) view.findViewById(R.id.track_list_item_start);
start.setText(
StringUtils.formatDateTime(TrackListActivity.this, cursor.getLong(startIndex)));
start.setVisibility(start.getText().equals(name.getText()) ? View.GONE : View.VISIBLE);
TextView description = (TextView) view.findViewById(R.id.track_list_item_description);
description.setText(cursor.getString(descriptionIndex));
description.setVisibility(description.getText().length() == 0 ? View.GONE : View.VISIBLE);
}
};
listView.setAdapter(adapter);
}
@Override
protected void onStart() {
super.onStart();
trackRecordingServiceConnection.bindIfRunning();
}
@Override
protected void onDestroy() {
super.onDestroy();
trackRecordingServiceConnection.unbind();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.track_list, menu);
recordTrack = menu.findItem(R.id.menu_record_track);
stopRecording = menu.findItem(R.id.menu_stop_recording);
search = menu.findItem(R.id.menu_search);
importAll = menu.findItem(R.id.menu_import_all);
exportAll = menu.findItem(R.id.menu_export_all);
deleteAll = menu.findItem(R.id.menu_delete_all);
ApiAdapterFactory.getApiAdapter().configureSearchWidget(this, search);
updateMenu();
return true;
}
/**
* Updates the menu based on whether My Tracks is recording or not.
*/
private void updateMenu() {
boolean isRecording = ServiceUtils.isRecording(
this, trackRecordingServiceConnection.getServiceIfBound(), sharedPreferences);
updateMenuItems(isRecording);
}
/**
* Updates the menu items.
*
* @param isRecording true if recording
*/
private void updateMenuItems(boolean isRecording) {
if (recordTrack != null) {
recordTrack.setVisible(!isRecording);
}
if (stopRecording != null) {
stopRecording.setVisible(isRecording);
}
if (importAll != null) {
importAll.setVisible(!isRecording);
}
if (exportAll != null) {
exportAll.setVisible(!isRecording);
}
if (deleteAll != null) {
deleteAll.setVisible(!isRecording);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_record_track:
updateMenuItems(true);
synchronized (trackRecordingServiceConnection) {
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;
case R.id.menu_stop_recording:
updateMenuItems(false);
stopRecording();
trackRecordingServiceConnection.stop();
return true;
case R.id.menu_search:
return ApiAdapterFactory.getApiAdapter().handleSearchMenuSelection(this);
case R.id.menu_import_all:
startActivity(new Intent(this, ImportActivity.class)
.putExtra(ImportActivity.EXTRA_IMPORT_ALL, true));
return true;
case R.id.menu_export_all:
showDialog(DIALOG_EXPORT_ALL_ID);
return true;
case R.id.menu_delete_all:
showDialog(DIALOG_DELETE_ALL_ID);
return true;
case R.id.menu_aggregated_statistics:
startActivity(new Intent(this, AggregatedStatsActivity.class));
return true;
case R.id.menu_settings:
startActivity(new Intent(this, SettingsActivity.class));
return true;
case R.id.menu_help:
startActivity(new Intent(this, WelcomeActivity.class));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/**
* Starts a new recording.
*/
private void startRecording() {
ITrackRecordingService service = trackRecordingServiceConnection.getServiceIfBound();
if (service != null) {
try {
recordingTrackId = service.startNewTrack();
startNewRecording = false;
adapter.notifyDataSetChanged();
Toast.makeText(TrackListActivity.this, R.string.track_record_success, Toast.LENGTH_SHORT)
.show();
Log.d(TAG, "Started a new recording");
} catch (Exception e) {
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");
}
}
/**
* Stops the current recording.
*/
private void stopRecording() {
ITrackRecordingService service = trackRecordingServiceConnection.getServiceIfBound();
if (service != null) {
try {
service.endCurrentTrack();
if (recordingTrackId != -1L) {
Intent intent = new Intent(this, TrackDetail.class)
.putExtra(TrackDetail.SHOW_CANCEL, false)
.putExtra(TrackDetail.TRACK_ID, recordingTrackId);
startActivity(intent);
}
recordingTrackId = -1L;
adapter.notifyDataSetChanged();
} catch (Exception e) {
Log.d(TAG, "Unable to stop recording.", e);
}
}
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DIALOG_EXPORT_ALL_ID:
return createExportAllDialog();
case DIALOG_DELETE_ALL_ID:
return DialogUtils.createConfirmationDialog(this,
R.string.track_list_delete_all_confirm_message, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
MyTracksProviderUtils.Factory.get(TrackListActivity.this).deleteAllTracks();
/*
* TODO Verify that selected_track_key is still needed with the
* ICS navigation design
*/
Editor editor = sharedPreferences.edit();
// TODO: Go through data manager
editor.putLong(getString(R.string.selected_track_key), -1L);
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
}
});
default:
return null;
}
}
/**
* Creates an export all dialog.
*/
private AlertDialog createExportAllDialog() {
String exportFileFormat = getString(R.string.track_list_export_file);
String fileTypes[] = getResources().getStringArray(R.array.file_types);
String[] choices = new String[fileTypes.length];
for (int i = 0; i < fileTypes.length; i++) {
choices[i] = String.format(exportFileFormat, fileTypes[i]);
}
return new AlertDialog.Builder(this).setNegativeButton(R.string.generic_cancel, null)
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
int index = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
Intent intent = new Intent(TrackListActivity.this, ExportActivity.class).putExtra(
ExportActivity.EXTRA_TRACK_FILE_FORMAT,
(Parcelable) TrackFileFormat.values()[index]);
TrackListActivity.this.startActivity(intent);
}
})
.setSingleChoiceItems(choices, 0, null)
.setTitle(R.string.track_list_export_all)
.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,18 +16,37 @@
package com.google.android.apps.mytracks.util;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.SearchManager;
import android.content.Context;
import android.view.MenuItem;
import android.view.Window;
import android.widget.SearchView;
/**
* API level 11 specific implementation of the {@link ApiAdapter}.
*
* @author Jimmy Shih
*/
public class Api11Adapter extends Api9Adapter {
@TargetApi(11)
public class Api11Adapter extends Api10Adapter {
@Override
public void showActionBar(Activity activity) {
activity.requestWindowFeature(Window.FEATURE_ACTION_BAR);
}
@Override
public void configureSearchWidget(Activity activity, MenuItem menuItem) {
SearchManager searchManager = (SearchManager) activity.getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) menuItem.getActionView();
searchView.setSearchableInfo(searchManager.getSearchableInfo(activity.getComponentName()));
}
@Override
public boolean handleSearchMenuSelection(Activity activity) {
// Returns false to allow the platform to expand the search widget.
return false;
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.util;
import android.annotation.TargetApi;
import android.view.MenuItem;
/**
* API level 14 specific implementation of the {@link ApiAdapter}.
*
* @author Jimmy Shih
*/
@TargetApi(14)
public class Api14Adapter extends Api11Adapter {
@Override
public boolean handleSearchKey(MenuItem menuItem) {
menuItem.expandActionView();
return true;
}
}
@@ -30,6 +30,7 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.util.Log;
import android.view.MenuItem;
import android.view.Window;
import java.io.IOException;
@@ -108,4 +109,21 @@ public class Api7Adapter implements ApiAdapter {
// via the regular menu.
activity.requestWindowFeature(Window.FEATURE_NO_TITLE);
}
@Override
public void configureSearchWidget(Activity activity, MenuItem menuItem) {
// Do nothing
}
@Override
public boolean handleSearchMenuSelection(Activity activity) {
activity.onSearchRequested();
return true;
}
@Override
public boolean handleSearchKey(MenuItem menuItem) {
// Return false and allow the framework to handle the search key.
return false;
}
}
@@ -24,6 +24,7 @@ import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.SharedPreferences;
import android.view.MenuItem;
import java.io.IOException;
@@ -110,4 +111,31 @@ public interface ApiAdapter {
*/
public void showActionBar(Activity activity);
/**
* Configures the search widget.
*
* Due to changes in API level 11.
*
* @param activity the activity
* @param menuItem the search menu item
*/
public void configureSearchWidget(Activity activity, MenuItem menuItem);
/**
* Handles the search menu selection. Returns true if handled.
*
* Due to changes in API level 11.
*
* @param activity the activity
*/
public boolean handleSearchMenuSelection(Activity activity);
/**
* Handles the search key press. Returns true if handled.
*
* Due to changes in API level 14.
*
* @param menu the search menu
*/
public boolean handleSearchKey(MenuItem menu);
}
@@ -31,7 +31,10 @@ public class ApiAdapterFactory {
*/
public static ApiAdapter getApiAdapter() {
if (apiAdapter == null) {
if (Build.VERSION.SDK_INT >= 11) {
if (Build.VERSION.SDK_INT >= 14) {
apiAdapter = new Api14Adapter();
return apiAdapter;
} else if (Build.VERSION.SDK_INT >= 11) {
apiAdapter = new Api11Adapter();
return apiAdapter;
} else if (Build.VERSION.SDK_INT >= 10) {