- Working update thread - Changed to Euro-based conversion because of ECB as data provider - Added XPath namespace helpers in case we can get namespaces working
/trunk/src/de/pointedears/converter/app/CurrenciesActivity.java |
---|
5,6 → 5,7 |
import android.app.Activity; |
import android.os.Bundle; |
import android.os.Handler; |
import android.text.Editable; |
import android.view.KeyEvent; |
import android.view.Menu; |
23,7 → 24,8 |
import android.widget.TextView; |
import de.pointedears.converter.R; |
import de.pointedears.converter.db.CurrenciesDatabase; |
import de.pointedears.converter.helpers.CurrenciesUpdateThread; |
import de.pointedears.converter.helpers.ConverterThread; |
import de.pointedears.converter.net.RatesUpdater; |
/** |
* Activity that implements currency conversion |
58,8 → 60,12 |
private Spinner spinnerUnit2; |
private CurrenciesDatabase db; |
private HashMap<String, HashMap<String, Double>> conversionRates; |
private HashMap<String, Double> conversionRates; |
private ConverterThread updateThread; |
private Handler handler; |
private RatesUpdater updateRates; |
/** Called when the activity is first created. */ |
@Override |
186,8 → 192,15 |
editValue2.setText(""); |
} |
}); |
if (this.handler == null) |
{ |
this.handler = new Handler(); |
} |
this.updateThread = null; |
} |
/** |
* Fills the table with currency conversion rates |
*/ |
196,21 → 209,14 |
TableLayout tableRates = |
(TableLayout) this.findViewById(R.id.currencies_table_rates); |
for (String key : this.conversionRates.keySet()) |
for (Entry<String, Double> factorEntry : this.conversionRates.entrySet()) |
{ |
for (Entry<String, Double> factorEntry : this.conversionRates.get(key) |
.entrySet()) |
{ |
TableRow row = new TableRow(this); |
TextView columnCurrency1 = new TextView(this); |
columnCurrency1.setText(key); |
columnCurrency1.setText(factorEntry.getKey()); |
row.addView(columnCurrency1); |
TextView columnCurrency2 = new TextView(this); |
columnCurrency2.setText(factorEntry.getKey()); |
row.addView(columnCurrency2); |
TextView columnRate = new TextView(this); |
columnRate.setText(factorEntry.getValue().toString()); |
row.addView(columnRate); |
218,7 → 224,6 |
tableRates.addView(row); |
} |
} |
} |
/** |
* @param value |
242,17 → 247,34 |
Double newValue = value; |
HashMap<String, Double> mapForCurrency = |
this.conversionRates.get(selectedItemValue1); |
if (mapForCurrency != null) |
/* |
* NOTE: Had to do it the complicated way because somehow the Android SDK |
* won't get it another way |
*/ |
Double factorToEuro = null; |
if (selectedItemValue1 != null) |
{ |
Double conversionFactor = mapForCurrency.get(selectedItemValue2); |
if (conversionFactor != null) |
factorToEuro = this.conversionRates.get(selectedItemValue1); |
} |
if (factorToEuro == null) |
{ |
newValue *= conversionFactor; |
factorToEuro = 1.0; |
} |
Double factorFromEuro = null; |
if (selectedItemValue2 != null) |
{ |
factorFromEuro = this.conversionRates.get(selectedItemValue2); |
} |
if (factorFromEuro == null) |
{ |
factorFromEuro = 1.0; |
} |
newValue = newValue / factorToEuro * factorFromEuro; |
return newValue.toString(); |
} |
286,10 → 308,45 |
switch (item.getItemId()) |
{ |
case R.id.item_options_update: |
Thread updateThread = new CurrenciesUpdateThread(); |
updateThread.start(); |
if (this.updateThread == null) |
{ |
this.updateRates = new RatesUpdater(this); |
this.updateThread = |
new ConverterThread(this.updateRates, this.handler); |
this.updateRates.setUpdateThread(this.updateThread); |
} |
try |
{ |
this.updateThread.start(); |
// this.editValue1.setText("Gestartet!"); |
} |
catch (IllegalThreadStateException e) |
{ |
// this.editValue1.setText("Bereits gestartet!"); |
} |
return true; |
case R.id.item_options_quit: |
if (this.updateThread != null) |
{ |
try |
{ |
this.updateThread.join(); |
} |
catch (InterruptedException e) |
{ |
// TODO Auto-generated catch block |
} |
// this.editValue1.setText("Gestoppt -> Warten auf Start"); |
} |
else |
{ |
// this.editValue1.setText("Bereits gestoppt -> Warten auf Start"); |
} |
return true; |
default: |
return super.onOptionsItemSelected(item); |
} |
/trunk/src/de/pointedears/converter/helpers/CurrenciesUpdateThread.java |
---|
File deleted |
Property changes: |
Deleted: svn:mime-type |
## -1 +0,0 ## |
-text/plain |
\ No newline at end of property |
Index: converter/helpers/ConverterThread.java |
=================================================================== |
--- converter/helpers/ConverterThread.java (nonexistent) |
+++ converter/helpers/ConverterThread.java (revision 16) |
@@ -0,0 +1,30 @@ |
+package de.pointedears.converter.helpers; |
+ |
+import android.os.Handler; |
+ |
+/** |
+ * General thread to perform background tasks |
+ * |
+ * @author pelinux |
+ */ |
+public class ConverterThread extends Thread |
+{ |
+ private Handler handler = null; |
+ private Runnable runnable = null; |
+ |
+ /** |
+ * @param runnable |
+ * @param handler |
+ */ |
+ public ConverterThread(Runnable runnable, Handler handler) |
+ { |
+ this.handler = handler; |
+ this.runnable = runnable; |
+ } |
+ |
+ @Override |
+ public void run() |
+ { |
+ this.handler.post(this.runnable); |
+ } |
+} |
/converter/helpers/ConverterThread.java |
---|
Property changes: |
Added: svn:mime-type |
## -0,0 +1 ## |
+text/plain |
\ No newline at end of property |
Index: converter/helpers/ConverterNamespaceContext.java |
=================================================================== |
--- converter/helpers/ConverterNamespaceContext.java (nonexistent) |
+++ converter/helpers/ConverterNamespaceContext.java (revision 16) |
@@ -0,0 +1,58 @@ |
+package de.pointedears.converter.helpers; |
+ |
+import java.util.HashMap; |
+import java.util.Iterator; |
+ |
+import javax.xml.XMLConstants; |
+import javax.xml.namespace.NamespaceContext; |
+ |
+/** |
+ * @author pelinux |
+ * |
+ */ |
+public final class ConverterNamespaceContext implements NamespaceContext |
+{ |
+ private final HashMap<String, String> namespaces = |
+ new HashMap<String, String>(); |
+ |
+ public void add(String prefix, String uri) |
+ { |
+ this.namespaces.put(prefix, uri); |
+ } |
+ |
+ @Override |
+ public Iterator getPrefixes(String namespaceURI) |
+ { |
+ throw new UnsupportedOperationException(); |
+ } |
+ |
+ @Override |
+ public String getPrefix(String namespaceURI) |
+ { |
+ throw new UnsupportedOperationException(); |
+ } |
+ |
+ @Override |
+ public String getNamespaceURI(String prefix) |
+ { |
+ if (prefix == null) |
+ { |
+ throw new NullPointerException("Null prefix"); |
+ } |
+ else |
+ { |
+ if ("xml".equals(prefix)) |
+ { |
+ return XMLConstants.XML_NS_URI; |
+ } |
+ |
+ String storedPrefix = this.namespaces.get(prefix); |
+ if (storedPrefix != null) |
+ { |
+ return storedPrefix; |
+ } |
+ |
+ return XMLConstants.NULL_NS_URI; |
+ } |
+ } |
+} |
\ No newline at end of file |
/converter/helpers/ConverterNamespaceContext.java |
---|
Property changes: |
Added: svn:mime-type |
## -0,0 +1 ## |
+text/plain |
\ No newline at end of property |
Index: converter/db/CurrenciesDatabase.java |
=================================================================== |
--- converter/db/CurrenciesDatabase.java (revision 15) |
+++ converter/db/CurrenciesDatabase.java (revision 16) |
@@ -20,36 +20,22 @@ |
public class CurrenciesDatabase extends SQLiteOpenHelper |
{ |
private static final String DATABASE_NAME = "currency.db"; //$NON-NLS-1$ |
- private static final int DATABASE_VERSION = 2; |
+ private static final int DATABASE_VERSION = 3; |
private static final String TABLE = "currency"; //$NON-NLS-1$ |
- private static final String COLUMN_CURRENCY1 = "currency1"; //$NON-NLS-1$ |
- private static final String COLUMN_CURRENCY2 = "currency2"; //$NON-NLS-1$ |
+ private static final String COLUMN_CURRENCY = "currency1"; //$NON-NLS-1$ |
private static final String COLUMN_FACTOR = "factor"; //$NON-NLS-1$ |
- private static HashMap<String, HashMap<String, Double>> conversionRates = |
- new HashMap<String, HashMap<String, Double>>(); |
+ private static HashMap<String, Double> conversionRates = |
+ new HashMap<String, Double>(); |
static |
{ |
- HashMap<String, Double> conversionFactors = new HashMap<String, Double>(); |
- conversionFactors.put(CurrenciesActivity.VALUE_EUR, 0.767842293); |
- conversionFactors.put(CurrenciesActivity.VALUE_USD, 1.03413); |
- CurrenciesDatabase.conversionRates.put(CurrenciesActivity.VALUE_CHF, |
- conversionFactors); |
- |
- conversionFactors = new HashMap<String, Double>(); |
- conversionFactors.put(CurrenciesActivity.VALUE_CHF, 1.30235077); |
- conversionFactors.put(CurrenciesActivity.VALUE_USD, 1.3468); |
- CurrenciesDatabase.conversionRates.put(CurrenciesActivity.VALUE_EUR, |
- conversionFactors); |
- |
- conversionFactors = new HashMap<String, Double>(); |
- conversionFactors.put(CurrenciesActivity.VALUE_CHF, 0.966996412); |
- conversionFactors.put(CurrenciesActivity.VALUE_EUR, 0.742500743); |
- CurrenciesDatabase.conversionRates.put(CurrenciesActivity.VALUE_USD, |
- conversionFactors); |
+ /* Default conversion rates from Euro (EUR) to other currencies */ |
+ CurrenciesDatabase.conversionRates |
+ .put(CurrenciesActivity.VALUE_CHF, 1.3013); |
+ CurrenciesDatabase.conversionRates |
+ .put(CurrenciesActivity.VALUE_USD, 1.3521); |
} |
- private final CurrenciesActivity context; |
/** |
* @param context |
@@ -59,7 +45,6 @@ |
{ |
super(context, CurrenciesDatabase.DATABASE_NAME, null, |
CurrenciesDatabase.DATABASE_VERSION); |
- this.context = context; |
this.readConversionsFromDatabase(); |
} |
@@ -75,30 +60,23 @@ |
public void onCreate(SQLiteDatabase db) |
{ |
db.execSQL("CREATE TABLE IF NOT EXISTS " + CurrenciesDatabase.TABLE |
- + " (" + CurrenciesDatabase.COLUMN_CURRENCY1 + " TEXT, " |
- + CurrenciesDatabase.COLUMN_CURRENCY2 + " TEXT, " |
+ + " (" + CurrenciesDatabase.COLUMN_CURRENCY + " TEXT, " |
+ CurrenciesDatabase.COLUMN_FACTOR |
+ " NUMERIC" |
+ ", CONSTRAINT unique_currency_pair UNIQUE (" |
- + CurrenciesDatabase.COLUMN_CURRENCY1 + ", " |
- + CurrenciesDatabase.COLUMN_CURRENCY2 + "))"); |
+ + CurrenciesDatabase.COLUMN_CURRENCY + "))"); |
- HashMap<String, HashMap<String, Double>> currencyConversions = |
+ HashMap<String, Double> currencyConversions = |
this.getConversionRates(); |
- for (String key : currencyConversions.keySet()) |
+ for (Entry<String, Double> factorEntry : currencyConversions.entrySet()) |
{ |
- for (Entry<String, Double> factorEntry : currencyConversions.get(key) |
- .entrySet()) |
- { |
ContentValues values = new ContentValues(); |
- values.put(CurrenciesDatabase.COLUMN_CURRENCY1, key); |
- values.put(CurrenciesDatabase.COLUMN_CURRENCY2, factorEntry.getKey()); |
+ values.put(CurrenciesDatabase.COLUMN_CURRENCY, factorEntry.getKey()); |
values.put(CurrenciesDatabase.COLUMN_FACTOR, factorEntry.getValue()); |
db.insert(CurrenciesDatabase.TABLE, CurrenciesDatabase.COLUMN_FACTOR, |
values); |
} |
} |
- } |
/* |
* (non-Javadoc) |
@@ -119,7 +97,7 @@ |
/** |
* @return |
*/ |
- public HashMap<String, HashMap<String, Double>> getConversionRates() |
+ public HashMap<String, Double> getConversionRates() |
{ |
return CurrenciesDatabase.conversionRates; |
} |
@@ -135,11 +113,9 @@ |
/* Get database connection, but upgrade database first if necessary! */ |
SQLiteDatabase dbConn = this.getWritableDatabase(); |
- @SuppressWarnings("nls") |
Cursor cursor = |
dbConn.query(true, CurrenciesDatabase.TABLE, null, null, null, null, |
- null, CurrenciesDatabase.COLUMN_CURRENCY1 + "," |
- + CurrenciesDatabase.COLUMN_CURRENCY2, null); |
+ null, CurrenciesDatabase.COLUMN_CURRENCY, null); |
if (cursor != null) |
{ |
@@ -147,10 +123,7 @@ |
{ |
int currency1Id = |
cursor |
- .getColumnIndexOrThrow(CurrenciesDatabase.COLUMN_CURRENCY1); |
- int currency2Id = |
- cursor |
- .getColumnIndexOrThrow(CurrenciesDatabase.COLUMN_CURRENCY2); |
+ .getColumnIndexOrThrow(CurrenciesDatabase.COLUMN_CURRENCY); |
int factorId = |
cursor.getColumnIndexOrThrow(CurrenciesDatabase.COLUMN_FACTOR); |
@@ -157,58 +130,17 @@ |
/* NOTE: Don't change the default values if the table is empty */ |
if (cursor.moveToFirst()) |
{ |
- HashMap<String, HashMap<String, Double>> newCurrencyConversions = |
- new HashMap<String, HashMap<String, Double>>(); |
- HashMap<String, Double> mapForCurrency = null; |
- String lastCurrency1Str = null; |
- String currency1Str; |
+ HashMap<String, Double> newCurrencyConversions = |
+ new HashMap<String, Double>(); |
do |
{ |
- currency1Str = cursor.getString(currency1Id); |
- String currency2Str = cursor.getString(currency2Id); |
+ String currencyStr = cursor.getString(currency1Id); |
Double factor = cursor.getDouble(factorId); |
- |
- if (lastCurrency1Str == null |
- || !lastCurrency1Str.equals(currency1Str)) |
- { |
- /* |
- * NOTE: Update outer map when we see a new currency; |
- * ORDER BY ensures we don't see a currency1 twice except |
- * consecutively |
- */ |
- if (mapForCurrency != null) |
- { |
- newCurrencyConversions.put(lastCurrency1Str, mapForCurrency); |
+ newCurrencyConversions.put(currencyStr, factor); |
} |
- |
- lastCurrency1Str = new String(currency1Str); |
- |
- /* NOTE: New currency1: Reset inner map */ |
- mapForCurrency = newCurrencyConversions.get(currency1Str); |
- } |
- |
- /* If we did not see this currency1 before */ |
- if (mapForCurrency == null) |
- { |
- mapForCurrency = new HashMap<String, Double>(); |
- } |
- |
- /* |
- * NOTE: Update inner map after each table row; assignment to |
- * mapForCurrency above ensures we are putting the factor |
- * into the correct map. |
- */ |
- mapForCurrency.put(currency2Str, factor); |
- } |
while (cursor.moveToNext()); |
- /* |
- * NOTE: Update from last table row; cursor not empty, so we can |
- * skip the test for null |
- */ |
- newCurrencyConversions.put(currency1Str, mapForCurrency); |
- |
CurrenciesDatabase.conversionRates = newCurrencyConversions; |
} |
} |
@@ -237,11 +169,9 @@ |
{ |
SQLiteDatabase dbConn = this.getReadableDatabase(); |
- @SuppressWarnings("nls") |
Cursor myCursor = |
dbConn.query(true, CurrenciesDatabase.TABLE, null, null, null, null, |
- null, CurrenciesDatabase.COLUMN_CURRENCY1 + "," |
- + CurrenciesDatabase.COLUMN_CURRENCY2, null); |
+ null, CurrenciesDatabase.COLUMN_CURRENCY, null); |
@SuppressWarnings({ "unused", "nls" }) |
String queryResult = ""; |
@@ -251,10 +181,7 @@ |
{ |
int currency1Id = |
myCursor |
- .getColumnIndexOrThrow(CurrenciesDatabase.COLUMN_CURRENCY1); |
- int currency2Id = |
- myCursor |
- .getColumnIndexOrThrow(CurrenciesDatabase.COLUMN_CURRENCY2); |
+ .getColumnIndexOrThrow(CurrenciesDatabase.COLUMN_CURRENCY); |
int factorId = |
myCursor.getColumnIndexOrThrow(CurrenciesDatabase.COLUMN_FACTOR); |
@@ -262,13 +189,12 @@ |
{ |
do |
{ |
- String currency1Str = myCursor.getString(currency1Id); |
- String currency2Str = myCursor.getString(currency2Id); |
+ String currencyStr = myCursor.getString(currency1Id); |
Double factor = myCursor.getDouble(factorId); |
/* DEBUG */ |
queryResult += |
- currency1Str + " --> " + currency2Str + ": " + factor + "\n"; |
+ "EUR --> " + currencyStr + ": " + factor + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
} |
while (myCursor.moveToNext()); |
} |
/trunk/src/de/pointedears/converter/net/RatesUpdater.java |
---|
0,0 → 1,179 |
/** |
* |
*/ |
package de.pointedears.converter.net; |
import java.io.IOException; |
import javax.xml.parsers.DocumentBuilder; |
import javax.xml.parsers.DocumentBuilderFactory; |
import javax.xml.parsers.ParserConfigurationException; |
import javax.xml.xpath.XPath; |
import javax.xml.xpath.XPathConstants; |
import javax.xml.xpath.XPathExpression; |
import javax.xml.xpath.XPathExpressionException; |
import javax.xml.xpath.XPathFactory; |
import org.w3c.dom.Document; |
import org.w3c.dom.NamedNodeMap; |
import org.w3c.dom.Node; |
import org.w3c.dom.NodeList; |
import org.xml.sax.SAXException; |
import android.app.Notification; |
import android.app.NotificationManager; |
import android.app.PendingIntent; |
import android.content.Context; |
import android.content.Intent; |
import de.pointedears.converter.R; |
import de.pointedears.converter.helpers.ConverterThread; |
/** |
* @author pelinux |
* |
*/ |
public class RatesUpdater implements Runnable |
{ |
private static final String URL_ECB = |
"http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"; //$NON-NLS-1$ |
private final Context activityContext; |
private ConverterThread updateThread = null; |
/** |
* |
*/ |
public RatesUpdater(Context activityContext) |
{ |
this.activityContext = activityContext; |
} |
/** |
* @return the updateThread |
*/ |
public ConverterThread getUpdateThread() |
{ |
return this.updateThread; |
} |
/** |
* @param updateThread |
*/ |
public void setUpdateThread(ConverterThread updateThread) |
{ |
this.updateThread = updateThread; |
} |
/* |
* (non-Javadoc) |
* |
* @see java.lang.Runnable#run() |
*/ |
@Override |
public void run() |
{ |
if (this.getUpdateThread() != null) |
{ |
// CurrenciesActivity.this.editValue1.setText("42"); |
DocumentBuilderFactory documentBuilderFactory = |
DocumentBuilderFactory.newInstance(); |
documentBuilderFactory.setNamespaceAware(true); |
try |
{ |
DocumentBuilder builder = |
documentBuilderFactory.newDocumentBuilder(); |
try |
{ |
Document doc = builder.parse(RatesUpdater.URL_ECB); |
XPathFactory xpathFactory = XPathFactory.newInstance(); |
XPath xpath = xpathFactory.newXPath(); |
// NamespaceContextHelper namespaceContext = |
// new NamespaceContextHelper(); |
// namespaceContext.add("gesmes", |
// "http://www.gesmes.org/xml/2002-08-01"); |
// xpath.setNamespaceContext(namespaceContext); |
try |
{ |
/* |
* FIXME: Why doesn't a simple "./Cube/Cube/Cube" work even with a |
* namespace resolver? |
*/ |
XPathExpression expr = |
xpath |
.compile("./*[local-name() = 'Cube']/*[local-name() = 'Cube']/*[local-name() = 'Cube']"); //$NON-NLS-1$ |
Object result = |
expr.evaluate(doc.getDocumentElement(), XPathConstants.NODESET); |
NodeList nodes = (NodeList) result; |
int len = nodes.getLength(); |
String ns = Context.NOTIFICATION_SERVICE; |
NotificationManager mNotificationManager = |
(NotificationManager) this.activityContext |
.getSystemService(ns); |
int icon = R.drawable.icon; |
CharSequence tickerText = "Found " + len + " nodes!"; |
long when = System.currentTimeMillis(); |
Notification notification = |
new Notification(icon, tickerText, when); |
Context applicationContext = |
this.activityContext.getApplicationContext(); |
CharSequence contentTitle = "Converter"; |
CharSequence contentText = "Found " + len + " nodes!"; |
Intent notificationIntent = |
new Intent(this.activityContext, this.activityContext.getClass()); |
PendingIntent contentIntent = |
PendingIntent.getActivity(this.activityContext, 0, |
notificationIntent, 0); |
notification.setLatestEventInfo(applicationContext, contentTitle, |
contentText, |
contentIntent); |
// private static final int HELLO_ID = 1; |
mNotificationManager.notify(1, notification); |
for (int i = 0; i < len; ++i) |
{ |
Node item = nodes.item(i); |
NamedNodeMap attributes = item.getAttributes(); |
String currency = |
attributes |
.getNamedItem("currency").getNodeValue(); //$NON-NLS-1$ |
String rate = attributes.getNamedItem("rate").getNodeValue(); //$NON-NLS-1$ |
/* TODO: Update UI */ |
System.out.println(currency + ": " + rate); //$NON-NLS-1$ |
} |
} |
catch (XPathExpressionException e) |
{ |
// TODO Auto-generated catch block |
e.printStackTrace(); |
} |
} |
catch (SAXException e) |
{ |
// TODO Auto-generated catch block |
e.printStackTrace(); |
} |
catch (IOException e) |
{ |
// TODO Auto-generated catch block |
e.printStackTrace(); |
} |
} |
catch (ParserConfigurationException e) |
{ |
// TODO Auto-generated catch block |
e.printStackTrace(); |
} |
} |
} |
} |
Property changes: |
Added: svn:mime-type |
## -0,0 +1 ## |
+text/plain |
\ No newline at end of property |