Subversion Repositories ES

Rev

Rev 16 | Rev 18 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
8 PointedEar 1
package de.pointedears.converter.app;
5 PointedEar 2
 
17 PointedEar 3
import java.text.DateFormat;
4
import java.text.SimpleDateFormat;
5
import java.util.Date;
7 PointedEar 6
import java.util.HashMap;
14 PointedEar 7
import java.util.Map.Entry;
7 PointedEar 8
 
5 PointedEar 9
import android.app.Activity;
17 PointedEar 10
import android.content.BroadcastReceiver;
11
import android.content.Context;
12
import android.content.Intent;
13
import android.content.IntentFilter;
5 PointedEar 14
import android.os.Bundle;
7 PointedEar 15
import android.text.Editable;
16
import android.view.KeyEvent;
8 PointedEar 17
import android.view.Menu;
18
import android.view.MenuInflater;
19
import android.view.MenuItem;
7 PointedEar 20
import android.view.View;
13 PointedEar 21
import android.view.View.OnClickListener;
7 PointedEar 22
import android.view.View.OnKeyListener;
23
import android.widget.AdapterView;
24
import android.widget.AdapterView.OnItemSelectedListener;
13 PointedEar 25
import android.widget.Button;
7 PointedEar 26
import android.widget.EditText;
27
import android.widget.Spinner;
14 PointedEar 28
import android.widget.TableLayout;
29
import android.widget.TableRow;
30
import android.widget.TextView;
8 PointedEar 31
import de.pointedears.converter.R;
17 PointedEar 32
import de.pointedears.converter.db.ConversionData;
11 PointedEar 33
import de.pointedears.converter.db.CurrenciesDatabase;
17 PointedEar 34
import de.pointedears.converter.helpers.Notifier;
35
import de.pointedears.converter.helpers.UpdateService;
5 PointedEar 36
 
37
/**
7 PointedEar 38
 * Activity that implements currency conversion
5 PointedEar 39
 *
7 PointedEar 40
 * @author pelinux
5 PointedEar 41
 */
