/*
* Copyright (C) 2012 The Serval Project
*
* This file is part of the Serval Maps Software
*
* Serval Maps Software is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this source code; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.servalproject.maps;
import org.servalproject.maps.provider.PointsOfInterestContract;
import android.app.ListActivity;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.Toast;
/**
* an activity to display a list of points of interest
*/
public class PoiListActivity extends ListActivity implements OnItemClickListener {
/*
* private class level constants
*/
private final boolean V_LOG = false;
private final String TAG = "PoiListActivity";
private final String PREFERENCE_NAME = "preferences_poi_list_sort";
private final String DEFAULT_SORT_FIELD = PointsOfInterestContract.Table.TITLE;
/*
* private class level variables
*/
private long defaultPoiMaxAge = 43200 * 1000;
private volatile long poiMaxAge = defaultPoiMaxAge;
private Cursor cursor;
private PoiListAdapter dataAdapter;
private ListView listView;
private String[] columnNames;
/*
* create the activity
*
* (non-Javadoc)
* @see android.preference.PreferenceActivity#onCreate(android.os.Bundle)
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.poi_list);
// define the list of columns
columnNames = new String[5];
columnNames[0] = PointsOfInterestContract.Table.TITLE;
columnNames[1] = PointsOfInterestContract.Table.TIMESTAMP;
columnNames[2] = PointsOfInterestContract.Table.TIMEZONE;
columnNames[3] = PointsOfInterestContract.Table.LATITUDE;
columnNames[4] = PointsOfInterestContract.Table.LONGITUDE;
// get the desired maximum age of the poi information
SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
String mPreference = mPreferences.getString("preferences_map_max_poi_age", null);
if(mPreference != null) {
poiMaxAge = Long.parseLong(mPreference) * 1000;
}
// get the data
cursor = getCursor();
if(cursor == null) {
Log.e(TAG, "a null cursor was returned when looking up POI info");
Toast.makeText(getApplicationContext(), R.string.poi_list_ui_toast_missing_data, Toast.LENGTH_LONG).show();
finish();
}
dataAdapter = getDataAdapter(cursor);
setListAdapter(dataAdapter);
// get a reference to the list view
listView = getListView();
//mListView.setTextFilterEnabled(true); // allow filtering by the user by adding in content
listView.setOnItemClickListener(this);
}
/*
* get the data adapter
*/
private PoiListAdapter getDataAdapter(Cursor cursor) {
// define the map between columns and layout elements
// ensure that this is the same size as the list of columns
int[] mLayoutElements = new int[5];
mLayoutElements[0] = R.id.poi_list_ui_entry_title;
mLayoutElements[1] = R.id.poi_list_ui_entry_age;
mLayoutElements[2] = PoiListAdapter.PLACE_HOLDER;
mLayoutElements[3] = R.id.poi_list_ui_txt_distance;
mLayoutElements[4] = PoiListAdapter.PLACE_HOLDER;
return new PoiListAdapter(
this,
R.layout.poi_list_entry,
cursor,
columnNames,
mLayoutElements);
}
/*
* get the required data and populate the cursor using the default sort order
*/
private Cursor getCursor() {
return getCursor(getPreference());
}
/*
* get the required data and populate the cursor
*/
private Cursor getCursor(String sortField) {
// get the data
String[] mProjection = new String[columnNames.length + 1];
mProjection[0] = PointsOfInterestContract.Table._ID;
for(int i = 1; i < mProjection.length; i++) {
mProjection[i] = columnNames[i-1];
}
// determine if we need to restrict the list of POIs
String mSelection = null;
String[] mSelectionArgs = null;
// restrict the poi content returned if required
if(poiMaxAge != -1000) {
mSelection = PointsOfInterestContract.Table.TIMESTAMP + " > ? ";
mSelectionArgs = new String[1];
mSelectionArgs[0] = Long.toString(System.currentTimeMillis() - poiMaxAge);
}
// determine the order by
String mOrderBy = null;
if(sortField.equals(PointsOfInterestContract.Table.TITLE) == true) {
mOrderBy = sortField + " ASC";
} else {
mOrderBy = sortField + " DESC";
}
Log.d(TAG, "order by statement: " + mOrderBy);
// get a content resolver
ContentResolver mContentResolver = getApplicationContext().getContentResolver();
// get the data
return mContentResolver.query(
PointsOfInterestContract.CONTENT_URI,
mProjection,
mSelection,
mSelectionArgs,
mOrderBy);
}
/*
* create the menu
*
* (non-Javadoc)
* @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// inflate the menu based on the XML
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.poi_list_activity, menu);
return true;
}
/*
* handle click events from the menu
*
* (non-Javadoc)
* @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.menu_poi_list_activity_sort_alpha:
// sort list of items by title alphabetically
cursor.close();
cursor = null;
cursor = getCursor(PointsOfInterestContract.Table.TITLE);
updatePreference(PointsOfInterestContract.Table.TITLE);
dataAdapter = getDataAdapter(cursor);
listView.setAdapter(dataAdapter);
return true;
case R.id.menu_poi_list_activity_sort_time:
// sort list of items by time
Log.d(TAG, "sorting the dataAdapter by time");
cursor.close();
cursor = null;
cursor = getCursor(PointsOfInterestContract.Table.TIMESTAMP);
updatePreference(PointsOfInterestContract.Table.TIMESTAMP);
dataAdapter = getDataAdapter(cursor);
listView.setAdapter(dataAdapter);
return true;
case R.id.menu_poi_list_activity_close:
// close this activity
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/*
* private method to update a preference on the sort order
*/
private void updatePreference(String prefValue) {
SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
SharedPreferences.Editor mEditor = mPreferences.edit();
mEditor.putString(PREFERENCE_NAME, prefValue);
// TODO once on API 9 or above use apply not commit
mEditor.commit();
}
/*
* private method to get the preference on the sort order
*/
private String getPreference() {
SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
return mPreferences.getString(PREFERENCE_NAME, DEFAULT_SORT_FIELD);
}
/*
* (non-Javadoc)
* @see android.app.Activity#onPause()
*/
@Override
public void onPause() {
// play nice and close the cursor
cursor.close();
cursor = null;
super.onPause();
}
/*
* (non-Javadoc)
* @see android.app.Activity#onResume()
*/
@Override
public void onResume() {
// get the data
cursor = getCursor();
super.onResume();
}
/*
* (non-Javadoc)
* @see android.app.ListActivity#onDestroy()
*/
@Override
public void onDestroy() {
// play nice and close the cursor if necessary
if(cursor != null) {
cursor.close();
cursor = null;
}
super.onDestroy();
}
/*
* (non-Javadoc)
* @see android.widget.AdapterView.OnItemClickListener#onItemClick(android.widget.AdapterView, android.view.View, int, long)
*/
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(V_LOG) {
Log.v(TAG, "item clicked at position: " + position);
}
// work out the id of the item
if(cursor.moveToPosition(position) == true) {
if(V_LOG) {
Log.v(TAG, "item in cursor has id: " + cursor.getInt(cursor.getColumnIndex(PointsOfInterestContract.Table._ID)));
}
Intent mIntent = new Intent(this, org.servalproject.maps.PoiInfoActivity.class);
mIntent.putExtra("recordId", cursor.getInt(cursor.getColumnIndex(PointsOfInterestContract.Table._ID)));
startActivity(mIntent);
} else {
Log.e(TAG, "unable to match list item position to poi id");
Toast.makeText(getApplicationContext(), R.string.poi_list_ui_tiast_missing_poi_id, Toast.LENGTH_LONG).show();
finish();
}
}
}