Subversion Repositories ES

Rev

Rev 17 | 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
      {
18 PointedEar 105
        CurrenciesActivity.this.fillTableRates();
106
 
17 PointedEar 107
        Bundle extras = intent.getExtras();
108
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$
109
        Notifier.sendMessage(CurrenciesActivity.this,
110
          extras.get(UpdateService.EXTRA_NUM_RATES)
111
            + UpdateBroadcastReceiver.EXCHANGE_RATES_UPDATED_TO
112
            + df.format(extras.get(UpdateService.EXTRA_DATE)));
113
      }
114
    }
115
  }
116
 
7 PointedEar 117
  /** Called when the activity is first created. */
5 PointedEar 118
  @Override
7 PointedEar 119
  public void onCreate(Bundle savedInstanceState)
5 PointedEar 120
  {
121
    super.onCreate(savedInstanceState);
7 PointedEar 122
    this.setContentView(R.layout.activity_currencies);
5 PointedEar 123
 
17 PointedEar 124
    UpdateBroadcastReceiver br = new UpdateBroadcastReceiver();
125
    this.registerReceiver(br, new IntentFilter(UpdateService.ACTION_UPDATE));
126
 
12 PointedEar 127
    /* Set up currency database, and retrieve conversion rates */
17 PointedEar 128
    this.database = new CurrenciesDatabase(this);
129
    this.setConversionRates(this.getDatabase().getConversionRates());
14 PointedEar 130
    this.fillTableRates();
8 PointedEar 131
 
7 PointedEar 132
    final EditText editValue1 =
133
      (EditText) this.findViewById(R.id.currencies_edit_value1);
134
    final EditText editValue2 =
135
      (EditText) this.findViewById(R.id.currencies_edit_value2);
136
 
137
    final OnKeyListener editValue1OnKey = new OnKeyListener() {
138
      @Override
139
      public boolean onKey(View v, int keyCode, KeyEvent event)
140
      {
141
        Editable editable1 = ((EditText) v).getText();
142
 
143
        Double value1;
144
        try
145
        {
146
          value1 = Double.parseDouble(editable1.toString());
147
        }
148
        catch (NumberFormatException e)
149
        {
150
          value1 = null;
151
        }
152
 
153
        String string2 = ""; //$NON-NLS-1$
154
        if (value1 != null)
155
        {
156
          string2 = CurrenciesActivity.this.getConvertedValue(value1, false);
157
        }
158
 
159
        editValue2.setText(string2);
160
 
161
        return false;
162
      }
163
    };
164
    editValue1.setOnKeyListener(editValue1OnKey);
165
 
166
    final OnKeyListener editValue2OnKey = new OnKeyListener() {
167
      @Override
168
      public boolean onKey(View v, int keyCode, KeyEvent event)
169
      {
170
        Editable editable2 = ((EditText) v).getText();
171
 
172
        Double value2;
173
        try
174
        {
175
          value2 = Double.parseDouble(editable2.toString());
176
        }
177
        catch (NumberFormatException e)
178
        {
179
          value2 = null;
180
        }
181
 
182
        String string1 = ""; //$NON-NLS-1$
183
        if (value2 != null)
184
        {
185
          string1 = CurrenciesActivity.this.getConvertedValue(value2, true);
186
        }
187
 
188
        editValue1.setText(string1);
189
 
190
        return false;
191
      }
192
    };
193
    editValue2.setOnKeyListener(editValue2OnKey);
194
 
195
    this.spinnerUnit1 =
196
      (Spinner) this.findViewById(R.id.currencies_spinner_unit1);
197
    this.spinnerUnit2 =
198
      (Spinner) this.findViewById(R.id.currencies_spinner_unit2);
199
 
200
    this.spinnerUnit1.setOnItemSelectedListener(new OnItemSelectedListener() {
201
      @Override
202
      public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
203
        long arg3)
204
      {
205
        /* Simulate input in second EditText so that first EditText is updated */
206
        editValue2OnKey.onKey(editValue2, 0, null);
207
      }
208
 
209
      @Override
210
      public void onNothingSelected(AdapterView<?> arg0)
211
      {
212
        /* no-op */
213
      }
214
    });
215
 
216
    this.spinnerUnit2.setSelection(1);
217
    this.spinnerUnit2.setOnItemSelectedListener(new OnItemSelectedListener() {
218
      @Override
219
      public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
220
        long arg3)
221
      {
222
        /* Simulate input in first EditText so that second EditText is updated */
223
        editValue1OnKey.onKey(editValue1, 0, null);
224
      }
225
 
226
      @Override
227
      public void onNothingSelected(AdapterView<?> arg0)
228
      {
229
        /* no-op */
230
      }
231
    });
13 PointedEar 232
 
233
    Button buttonClear =
234
      (Button) this.findViewById(R.id.currencies_button_clear);
235
    buttonClear.setOnClickListener(new OnClickListener() {
236
 
237
      @SuppressWarnings("nls")
238
      @Override
239
      public void onClick(View v)
240
      {
241
        editValue1.setText("");
242
        editValue2.setText("");
243
      }
244
    });
5 PointedEar 245
  }
7 PointedEar 246
 
247
  /**
14 PointedEar 248
   * Fills the table with currency conversion rates
249
   */
17 PointedEar 250
  public void fillTableRates()