42
public class CurrenciesActivity extends Activity
43
{
17 PointedEar 44
  /**
45
   * String to use to indicate that an exchange rate has never been updated
46
   */
47
  private static final String TEXT_NEVER = "never";
48
 
49
  /**
50
   * Serialization version id
51
   */
52
  private static final long serialVersionUID = 1L;
53
 
7 PointedEar 54
  /*
8 PointedEar 55
   * Constants for mapping value strings
12 PointedEar 56
   *
57
   * @todo: Use resource IDs
7 PointedEar 58
   */
12 PointedEar 59
  /**
60
   * Database field/spinner value for Swiss Francs
61
   */
62
  public static final String VALUE_CHF = "CHF"; //$NON-NLS-1$
7 PointedEar 63
 
12 PointedEar 64
  /**
65
   * Database field/spinner value for Euros
66
   */
7 PointedEar 67
 
12 PointedEar 68
  public static final String VALUE_EUR = "EUR"; //$NON-NLS-1$
69
 
70
  /**
71
   * Database field/spinner value for US Dollars
72
   */
73
  public static final String VALUE_USD = "USD"; //$NON-NLS-1$
74
 
7 PointedEar 75
  /* Unit spinners (dropdowns) */
76
  private Spinner spinnerUnit1;
77
  private Spinner spinnerUnit2;
17 PointedEar 78
  private CurrenciesDatabase database;
7 PointedEar 79
 
17 PointedEar 80
  private HashMap<String, ConversionData> conversionRates;
12 PointedEar 81
 
17 PointedEar 82
  /**
83
   * Receiver for intent broadcasts, registered in
84
   * {@link CurrenciesActivity#onCreate(Bundle)}
85
   */
86
  public class UpdateBroadcastReceiver extends BroadcastReceiver
87
  {
88
    /**
89
     * Notification message template
90
     */
91
    private static final String EXCHANGE_RATES_UPDATED_TO =
92
      " exchange rates updated to ";
16 PointedEar 93
 
17 PointedEar 94
    /*
95
     * (non-Javadoc)
96
     *
97
     * @see android.content.BroadcastReceiver#onReceive(android.content.Context,
98
     * android.content.Intent)
99
     */
100
    @Override
101
    public void onReceive(Context context, Intent intent)
102
    {
103
      if (intent.getAction().equals(UpdateService.ACTION_UPDATE))
104
      {
105
        Bundle extras = intent.getExtras();
106
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$
107
        Notifier.sendMessage(CurrenciesActivity.this,
108
          extras.get(UpdateService.EXTRA_NUM_RATES)
109
            + UpdateBroadcastReceiver.EXCHANGE_RATES_UPDATED_TO
110
            + df.format(extras.get(UpdateService.EXTRA_DATE)));
111
      }
112
    }
113
  }
114
 
7 PointedEar 115
  /** Called when the activity is first created. */
5 PointedEar 116
  @Override
7 PointedEar 117
  public void onCreate(Bundle savedInstanceState)
5 PointedEar 118
  {
119
    super.onCreate(savedInstanceState);
7 PointedEar 120
    this.setContentView(R.layout.activity_currencies);
5 PointedEar 121
 
17 PointedEar 122
    UpdateBroadcastReceiver br = new UpdateBroadcastReceiver();
123
    this.registerReceiver(br, new IntentFilter(UpdateService.ACTION_UPDATE));
124
 
12 PointedEar 125
    /* Set up currency database, and retrieve conversion rates */
17 PointedEar 126
    this.database = new CurrenciesDatabase(this);
127
    this.setConversionRates(this.getDatabase().getConversionRates());
14 PointedEar 128
    this.fillTableRates();
8 PointedEar 129
 
7 PointedEar 130
    final EditText editValue1 =
131
      (EditText) this.findViewById(R.id.currencies_edit_value1);
132
    final EditText editValue2 =
133
      (EditText) this.findViewById(R.id.currencies_edit_value2);
134
 
135
    final OnKeyListener editValue1OnKey = new OnKeyListener() {
136
      @Override
137
      public boolean onKey(View v, int keyCode, KeyEvent event)
138
      {
139
        Editable editable1 = ((EditText) v).getText();
140
 
141
        Double value1;
142
        try
143
        {
144
          value1 = Double.parseDouble(editable1.toString());
145
        }
146
        catch (NumberFormatException e)
147
        {
148
          value1 = null;
149
        }
150
 
151
        String string2 = ""; //$NON-NLS-1$
152
        if (value1 != null)
153
        {
154
          string2 = CurrenciesActivity.this.getConvertedValue(value1, false);
155
        }
156
 
157
        editValue2.setText(string2);
158
 
159
        return false;
160
      }
161
    };
162
    editValue1.setOnKeyListener(editValue1OnKey);
163
 
164
    final OnKeyListener editValue2OnKey = new OnKeyListener() {
165
      @Override
166
      public boolean onKey(View v, int keyCode, KeyEvent event)
167
      {
168
        Editable editable2 = ((EditText) v).getText();
169
 
170
        Double value2;
171
        try
172
        {
173
          value2 = Double.parseDouble(editable2.toString());
174
        }
175
        catch (NumberFormatException e)
176
        {
177
          value2 = null;
178
        }
179
 
180
        String string1 = ""; //$NON-NLS-1$
181
        if (value2 != null)
182
        {
183
          string1 = CurrenciesActivity.this.getConvertedValue(value2, true);
184
        }
185
 
186
        editValue1.setText(string1);
187
 
188
        return false;
189
      }
190
    };
191
    editValue2.setOnKeyListener(editValue2OnKey);
192
 
193
    this.spinnerUnit1 =
194
      (Spinner) this.findViewById(R.id.currencies_spinner_unit1);
195
    this.spinnerUnit2 =
196
      (Spinner) this.findViewById(R.id.currencies_spinner_unit2);
197
 
198
    this.spinnerUnit1.setOnItemSelectedListener(new OnItemSelectedListener() {
199
      @Override
200
      public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
201
        long arg3)
202
      {
203
        /* Simulate input in second EditText so that first EditText is updated */
204
        editValue2OnKey.onKey(editValue2, 0, null);
205
      }
206
 
207
      @Override
208
      public void onNothingSelected(AdapterView<?> arg0)
209
      {
210
        /* no-op */
211
      }
212
    });
213
 
214
    this.spinnerUnit2.setSelection(1);
215
    this.spinnerUnit2.setOnItemSelectedListener(new OnItemSelectedListener() {
216
      @Override
217
      public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
218
        long arg3)
219
      {
220
        /* Simulate input in first EditText so that second EditText is updated */
221
        editValue1OnKey.onKey(editValue1, 0, null);
222
      }
223
 
224
      @Override
225
      public void onNothingSelected(AdapterView<?> arg0)
226
      {
227
        /* no-op */
228
      }
229
    });
