From f466b65fc7167eed645a92dd29ef9769718bd666 Mon Sep 17 00:00:00 2001 From: Mudar Noufal Date: Tue, 22 Nov 2011 11:39:55 -0500 Subject: [PATCH] v0.9.2: about, preferences, UI language, units system, cleanup --- AndroidManifest.xml | 19 +++- README.md | 4 +- res/values-fr/strings.xml | 54 ++++++++---- res/values/colors.xml | 4 +- res/values/dimens.xml | 4 +- res/values/strings.xml | 54 ++++++++---- res/values/styles.xml | 16 ++-- res/values/themes.xml | 9 +- src/ca/mudar/mtlaucasou/BaseMapActivity.java | 7 +- src/ca/mudar/mtlaucasou/BaseMapFragment.java | 65 ++------------ src/ca/mudar/mtlaucasou/MainActivity.java | 85 +++++++++++++----- .../io/RemotePlacemarksHandler.java | 6 +- .../provider/PlacemarkDatabase.java | 6 +- .../mtlaucasou/ui/DashboardFragment.java | 8 +- .../ui/widgets/PlacemarksCursorAdapter.java | 58 ++----------- src/ca/mudar/mtlaucasou/utils/AppHelper.java | 75 +++++++++++++--- src/ca/mudar/mtlaucasou/utils/Const.java | 23 ++++- src/ca/mudar/mtlaucasou/utils/Helper.java | 86 ++++++++++++++++++- 18 files changed, 368 insertions(+), 215 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 8814847..c10c8cf 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,8 +1,9 @@ + android:versionCode="12" + android:versionName="@string/app_version" > + android:name=".ui.AboutActivity" + android:theme="@style/Theme.About" /> + diff --git a/README.md b/README.md index f075804..9b2b8fe 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Montréal Just in Case is an open source **Android** application that provides you with the geographic locations and addresses for four public safety services: - * Fire Halls; + * Fire Stations; * SPVM Stations; * Water Supplies; * Emergency Hostels. @@ -34,7 +34,7 @@ This project was done in collaboration with [Montréal Ouvert][link_mtl_ouvert]. Data sources are KML files provided by the City of Montréal: -1. [Fire Halls][link_portal_1] +1. [Fire Stations][link_portal_1] 2. [SPVM Stations][link_portal_2] 3. [Water Supplies][link_portal_3] 4. [Emergency Hostels][link_portal_4] diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 474b0d2..cc2d926 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -26,6 +26,7 @@ Hello World, Montréal au cas où! MTL au cas où + 0.9.2 Casernes de pompiers @@ -33,21 +34,25 @@ Points d\'eau Hébergements d\'urgence À propos + Réglages Casernes\nde pompiers Postes\nde la SPVM Points\nd\'eau Hébergements\nd\'urgence Liste Carte - Préférences + Réglages Aide À propos Ouvrir dans GMaps La liste est vide… - %.1f km - <100 m + %.1f km + < 100 m + %.1f mi + %s pi + < 200 pi @drawable/logo_open_data_fr - Erreur de syntaxe: %1$s + Erreur de syntaxe : %1$s gpl-3.0-standalone.html GNU General Public License v3.0 Ok @@ -60,19 +65,32 @@ Chargement terminé Ouvrir dans GMaps Voulez-vous télécharger le fichier KML ? Il sera affiché dans l\'application Google Maps… - À venir… Ceci est encore une version bêta !\nCette section vous permettra de :\n– trier les listes par nom ou par distance,\n– utiliser le français ou l\'anglais pour la langue de l\'interface,\n– afficher les distances avec le système métrique ou impérial,\n– mettre les données à jour à partir du site de la ville. - En cas d\'urgence, veuillez contacter le Service de la sécurité publique. Ne vous fiez pas aux informations présentées dans cette application car elle ne contiendra pas les dernirères mesures d\'urgence. - Montréal au cas où vous donne accès aux localisations géographiques et aux adresses civiques associées à quatre services de sécurité publique : - 1. casernes de pompiers, - 2. postes de quartier de la police (SPVM), - 3. points d\'eau - mesures d\'urgence : Localisation des points d\'eau mises à la disposition de la population en cas de canicule ou autre événement touchant la sécurité publique, - 4. centres d\'hébergement d\'urgence et lieux publics climatisés. - Les données sont en provenance du Portail données ouvertes de la Ville de Montréal. Appuyez pour accéder aux adresses URL : - Casernes de pompiers - Postes de la SPVM - Points d\'eau - Hébergements d\'urgence - La licence des données ouvertes - Application Android réalisée par Mudar Noufal. Le code source est publié sous la licence GPLv3 de la Free Software Foundation. + En cas d\'urgence, veuillez contacter le Service de la sécurité publique. Ne vous fiez pas aux informations présentées dans cette application car elle ne contiendra pas les dernirères mesures d\'urgence. + montrealaucasou.com + Version %s + Montréal au cas où vous donne accès aux localisations géographiques et aux adresses civiques associées à quatre services de sécurité publique : + casernes de pompiers, + postes de quartier de la police (SPVM), + points d\'eau mises à la disposition de la population en cas de canicule ou autre événement touchant la sécurité publique, + centres d\'hébergement d\'urgence et lieux publics climatisés. + Application Android réalisée par Mudar Noufal. Le code source est publié sous la licence GPLv3 de la Free Software Foundation. + Projet réalisé en collaboration avec Montréal ouvert. Cette application est propulsée par le Portail données ouvertes de la Ville de Montréal en conformité avec sa licence d\'utilisation des données ouvertes. + Réglages + Langue + Changer la langue de l\'interface + Choix de langue + Français + English + Unités de mesure + Afficher les distances en km ou en milles + Système des unités de mesure + Métrique (km) + Impérial (mile) + Ordre d\'affichage + Modifier l\'ordre d\'affichage des listes + Ordre alphabétique ou distance. À venir… + Trier par + Ordre alphabétique + Distance \ No newline at end of file diff --git a/res/values/colors.xml b/res/values/colors.xml index b799f98..62ee17e 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -46,12 +46,14 @@ - #cc9900 + #ffaa00 #404040 + #000000 #ff9900 #cc9900 #aa6600 #e5e5e5 + #606060 \ No newline at end of file diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 2e8861b..b32c5b0 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -27,8 +27,8 @@ 2dp 4dp 6dp - 2dp - 10dp + + 10dp 10dp 12sp diff --git a/res/values/strings.xml b/res/values/strings.xml index 450f42d..7fe1740 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -26,14 +26,16 @@ Hello World, Montréal Just in Case! MTL Just in Case + 0.9.2 - Fire Halls + Fire Stations SPVM Stations Water Supplies Emergency Hostels About - Fire Halls + Settings + Fire Stations SPVM Stations Water\nSupplies Emergency\nHostels @@ -44,8 +46,11 @@ About Open in GMaps List is empty… - %.1fkm - <100m + %.1f km + < 100 m + %.1f mi + %s ft + < 200 ft @drawable/logo_open_data_en Sync error: %1$s gpl-3.0-standalone.html @@ -60,19 +65,32 @@ Loading completed successfully! Open in GMaps Do you want to download the remote KML file? It will be opened using your Google Maps app… - Coming soon… This is still a beta version!\nSettings will allow you to:\n– Sort lists by Distance or Name;\n– Set interface language to English or French;\n– Display distances using Metric or Imperial units;\n– Update data using the city\'s remote server. - In case of emergency, please contact the City\'s security services directly. Do not rely on information provided here as it will not contain the updated security measures. - Montréal Just in Case provides you with the geographic locations and addresses for four public safety services: - 1. Fire Halls; - 2. Neighbourhood Police Stations (SPVM); - 3. Water Supplies – Contingency measures: Locations of water supplies available to the population in case of heat wave or other events related to public safety; - 4. Emergency accommodation centres and air conditioned public places. - The source of the data is the City of Montréal on its Open Data Portal. Tap to access the URL of each source: - Fire Halls - SPVM Stations - Water Supplies - Emergency Hostels - Licence related to the use and redistribution of the data - Android app developed by Mudar Noufal. Source code is released under the GPLv3 license from the Free Software Foundation. + In case of emergency, please contact the City\'s security services directly. Do not rely on information provided here as it will not contain the updated security measures. + montrealjustincase.com + Version %s + Montréal Just in Case provides you with the geographic locations and addresses of four public safety services: + Fire stations. + Neighbourhood police stations (SPVM). + Water supplies available to the population in case of heat wave or other events related to public safety. + Emergency accommodation centres and air conditioned public places. + Android app developed by Mudar Noufal. Source code is released under the GPLv3 license from the Free Software Foundation. + Project done in collaboration with Montréal ouvert. This app is powered by The City of Montréal Open Data Portal, in compliance with its Open Data license. + General Preferences + Language + Change the interface language + Set language + Français + English + Distance Units System + Calculate distances using km or mi + Set units system + Metric (km) + Imperial (mile) + Sort By + Sort lists by name or distance + By name or distance. Coming soon… + Sort lists by + Alphabetical order + Distance \ No newline at end of file diff --git a/res/values/styles.xml b/res/values/styles.xml index 4e7a929..34ac47b 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -58,17 +58,13 @@ @null - - - - - + + + \ No newline at end of file diff --git a/src/ca/mudar/mtlaucasou/BaseMapActivity.java b/src/ca/mudar/mtlaucasou/BaseMapActivity.java index 49ad091..f82357e 100644 --- a/src/ca/mudar/mtlaucasou/BaseMapActivity.java +++ b/src/ca/mudar/mtlaucasou/BaseMapActivity.java @@ -27,6 +27,7 @@ import ca.mudar.mtlaucasou.BaseListFragment.OnPlacemarkSelectedListener; import ca.mudar.mtlaucasou.utils.ActivityHelper; +import ca.mudar.mtlaucasou.utils.AppHelper; import ca.mudar.mtlaucasou.utils.ConnectionHelper; import ca.mudar.mtlaucasou.utils.Const; @@ -39,7 +40,6 @@ import android.support.v4.view.Menu; import android.support.v4.view.MenuInflater; import android.support.v4.view.MenuItem; -import android.util.Log; import android.view.View; public class BaseMapActivity extends FragmentMapActivity implements OnPlacemarkSelectedListener { @@ -66,6 +66,8 @@ public BaseMapActivity(int indexSection) { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + ((AppHelper) getApplicationContext()).updateUiLanguage(); /** * By default, show map and hide list. @@ -104,7 +106,7 @@ public void onResume() { Fragment fragmentMap = fm.findFragmentByTag(Const.TAG_FRAGMENT_MAP); Fragment fragmentList = fm.findFragmentByTag(Const.TAG_FRAGMENT_LIST); - // TODO Bug onResume after device (Nook!) shutdown or memory problems. + // TODO Bug: onResume after device (Nook!) shutdown or memory problems. // Temporary solution is the use of ft.show() in the following lines. /** * By default, both fragments are shown. No need to use @@ -158,7 +160,6 @@ protected boolean isRouteDisplayed() { @Override public boolean onCreateOptionsMenu(Menu menu) { - Log.v(TAG, "onCreateOptionsMenu"); /** * This is because of a ActionBarSherlock/compatibility package with the * MenuInflater. Also, versions earlier than Honeycomb understand only diff --git a/src/ca/mudar/mtlaucasou/BaseMapFragment.java b/src/ca/mudar/mtlaucasou/BaseMapFragment.java index cee0639..f586c86 100644 --- a/src/ca/mudar/mtlaucasou/BaseMapFragment.java +++ b/src/ca/mudar/mtlaucasou/BaseMapFragment.java @@ -46,7 +46,6 @@ import android.provider.BaseColumns; import android.support.v4.app.Fragment; import android.support.v4.view.MenuItem; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -97,14 +96,13 @@ public BaseMapFragment(int indexSection) { */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - Log.v(TAG, "onCreateView"); +// Log.v(TAG, "onCreateView"); /** * Restore map center and zoom */ int savedZoom = ZOOM_DEFAULT; if (savedInstanceState != null) { - Log.v(TAG, "has saved instance"); if (savedInstanceState.containsKey(Const.KEY_INSTANCE_COORDS)) { int[] coords = savedInstanceState.getIntArray(Const.KEY_INSTANCE_COORDS); mMapCenter = new GeoPoint(coords[0], coords[1]); @@ -135,44 +133,13 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa return root; } - // @Override - // public void onActivityCreated(Bundle savedInstanceState) { - // super.onActivityCreated(savedInstanceState); - // - // // This is a tablet if this view exists - // View root = getSupportActivity().findViewById(R.id.map_root_landscape); - // mIsTablet = (root != null); - // - // boolean isVisible = true; - // if (savedInstanceState != null) { - // if (savedInstanceState.containsKey(Const.KEY_INSTANCE_IS_VISIBLE_MAP)) { - // isVisible = - // savedInstanceState.getBoolean(Const.KEY_INSTANCE_IS_VISIBLE_MAP); - // } - // // mCurrentSelectedItemIndex = - // // savedInstanceState.getInt("currentListIndex", -1); - // } - // FragmentManager fm = getSupportFragmentManager(); - // FragmentTransaction ft = fm.beginTransaction(); - // if (isVisible || mIsTablet) { - // ft.show(this); - // } - // else { - // ft.hide(this); - // } - // ft.commit(); - // } - /** * Initialize Map: centre and load placemarks */ protected void initMap() { - Log.v(TAG, "initMap"); - mLocationOverlay = new MyLocationOverlay(getActivity().getApplicationContext(), mMapView); mLocationOverlay.enableCompass(); mLocationOverlay.enableMyLocation(); - // mMapView.getOverlays().add(mLocationOverlay); mMapView.getOverlays().add(INDEX_OVERLAY_MY_LOCATION, mLocationOverlay); ArrayList arMapMarker = fetchMapMarkers(); @@ -184,7 +151,7 @@ protected void initMap() { mMapView); if (arMapMarker.size() > 0) { - Log.v(TAG, "Adding markers to map"); +// Log.v(TAG, "Adding markers to map"); for (MapMarker marker : arMapMarker) { OverlayItem overlayitem = new OverlayItem(marker.geoPoint, marker.name, marker.address); @@ -215,8 +182,6 @@ protected void animateToPoint(GeoPoint mapCenter) { */ protected void initialAnimateToPoint() { - Log.v(TAG, "initialAnimateToPoint"); - List enabledProviders = mLocationManager.getProviders(true); String coordinates[] = Const.MAPS_DEFAULT_COORDINATES; @@ -287,7 +252,7 @@ protected ArrayList fetchMapMarkers() { MAP_MARKER_PROJECTION, null, null, null); // TODO: verify cursor close vs manage - getActivity().startManagingCursor(cur); +// getActivity().startManagingCursor(cur); if (cur.moveToFirst()) { final int columnId = cur.getColumnIndex(BaseColumns._ID); @@ -304,6 +269,7 @@ protected ArrayList fetchMapMarkers() { } while (cur.moveToNext()); } + cur.close(); return alLocations; } @@ -321,26 +287,9 @@ public boolean onOptionsItemSelected(MenuItem item) { */ @Override public void onResume() { - Log.v(TAG, "onResume"); +// Log.v(TAG, "onResume"); mLocationOverlay.enableMyLocation(); - // if (((BaseMapActivity) getSupportActivity()).isListVisiblePortrait()) - // { - // Log.v(TAG, "isListVisiblePortrait"); - // FragmentManager fm = getSupportFragmentManager(); - // FragmentTransaction ft = fm.beginTransaction(); - // ft.hide(this); - // ft.commit(); - // } - - // if (mMapCenter == null) { - // mMapController.setZoom(ZOOM_DEFAULT); - // } - // else { - // mMapController.setZoom(ZOOM_NEAR); - // mMapController.setCenter(mMapCenter); - // } - super.onResume(); } @@ -388,7 +337,7 @@ public void onSaveInstanceState(Bundle outState) { @Override public void onLocationChanged(Location location) { // TODO Auto-generated method stub - Log.e(TAG, "onLocationChanged"); +// Log.e(TAG, "onLocationChanged"); mAppHelper.setLocation(location); } @@ -443,7 +392,7 @@ public GeoPoint getMapCenter() { * @param mapCenter The new location */ public void setMapCenter(GeoPoint mapCenter) { - Log.v(TAG, "Geo = " + mapCenter.getLatitudeE6() + "," + mapCenter.getLongitudeE6()); +// Log.v(TAG, "Geo = " + mapCenter.getLatitudeE6() + "," + mapCenter.getLongitudeE6()); animateToPoint(mapCenter); Overlay overlayPlacemarks = mMapView.getOverlays().get(INDEX_OVERLAY_PLACEMARKS); diff --git a/src/ca/mudar/mtlaucasou/MainActivity.java b/src/ca/mudar/mtlaucasou/MainActivity.java index b1a3ee4..4fb37b1 100644 --- a/src/ca/mudar/mtlaucasou/MainActivity.java +++ b/src/ca/mudar/mtlaucasou/MainActivity.java @@ -23,8 +23,10 @@ package ca.mudar.mtlaucasou; +import ca.mudar.mtlaucasou.provider.PlacemarkDatabase; import ca.mudar.mtlaucasou.service.SyncService; import ca.mudar.mtlaucasou.utils.ActivityHelper; +import ca.mudar.mtlaucasou.utils.AppHelper; import ca.mudar.mtlaucasou.utils.Const; import ca.mudar.mtlaucasou.utils.DetachableResultReceiver; import ca.mudar.mtlaucasou.utils.EulaHelper; @@ -42,38 +44,63 @@ import android.support.v4.view.MenuInflater; import android.support.v4.view.MenuItem; import android.support.v4.view.Window; -import android.util.Log; +//import android.util.Log; +import android.view.View; +import android.widget.Button; import android.widget.Toast; public class MainActivity extends FragmentActivity { private static final String TAG = "MainActivity"; private ActivityHelper mActivityHelper; + private AppHelper mAppHelper; private SyncStatusUpdaterFragment mSyncStatusUpdaterFragment; private boolean hasLoadedData; + private String lang; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); - SharedPreferences prefs = getSharedPreferences(Const.APP_PREFS_NAME, Context.MODE_PRIVATE); + /** + * SharedPreferences are used to verify determine if syncService is + * required for initial launch or on database upgrade. + */ + SharedPreferences prefs = getSharedPreferences(Const.APP_PREFS_NAME, + Context.MODE_PRIVATE); hasLoadedData = prefs.getBoolean(Const.PrefsNames.HAS_LOADED_DATA, false); - if (!hasLoadedData) { - Log.v(TAG, "hasLoadedData = false"); + int dbVersionPrefs = prefs.getInt(Const.PrefsNames.VERSION_DATABASE, -1); + + if (!hasLoadedData || PlacemarkDatabase.getDatabaseVersion() > dbVersionPrefs) { + hasLoadedData = false; createServiceFragment(); } - // TODO Add Eula content + /** + * Display the GPLv3 licence + */ if (!EulaHelper.hasAcceptedEula(this)) { EulaHelper.showEula(false, this); } + /** + * Get the ActivityHelper + */ mActivityHelper = ActivityHelper.createInstance(this); + mAppHelper = (AppHelper) getApplicationContext(); + + lang = mAppHelper.getLanguage(); + mAppHelper.updateUiLanguage(); setContentView(R.layout.activity_home); + setProgressBarIndeterminateVisibility(Boolean.FALSE); + /** + * Android ICS has support for setHomeButtonEnabled() to disable tap on + * actionbar logo on dashboard. + */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { getActionBar().setHomeButtonEnabled(false); } @@ -82,7 +109,15 @@ public void onCreate(Bundle savedInstanceState) { @Override public void onResume() { super.onResume(); - Log.v(TAG, "onResume"); + + /** + * Update the interface language + */ + getSupportActionBar().setTitle(R.string.app_name); + if (!lang.equals(mAppHelper.getLanguage())) { + lang = mAppHelper.getLanguage(); + this.onConfigurationChanged(); + } /** * Starting the sync service is done onResume() for @@ -90,7 +125,6 @@ public void onResume() { * receiver to the service. */ if (!hasLoadedData && (mSyncStatusUpdaterFragment != null)) { - Log.v(TAG, "mSyncStatusUpdaterFragment != null"); Intent intent = new Intent(Intent.ACTION_SYNC, null, getApplicationContext(), SyncService.class); intent.putExtra(SyncService.EXTRA_STATUS_RECEIVER, mSyncStatusUpdaterFragment.mReceiver); @@ -102,14 +136,13 @@ public void onResume() { SharedPreferences.Editor editor = prefs.edit(); editor.putBoolean(Const.PrefsNames.HAS_LOADED_DATA, true); + editor.putInt(Const.PrefsNames.VERSION_DATABASE, PlacemarkDatabase.getDatabaseVersion()); editor.commit(); hasLoadedData = true; } } private void createServiceFragment() { - Log.v(TAG, "createServiceFragment"); - FragmentManager fm = getSupportFragmentManager(); mSyncStatusUpdaterFragment = (SyncStatusUpdaterFragment) fm @@ -157,6 +190,26 @@ public boolean onOptionsItemSelected(MenuItem item) { return mActivityHelper.onOptionsItemSelected(item); } + /** + * Update the interface language, independently from the phone's UI + * language. This does not override the parent function because the Manifest + * does not include configChanges. + */ + private void onConfigurationChanged() { + View root = findViewById(android.R.id.content).getRootView(); + + ((Button) root.findViewById(R.id.home_btn_fire_halls)) + .setText(R.string.btn_fire_halls); + ((Button) root.findViewById(R.id.home_btn_spvm_stations)) + .setText(R.string.btn_spvm_stations); + ((Button) root.findViewById(R.id.home_btn_water_supplies)) + .setText(R.string.btn_water_supplies); + ((Button) root.findViewById(R.id.home_btn_emergency_hostels)) + .setText(R.string.btn_emergency_hostels); + + invalidateOptionsMenu(); + } + // @Override // public void onAttachedToWindow() { // // TODO: verify if this does any difference since it uses @@ -179,20 +232,14 @@ public static class SyncStatusUpdaterFragment extends Fragment implements @Override public void onCreate(Bundle savedInstanceState) { - Log.v(TAG, "onCreate"); super.onCreate(savedInstanceState); setRetainInstance(true); mReceiver = new DetachableResultReceiver(new Handler()); - if (mReceiver == null) { - Log.v(TAG, "mReceiver == null "); - } - Log.v(TAG, "setReceiver"); mReceiver.setReceiver(this); } /** {@inheritDoc} */ public void onReceiveResult(int resultCode, Bundle resultData) { - Log.v(TAG, "onReceiveResult"); MainActivity activity = (MainActivity) getSupportActivity(); if (activity == null) { return; @@ -201,13 +248,13 @@ public void onReceiveResult(int resultCode, Bundle resultData) { switch (resultCode) { case SyncService.STATUS_RUNNING: { - Log.v(TAG, "SyncService.STATUS_RUNNING"); + // Log.v(TAG, "SyncService.STATUS_RUNNING"); activity.setProgressBarIndeterminateVisibility(Boolean.TRUE); // mSyncing = true; break; } case SyncService.STATUS_FINISHED: { - Log.v(TAG, "SyncService.STATUS_FINISHED"); + // Log.v(TAG, "SyncService.STATUS_FINISHED"); activity.setProgressBarIndeterminateVisibility(Boolean.FALSE); // mSyncing = false; // TODO put this in an activity listener @@ -220,7 +267,7 @@ public void onReceiveResult(int resultCode, Bundle resultData) { break; } case SyncService.STATUS_ERROR: { - Log.v(TAG, "SyncService.STATUS_ERROR"); + // Log.v(TAG, "SyncService.STATUS_ERROR"); activity.setProgressBarIndeterminateVisibility(Boolean.FALSE); /** * Error happened down in SyncService, show as toast. @@ -232,8 +279,6 @@ public void onReceiveResult(int resultCode, Bundle resultData) { break; } } - - // activity.updateRefreshStatus(mSyncing); } // @Override diff --git a/src/ca/mudar/mtlaucasou/io/RemotePlacemarksHandler.java b/src/ca/mudar/mtlaucasou/io/RemotePlacemarksHandler.java index 9e99a9d..977b646 100644 --- a/src/ca/mudar/mtlaucasou/io/RemotePlacemarksHandler.java +++ b/src/ca/mudar/mtlaucasou/io/RemotePlacemarksHandler.java @@ -34,8 +34,6 @@ import android.content.ContentProviderOperation; import android.content.ContentResolver; import android.net.Uri; -import android.util.Log; -//import android.util.Log; import java.io.IOException; import java.text.DecimalFormat; @@ -122,9 +120,9 @@ public ArrayList parse(XmlPullParser parser, ContentRe builder.withValue(FireHalls.PLACEMARK_ADDRESS, locationInfo.get(RemoteTags.ADDRESS)); builder.withValue(FireHalls.PLACEMARK_GEO_LAT, - Double.parseDouble(coords[0])); - builder.withValue(FireHalls.PLACEMARK_GEO_LNG, Double.parseDouble(coords[1])); + builder.withValue(FireHalls.PLACEMARK_GEO_LNG, + Double.parseDouble(coords[0])); batch.add(builder.build()); } diff --git a/src/ca/mudar/mtlaucasou/provider/PlacemarkDatabase.java b/src/ca/mudar/mtlaucasou/provider/PlacemarkDatabase.java index e65f36c..61f6c12 100644 --- a/src/ca/mudar/mtlaucasou/provider/PlacemarkDatabase.java +++ b/src/ca/mudar/mtlaucasou/provider/PlacemarkDatabase.java @@ -45,11 +45,15 @@ interface Tables { String EMERGENCY_HOSTELS = "emergency_hostels"; } - public PlacemarkDatabase(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + public static int getDatabaseVersion() { + return DATABASE_VERSION; + } + @Override public void onCreate(SQLiteDatabase db) { Log.v(TAG, "Creating database tables. DB name: " + DATABASE_NAME); diff --git a/src/ca/mudar/mtlaucasou/ui/DashboardFragment.java b/src/ca/mudar/mtlaucasou/ui/DashboardFragment.java index ae27e0f..501e552 100644 --- a/src/ca/mudar/mtlaucasou/ui/DashboardFragment.java +++ b/src/ca/mudar/mtlaucasou/ui/DashboardFragment.java @@ -40,7 +40,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa root.findViewById(R.id.home_btn_fire_halls).setOnClickListener( new View.OnClickListener() { public void onClick(View view) { - Intent intent = new Intent(getActivity().getApplicationContext(), + Intent intent = new Intent(getSupportActivity().getApplicationContext(), FireHallsMapActivity.class); startActivity(intent); } @@ -48,7 +48,7 @@ public void onClick(View view) { root.findViewById(R.id.home_btn_spvm_stations).setOnClickListener( new View.OnClickListener() { public void onClick(View view) { - Intent intent = new Intent(getActivity().getApplicationContext(), + Intent intent = new Intent(getSupportActivity().getApplicationContext(), SpvmStationsMapActivity.class); startActivity(intent); } @@ -56,7 +56,7 @@ public void onClick(View view) { root.findViewById(R.id.home_btn_water_supplies).setOnClickListener( new View.OnClickListener() { public void onClick(View view) { - Intent intent = new Intent(getActivity().getApplicationContext(), + Intent intent = new Intent(getSupportActivity().getApplicationContext(), WaterSuppliesMapActivity.class); startActivity(intent); } @@ -64,7 +64,7 @@ public void onClick(View view) { root.findViewById(R.id.home_btn_emergency_hostels).setOnClickListener( new View.OnClickListener() { public void onClick(View view) { - Intent intent = new Intent(getActivity().getApplicationContext(), + Intent intent = new Intent(getSupportActivity().getApplicationContext(), EmergencyHostelsMapActivity.class); startActivity(intent); } diff --git a/src/ca/mudar/mtlaucasou/ui/widgets/PlacemarksCursorAdapter.java b/src/ca/mudar/mtlaucasou/ui/widgets/PlacemarksCursorAdapter.java index a539185..c09d3f6 100644 --- a/src/ca/mudar/mtlaucasou/ui/widgets/PlacemarksCursorAdapter.java +++ b/src/ca/mudar/mtlaucasou/ui/widgets/PlacemarksCursorAdapter.java @@ -24,20 +24,20 @@ package ca.mudar.mtlaucasou.ui.widgets; import ca.mudar.mtlaucasou.provider.PlacemarkContract.PlacemarkColumns; +import ca.mudar.mtlaucasou.utils.Helper; import ca.mudar.mtlaucasou.R; + import android.content.Context; -import android.content.res.Resources; import android.database.Cursor; import android.location.Location; -import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.SimpleCursorAdapter; import android.widget.TextView; public class PlacemarksCursorAdapter extends SimpleCursorAdapter { - protected static final String TAG = "HistorySimpleCursorAdapter"; + protected static final String TAG = "PlacemarksCursorAdapter"; private Location mLocation; @@ -56,12 +56,14 @@ public View newView(Context context, Cursor cursor, ViewGroup parent) { public void bindView(View view, Context context, Cursor cursor) { super.bindView(view, context, cursor); - // Can't calculate the distance if we don't know the current location + /** + * Can't calculate the distance if we don't know the current location + */ if (mLocation == null) { return; } - Resources res = context.getResources(); + // Resources res = context.getResources(); TextView vDistance = (TextView) view.findViewById(R.id.placemark_distance); Double geoLat = cursor.getDouble(cursor.getColumnIndex(PlacemarkColumns.PLACEMARK_GEO_LAT)); @@ -72,54 +74,12 @@ public void bindView(View view, Context context, Cursor cursor) { (mLocation.getLatitude()), (mLocation.getLongitude()), results); - float fDistance = (results[0] / 1000); + float fDistance = (results[0]); // Log.v(TAG, "geoLat = "+ geoLat + "geoLng = "+ geoLng ); - // - String sDistance; - if (fDistance <= 1) { - sDistance = res.getString(R.string.placemark_distance_min); - } - else { - sDistance = String.format(res.getString(R.string.placemark_distance), fDistance); - } + String sDistance = Helper.getDistanceDisplay(context, fDistance); - // res.getString(R.string.placemark_distance); vDistance.setText(sDistance); - - // int transcationType = - // cursor.getInt(cursor.getColumnIndex(Transactions.TRANSACTION_SBM_TRANSACTION_TYPE)); - // double amount = - // cursor.getDouble(cursor.getColumnIndex(Transactions.TRANSACTION_AMOUNT)); - // String comment = - // cursor.getString(cursor.getColumnIndex(Transactions.TRANSACTION_COMMENT)); - // - // String sType; - // String sAmount; - // if (type == Const.API_TRANSACTION_TYPE_CREDIT) { - // sAmount = - // String.format(res.getString(R.string.transaction_type_amount_credit), - // amount); - // sType = res.getString(R.string.transaction_type_credit); - // comment = sType + ". " + comment; - // } else if (transcationType == - // Const.ApiTransactionType.GIFTCARD_PAYMENT) { - // sAmount = res.getString(R.string.transaction_type_gift); - // } else { - // sAmount = - // String.format(res.getString(R.string.transaction_type_amount_debit), - // amount); - // sType = res.getString(R.string.transaction_type_debit); - // } - // - // if (vAmount != null) { - // vAmount.setText(sAmount); - // } - // - // if (vComment != null && type == Const.API_TRANSACTION_TYPE_CREDIT) { - // vComment.setText("abc def"); - // } - } public void setLocation(Location mLocation) { diff --git a/src/ca/mudar/mtlaucasou/utils/AppHelper.java b/src/ca/mudar/mtlaucasou/utils/AppHelper.java index 08c83fc..8139099 100644 --- a/src/ca/mudar/mtlaucasou/utils/AppHelper.java +++ b/src/ca/mudar/mtlaucasou/utils/AppHelper.java @@ -23,11 +23,14 @@ package ca.mudar.mtlaucasou.utils; +import ca.mudar.mtlaucasou.utils.Const.PrefsNames; +import ca.mudar.mtlaucasou.utils.Const.PrefsValues; + import android.app.Application; import android.content.Context; import android.content.SharedPreferences; +import android.content.res.Configuration; import android.location.Location; -import android.util.Log; import android.widget.Toast; import java.util.Locale; @@ -39,6 +42,8 @@ public class AppHelper extends Application { protected static final String TAG = "AppHelper"; private Location mLocation; + private String mUnits; + private String mListSort; private String mLanguage; private Toast mToast; @@ -47,9 +52,8 @@ public Location getLocation() { } public void setLocation(Location location) { - Log.v(TAG, - "setLocation. Lat = " + location.getLatitude() + ". Lng = " - + location.getLongitude()); + // Log.v(TAG,"setLocation. Lat = " + location.getLatitude() + + // ". Lng = "+ location.getLongitude()); this.mLocation = location; } @@ -58,8 +62,19 @@ public String getLanguage() { } public void setLanguage(String lang) { - Log.v(TAG, "setLanguage = " + lang); this.mLanguage = lang; + updateUiLanguage(); + } + + public void updateUiLanguage() { + + Locale locale = new Locale(mLanguage); + + Configuration config = new Configuration(); + config.locale = locale; + Locale.setDefault(locale); + getBaseContext().getResources().updateConfiguration(config, + getBaseContext().getResources().getDisplayMetrics()); } public void showToastText(int res, int duration) { @@ -74,6 +89,47 @@ public void showToastText(String msg, int duration) { mToast.show(); } + @Override + public void onCreate() { + super.onCreate(); + instance = this; + + SharedPreferences prefs = getSharedPreferences(Const.APP_PREFS_NAME, Context.MODE_PRIVATE); + + /** + * Initialize UI settings based on preferences. + */ + mUnits = prefs.getString(PrefsNames.UNITS_SYSTEM, PrefsValues.UNITS_ISO); + + mListSort = prefs.getString(PrefsNames.LIST_SORT, PrefsValues.LIST_SORT_NAME); + + mLanguage = prefs.getString(Const.PrefsNames.LANGUAGE, Locale.getDefault().getLanguage()); + if (!mLanguage.equals(PrefsValues.LANG_EN) && !mLanguage.equals(PrefsValues.LANG_FR)) { + mLanguage = PrefsValues.LANG_EN; + } + + mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT); + + updateUiLanguage(); + } + + public String getListSort() { + return mListSort; + } + + public void setListSort(String sort) { +// Log.v(TAG, "setListSort = " + sort); + this.mListSort = sort; + } + + public String getUnits() { + return mUnits; + } + + public void setUnits(String units) { + this.mUnits = units; + } + // TODO: verify possible memory leakage of the following code private static AppHelper instance = null; @@ -87,13 +143,4 @@ private static void checkInstance() { throw new IllegalStateException("Application not created yet!"); } - @Override - public void onCreate() { - super.onCreate(); - instance = this; - - SharedPreferences prefs = getSharedPreferences(Const.APP_PREFS_NAME, Context.MODE_PRIVATE); - mLanguage = prefs.getString(Const.PrefsNames.LANGUAGE, Locale.getDefault().getLanguage()); - mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT); - } } diff --git a/src/ca/mudar/mtlaucasou/utils/Const.java b/src/ca/mudar/mtlaucasou/utils/Const.java index 4c1e6c0..54b73ee 100644 --- a/src/ca/mudar/mtlaucasou/utils/Const.java +++ b/src/ca/mudar/mtlaucasou/utils/Const.java @@ -29,15 +29,34 @@ public class Const { public static interface PrefsNames { final String HAS_LOADED_DATA = "prefs_has_loaded_data"; - final String LANGUAGE = "prefs_lang"; + final String VERSION_DATABASE = "prefs_version_database"; + final String LANGUAGE = "prefs_language"; final String UNITS_SYSTEM = "prefs_units_system"; - final String SORT_ORDER = "prefs_sort_order"; + final String LIST_SORT = "prefs_list_sort"; + } + + public static interface PrefsValues { + final String LANG_FR = "fr"; + final String LANG_EN = "en"; + final String UNITS_ISO = "iso"; + final String UNITS_IMP = "imp"; + final String LIST_SORT_NAME = "name"; + final String LIST_SORT_DISTANCE = "distance"; } public static final String MAPS_DEFAULT_COORDINATES[] = { "45.5", "-73.666667" }; public static final int MAPS_MIN_DISTANCE = 25; // Distance in KM + + public static interface UnitsDisplay { + final float FEET_PER_MILE = 5280; + final float METER_PER_MILE = 1609.344f; + final int ACCURACY_FEET_FAR = 100; + final int ACCURACY_FEET_NEAR = 10; + final int MIN_FEET = 200; + final int MIN_METERS = 100; + } // public static final String INTENT_EXTRA_NAME_SECTION = "section"; public static final String INTENT_EXTRA_GEO_LAT = "geo_lat"; diff --git a/src/ca/mudar/mtlaucasou/utils/Helper.java b/src/ca/mudar/mtlaucasou/utils/Helper.java index 1b89165..d6af5bc 100644 --- a/src/ca/mudar/mtlaucasou/utils/Helper.java +++ b/src/ca/mudar/mtlaucasou/utils/Helper.java @@ -23,6 +23,12 @@ package ca.mudar.mtlaucasou.utils; +import ca.mudar.mtlaucasou.R; +import ca.mudar.mtlaucasou.utils.Const.UnitsDisplay; + +import android.content.Context; +import android.content.res.Resources; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -48,4 +54,82 @@ public static String inputStreamToString(InputStream inputStream) { return resultString; } -} \ No newline at end of file + public static String getDistanceDisplay(Context c, float fDistanceM) { + String sDistance; + + AppHelper appHelper = (AppHelper) c.getApplicationContext(); + Resources res = c.getResources(); + String units = appHelper.getUnits(); + + if (units.equals(Const.PrefsValues.UNITS_IMP)) { + /** + * Imperial units system, Miles and Feet. + */ + + float fDistanceMi = fDistanceM / UnitsDisplay.METER_PER_MILE; + + if (fDistanceMi + (UnitsDisplay.ACCURACY_FEET_FAR / UnitsDisplay.FEET_PER_MILE) < 1) { + /** + * Display distance in Feet if less than one mile. + */ + int iDistanceFt = Math.round(fDistanceMi * UnitsDisplay.FEET_PER_MILE); + + if (iDistanceFt <= UnitsDisplay.MIN_FEET) { + /** + * Display "Less than 200 ft", which is +/- equal to the GPS + * accuracy. + */ + sDistance = res.getString(R.string.placemark_distance_imp_min); + } + else { + /** + * When displaying in feet, we round up by 100 ft for + * distances greater than 1000 ft and by 100 ft for smaller + * distances. Example: 1243 ft becomes 1200 and 943 ft + * becomes 940 ft. + */ + if (iDistanceFt > 1000) { + iDistanceFt = Math.round(iDistanceFt / UnitsDisplay.ACCURACY_FEET_FAR) + * UnitsDisplay.ACCURACY_FEET_FAR; + } + else { + iDistanceFt = Math.round(iDistanceFt / UnitsDisplay.ACCURACY_FEET_NEAR) + * UnitsDisplay.ACCURACY_FEET_NEAR; + } + sDistance = String.format(res.getString(R.string.placemark_distance_imp_feet), + iDistanceFt); + } + } + else { + /** + * Display distance in Miles when greater than 1 mile. + */ + sDistance = String.format(res.getString(R.string.placemark_distance_imp), + fDistanceMi); + } + } + else { + /** + * International Units system, Meters and Km. + */ + + if (fDistanceM <= UnitsDisplay.MIN_METERS) { + /** + * Display "Less than 100 m". + */ + sDistance = res.getString(R.string.placemark_distance_iso_min); + } + else { + /** + * No need to have a constant for 1 Km = 1000 M + */ + float fDistanceKm = (fDistanceM / 1000); + sDistance = String + .format(res.getString(R.string.placemark_distance_iso), fDistanceKm); + } + } + + return sDistance; + } + +}