14 PointedEar 251
  {
252
    TableLayout tableRates =
253
      (TableLayout) this.findViewById(R.id.currencies_table_rates);
254
 
17 PointedEar 255
    /* Remove any pre-existing currency rows */
256
    while (tableRates.getChildCount() > 3)
14 PointedEar 257
    {
17 PointedEar 258
      tableRates.removeViewAt(3);
259
    }
260
 
261
    for (Entry<String, ConversionData> factorEntry : this.getConversionRates()
262
      .entrySet())
263
    {
16 PointedEar 264
      TableRow row = new TableRow(this);
14 PointedEar 265
 
16 PointedEar 266
      TextView columnCurrency1 = new TextView(this);
267
      columnCurrency1.setText(factorEntry.getKey());
268
      row.addView(columnCurrency1);
14 PointedEar 269
 
16 PointedEar 270
      TextView columnRate = new TextView(this);
17 PointedEar 271
      final ConversionData conversionData = factorEntry.getValue();
272
      columnRate.setText(conversionData.getRate().toString());
16 PointedEar 273
      row.addView(columnRate);
14 PointedEar 274
 
17 PointedEar 275
      TextView columnUpdated = new TextView(this);
276
      Date updated = conversionData.getUpdated();
277
      if (updated.getTime() > 0)
278
      {
279
        DateFormat df =
280
          DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
281
        columnUpdated.setText(df.format(updated));
282
      }
283
      else
284
      {
285
        columnUpdated.setText(CurrenciesActivity.TEXT_NEVER);
286
      }
287
 
288
      row.addView(columnUpdated);
289
 
16 PointedEar 290
      tableRates.addView(row);
14 PointedEar 291
    }
292
  }
293
 
294
  /**
7 PointedEar 295
   * @param value
296
   * @return
297
   */
298
  private String getConvertedValue(double value, boolean reverse)
299
  {
300
    int selectedItemPosition1 = this.spinnerUnit1.getSelectedItemPosition();
301
    int selectedItemPosition2 = this.spinnerUnit2.getSelectedItemPosition();
8 PointedEar 302
    String[] items =
7 PointedEar 303
      this.getResources().getStringArray(R.array.currency_units_values);
8 PointedEar 304
    String selectedItemValue1 = items[selectedItemPosition1];
305
    String selectedItemValue2 = items[selectedItemPosition2];
7 PointedEar 306
 
307
    if (reverse)
308
    {
309
      String tmp = selectedItemValue1;
310
      selectedItemValue1 = selectedItemValue2;
311
      selectedItemValue2 = tmp;
312
    }
313
 
314
    Double newValue = value;
315
 
16 PointedEar 316
    /*
317
     * NOTE: Had to do it the complicated way because somehow the Android SDK
318
     * won't get it another way
319
     */
17 PointedEar 320
    ConversionData conversionData1 = null;
321
    Double factorToEuro = 1.0;
16 PointedEar 322
    if (selectedItemValue1 != null)
7 PointedEar 323
    {
17 PointedEar 324
      conversionData1 = this.getConversionRates().get(selectedItemValue1);
325
      if (conversionData1 != null)
326
      {
327
        factorToEuro = conversionData1.getRate();
328
      }
7 PointedEar 329
    }
330
 
17 PointedEar 331
    ConversionData conversionData2 = null;
332
    Double factorFromEuro = 1.0;
16 PointedEar 333
    if (selectedItemValue2 != null)
334
    {
17 PointedEar 335
      conversionData2 = this.getConversionRates().get(selectedItemValue2);
336
      if (conversionData2 != null)
337
      {
338
        factorFromEuro = conversionData2.getRate();
339
      }
16 PointedEar 340
    }
341
 
342
    newValue = newValue / factorToEuro * factorFromEuro;
343
 
7 PointedEar 344
    return newValue.toString();
345
  }
8 PointedEar 346
 
347
  /*
348
   * (non-Javadoc)
349
   *
350
   * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
351
   */
12 PointedEar 352
  /*
353
   * (non-Javadoc)
354
   *
355
   * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
356
   */
8 PointedEar 357
  @Override
358
  public boolean onCreateOptionsMenu(Menu menu)
359
  {
360
    MenuInflater inflater = this.getMenuInflater();
361
    inflater.inflate(R.menu.options, menu);
362
    return true;
363
  }
364
 
365
  /*
366
   * (non-Javadoc)
367
   *
368
   * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
369
   */
370
  @Override
371
  public boolean onOptionsItemSelected(MenuItem item)
372
  {
17 PointedEar 373
    /* Handle item selection */
15 PointedEar 374
    switch (item.getItemId())
375
    {
376
      case R.id.item_options_update:
17 PointedEar 377
        /*
378
         * Request the update service to run a thread to fetch the rates from
379
         * the Web (project requirement)
380
         */
381
        Intent intent = new Intent(this, UpdateService.class);
382
        intent.setAction(UpdateService.ACTION_UPDATE);
16 PointedEar 383
 
17 PointedEar 384
        /*
385
         * FIXME: Not thread-safe!
386
         * Get the activity context from the intent directly instead
387
         */
388
        UpdateService.setActivityContext(this);
15 PointedEar 389
 
17 PointedEar 390
        this.startService(intent);
16 PointedEar 391
        return true;
392
 
15 PointedEar 393
      default:
394
        return super.onOptionsItemSelected(item);
395
    }
8 PointedEar 396
  }
17 PointedEar 397
 
398
  /**
399
   * @return the conversionRates
400
   */
401
  public HashMap<String, ConversionData> getConversionRates()
402
  {
403
    return this.conversionRates;
404
  }
405
 
406
  /**
407
   * @param conversionRates
408
   *          the conversionRates to set
409
   */
410
  public void setConversionRates(HashMap<String, ConversionData> conversionRates)
411
  {
412
    this.conversionRates = conversionRates;
413
  }
414
 
415
  /**
416
   * @return the database
417
   */
418
  public CurrenciesDatabase getDatabase()
419
  {
420
    return this.database;
421
  }
5 PointedEar 422
}