13 PointedEar 230
 
231
    Button buttonClear =
232
      (Button) this.findViewById(R.id.currencies_button_clear);
233
    buttonClear.setOnClickListener(new OnClickListener() {
234
 
235
      @SuppressWarnings("nls")
236
      @Override
237
      public void onClick(View v)
238
      {
239
        editValue1.setText("");
240
        editValue2.setText("");
241
      }
242
    });
5 PointedEar 243
  }
7 PointedEar 244
 
245
  /**
14 PointedEar 246
   * Fills the table with currency conversion rates
247
   */
17 PointedEar 248
  public void fillTableRates()
14 PointedEar 249
  {
250
    TableLayout tableRates =
251
      (TableLayout) this.findViewById(R.id.currencies_table_rates);
252
 
17 PointedEar 253
    /* Remove any pre-existing currency rows */
254
    while (tableRates.getChildCount() > 3)
14 PointedEar 255
    {
17 PointedEar 256
      tableRates.removeViewAt(3);
257
    }
258
 
259
    for (Entry<String, ConversionData> factorEntry : this.getConversionRates()
260
      .entrySet())
261
    {
16 PointedEar 262
      TableRow row = new TableRow(this);
14 PointedEar 263
 
16 PointedEar 264
      TextView columnCurrency1 = new TextView(this);
265
      columnCurrency1.setText(factorEntry.getKey());
266
      row.addView(columnCurrency1);
14 PointedEar 267
 
16 PointedEar 268
      TextView columnRate = new TextView(this);
17 PointedEar 269
      final ConversionData conversionData = factorEntry.getValue();
270
      columnRate.setText(conversionData.getRate().toString());
16 PointedEar 271
      row.addView(columnRate);
14 PointedEar 272
 
17 PointedEar 273
      TextView columnUpdated = new TextView(this);
274
      Date updated = conversionData.getUpdated();
275
      if (updated.getTime() > 0)
276
      {
277
        DateFormat df =
278
          DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
279
        columnUpdated.setText(df.format(updated));
280
      }
281
      else
282
      {
283
        columnUpdated.setText(CurrenciesActivity.TEXT_NEVER);
284
      }
285
 
286
      row.addView(columnUpdated);
287
 
16 PointedEar 288
      tableRates.addView(row);
14 PointedEar 289
    }
290
  }
291
 
292
  /**
7 PointedEar 293
   * @param value
294
   * @return
295
   */
296
  private String getConvertedValue(double value, boolean reverse)
297
  {
298
    int selectedItemPosition1 = this.spinnerUnit1.getSelectedItemPosition();
299
    int selectedItemPosition2 = this.spinnerUnit2.getSelectedItemPosition();
8 PointedEar 300
    String[] items =
7 PointedEar 301
      this.getResources().getStringArray(R.array.currency_units_values);
8 PointedEar 302
    String selectedItemValue1 = items[selectedItemPosition1];
303
    String selectedItemValue2 = items[selectedItemPosition2];
7 PointedEar 304
 
305
    if (reverse)
306
    {
307
      String tmp = selectedItemValue1;
308
      selectedItemValue1 = selectedItemValue2;
309
      selectedItemValue2 = tmp;
310
    }
311
 
312
    Double newValue = value;
313
 
16 PointedEar 314
    /*
315
     * NOTE: Had to do it the complicated way because somehow the Android SDK
316
     * won't get it another way
317
     */
17 PointedEar 318
    ConversionData conversionData1 = null;
319
    Double factorToEuro = 1.0;
16 PointedEar 320
    if (selectedItemValue1 != null)
7 PointedEar 321
    {
17 PointedEar 322
      conversionData1 = this.getConversionRates().get(selectedItemValue1);
323
      if (conversionData1 != null)
324
      {
325
        factorToEuro = conversionData1.getRate();
326
      }
7 PointedEar 327
    }
328
 
17 PointedEar 329
    ConversionData conversionData2 = null;
330
    Double factorFromEuro = 1.0;
16 PointedEar 331
    if (selectedItemValue2 != null)
332
    {
17 PointedEar 333
      conversionData2 = this.getConversionRates().get(selectedItemValue2);
334
      if (conversionData2 != null)
335
      {
336
        factorFromEuro = conversionData2.getRate();
337
      }
16 PointedEar 338
    }
339
 
340
    newValue = newValue / factorToEuro * factorFromEuro;
341
 
7 PointedEar 342
    return newValue.toString();
343
  }
8 PointedEar 344
 
345
  /*
346
   * (non-Javadoc)
347
   *
348
   * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
349
   */
12 PointedEar 350
  /*
351
   * (non-Javadoc)
352
   *
353
   * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
354
   */
8 PointedEar 355
  @Override
356
  public boolean onCreateOptionsMenu(Menu menu)
357
  {
358
    MenuInflater inflater = this.getMenuInflater();
359
    inflater.inflate(R.menu.options, menu);
360
    return true;
361
  }
362
 
363
  /*
364
   * (non-Javadoc)
365
   *
366
   * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
367
   */
368
  @Override
369
  public boolean onOptionsItemSelected(MenuItem item)
370
  {
17 PointedEar 371
    /* Handle item selection */
15 PointedEar 372
    switch (item.getItemId())
373
    {
374
      case R.id.item_options_update:
17 PointedEar 375
        /*
376
         * Request the update service to run a thread to fetch the rates from
377
         * the Web (project requirement)
378
         */
379
        Intent intent = new Intent(this, UpdateService.class);
380
        intent.setAction(UpdateService.ACTION_UPDATE);
16 PointedEar 381
 
17 PointedEar 382
        /*
383
         * FIXME: Not thread-safe!
384
         * Get the activity context from the intent directly instead
385
         */
386
        UpdateService.setActivityContext(this);
15 PointedEar 387
 
17 PointedEar 388
        this.startService(intent);
16 PointedEar 389
        return true;
390
 
15 PointedEar 391
      default:
392
        return super.onOptionsItemSelected(item);
393
    }
8 PointedEar 394
  }
17 PointedEar 395
 
396
  /**
397
   * @return the conversionRates
398
   */
399
  public HashMap<String, ConversionData> getConversionRates()
400
  {
401
    return this.conversionRates;
402
  }
403
 
404
  /**
405
   * @param conversionRates
406
   *          the conversionRates to set
407
   */
408
  public void setConversionRates(HashMap<String, ConversionData> conversionRates)
409
  {
410
    this.conversionRates = conversionRates;
411
  }
412
 
413
  /**
414
   * @return the database
415
   */
416
  public CurrenciesDatabase getDatabase()
417
  {
418
    return this.database;
419
  }
5 PointedEar 420
}