source: other-projects/tipple-android/tipple-lib/src/org/greenstone/android/tipple/base/TippleActivity.java@ 29186

Last change on this file since 29186 was 29186, checked in by ak19, 10 years ago

Tidy up on how the .loc and .json files are found

File size: 19.8 KB
Line 
1package org.greenstone.android.tipple.base;
2
3import java.io.BufferedWriter;
4import java.io.File;
5import java.io.FileOutputStream;
6import java.io.FileWriter;
7import java.io.InputStream;
8import java.util.ArrayList;
9import java.util.HashMap;
10import java.util.Locale;
11
12import android.location.Criteria;
13import android.location.LocationManager;
14import android.os.Environment;
15import android.preference.PreferenceManager;
16import android.speech.tts.TextToSpeech;
17import android.speech.tts.TextToSpeech.OnInitListener;
18import android.text.method.ScrollingMovementMethod;
19import android.util.Log;
20import android.view.Gravity;
21import android.view.Menu;
22import android.view.MenuItem;
23import android.view.View;
24import android.view.ViewGroup;
25import android.app.Activity;
26import android.app.AlertDialog;
27import android.content.Context;
28import android.content.DialogInterface;
29import android.content.Intent;
30import android.content.SharedPreferences;
31import android.content.res.AssetManager;
32import android.location.LocationListener;
33import android.widget.FrameLayout;
34import android.widget.LinearLayout;
35import android.widget.Toast;
36import android.widget.LinearLayout.LayoutParams;
37import android.widget.TextView;
38
39
40import org.greenstone.android.tipple.R;
41import org.json1.JSONStringer;
42import org.json1.JSONWriter;
43import org.mapsforge.android.maps.MapActivity;
44import org.mapsforge.android.maps.MapView;
45
46
47public class TippleActivity extends MapActivity implements OnInitListener
48{
49 private final boolean debug_mode = true;
50
51 enum TextAudioModeEnum { TEXT_ONLY, TEXT_PLUS_AUDIO, AUDIO_ONLY, AUDIO_PLUS_TEXT };
52
53
54
55 private static boolean first_time_starting = true;
56
57 // File storage
58 protected static String geodataDirectory;
59 protected static String logDirectory;
60 protected static String audioDirectory;
61
62 // Preferences
63 public static SharedPreferences sharedPreferences;
64 public static boolean centreOnGPSLocation;
65 public static boolean showScaleBar;
66 public static boolean showSights;
67 public static boolean showUserTrail;
68 public static TextAudioModeEnum textAudioMode;
69
70 // Logging
71 public static TippleLog log;
72
73 // Views
74 protected TextView longlat_view_;
75 protected MapView map_view_;
76 protected TextView text_view_;
77 protected FrameLayout text_map_composite_;
78 protected AudioPlayerView audio_player_view_;
79
80 protected ArrayList<TipLocation> user_trail_ = null;
81 protected String user_trail_filename_ = null;
82
83 // Text to Speech
84 protected TextToSpeech tts_ = null;
85
86 protected TipLocationManager tip_location_manager_ = null;
87 protected LocationManager location_manager_ = null;
88 protected LocationListener location_listener_ = null;
89
90 // Request codes
91 protected final int TTS_DATA_CHECK = 0;
92 private static final int SELECT_LOG_FILE = 1;
93
94 public static String DEFAULT_LOC_FILE = "hamilton";
95 //public static String DEFAULT_LOC_FILE = "fieldays";
96
97 /*
98 * GPS coords point to ==> uni rec centre
99 * TODO: Rather than hardcode a "starting point" location as shown below, get the last
100 * known location of the user.
101 */
102
103
104 // University ??
105 private static final double DEFAULT_NO_GPS_LONGITUDE = 175.3141;
106 private static final double DEFAULT_NO_GPS_LATITUDE = -37.7876;
107
108 // Mystery creek -- centre of fieldays innovation tent
109 //private static final double DEFAULT_NO_GPS_LONGITUDE = 175.355012;
110 //private static final double DEFAULT_NO_GPS_LATITUDE = -37.872816;
111
112 public static String getGeodataDirectory()
113 {
114 return geodataDirectory;
115 }
116
117 public static String getLogDirectory()
118 {
119 return logDirectory;
120 }
121
122 public static String getAudioDirectory()
123 {
124 return audioDirectory;
125 }
126
127 /**
128 *
129 * @param asset_filename
130 * @param external_storage_filename
131 * @param debug_mode If this is set to true, then we will always push out new files to the SD card on Tipple launch
132 * @return
133 */
134 protected boolean assetToExternalStorage(String asset_filename, String external_storage_filename, boolean debug_mode)
135 {
136 boolean status = true;
137
138 try {
139
140 File external_storage_file = new File(external_storage_filename);
141 if (!external_storage_file.exists() || (debug_mode)) {
142 // Need to create the /sdcard version
143
144 AssetManager assetManager = getAssets();
145
146 InputStream ais = assetManager.open(asset_filename); // ais = asset input stream
147 FileOutputStream fos = new FileOutputStream(external_storage_file); // fos = file output stream
148
149 byte [] buffer = new byte[1024];
150
151 int buflen;
152 while ((buflen = ais.read(buffer))>0) {
153 fos.write(buffer,0,buflen);
154 }
155
156 ais.close();
157 fos.close();
158 }
159
160 }
161 catch (Exception e) {
162 e.printStackTrace();
163 status = false;
164 }
165
166 return status;
167 }
168
169 protected boolean initTippleStore(String location)
170 {
171 DEFAULT_LOC_FILE = location;
172
173 // Locate map data directory
174 File external_root_file = Environment.getExternalStorageDirectory();
175 String external_root = external_root_file.getAbsolutePath();
176 String tipple_store_dir = external_root + "/tipple-store";
177
178 geodataDirectory = tipple_store_dir + "/geodata/";
179 logDirectory = tipple_store_dir + "/logs/";
180 audioDirectory = tipple_store_dir + "/audio/";
181
182 File tipple_store_file = new File(tipple_store_dir);
183 if (!tipple_store_file.exists()) {
184 if (!tipple_store_file.mkdir()) {
185
186 String error = "Failed to create directory: " + tipple_store_dir;
187
188 System.err.println(error);
189 Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
190
191 return false;
192 }
193 }
194
195 File geodataDirFile = new File(geodataDirectory);
196 if (!geodataDirFile.exists()) {
197 if (!geodataDirFile.mkdir()) {
198
199 String error = "Failed to create directory: " + geodataDirectory;
200
201 System.err.println(error);
202 Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
203
204 return false;
205 }
206 }
207
208 File logDirFile = new File(logDirectory);
209 if (!logDirFile.exists()) {
210 if (!logDirFile.mkdir()) {
211
212 String error = "Failed to create directory: " + logDirectory;
213
214 System.err.println(error);
215 Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
216
217 return false;
218 }
219 }
220
221 File audioDirFile = new File(audioDirectory);
222 if (!audioDirFile.exists()) {
223 if (!audioDirFile.mkdir()) {
224
225 String error = "Failed to create directory: " + audioDirectory;
226
227 System.err.println(error);
228 Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
229
230 return false;
231 }
232 }
233
234 // dig out the audio files
235 String[] audio_filenames = { "BeepMorseSonar.wav","Ding.wav","DingExtended.wav" };
236 for (String audio_filename: audio_filenames) {
237 String audio_asset_filename = "audio/" + audio_filename;
238 String audio_exstore_filename = audioDirectory + audio_filename;
239
240 if (!assetToExternalStorage(audio_asset_filename,audio_exstore_filename,debug_mode)) {
241
242
243 String error = "Failed to transfer asset " + audio_asset_filename + " to " + audio_exstore_filename;
244
245 System.err.println(error);
246 Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
247
248 return false;
249 }
250 }
251
252 String loc_asset_filename = "geodata/" + DEFAULT_LOC_FILE + ".loc";
253 String loc_exstore_filename = geodataDirectory + DEFAULT_LOC_FILE + ".loc";
254
255 if (!assetToExternalStorage(loc_asset_filename,loc_exstore_filename,debug_mode)) {
256
257 String error = "Failed to transfer asset " + loc_asset_filename + " to " + loc_exstore_filename;
258
259 System.err.println(error);
260 Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
261
262 return false;
263 }
264
265 return true;
266 }
267
268 protected boolean initTippleStore()
269 {
270 return initTippleStore(null);
271 }
272
273
274 protected TextView createLongLatView()
275 {
276 // Lat,Long line at top
277 TextView longlat_view = new TextView(this);
278 longlat_view.setText("(Long,Lat): ");
279
280 LayoutParams longlat_view_layout
281 = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 35, 0);
282 longlat_view.setLayoutParams(longlat_view_layout);
283
284 return longlat_view;
285 }
286
287
288
289
290 protected MapView createMapView(String map_filename)
291 {
292
293 // Map view in middle
294 MapView map_view = new MapView(this);
295 map_view.setClickable(true);
296 map_view.setBuiltInZoomControls(true);
297 String full_map_filename = geodataDirectory + map_filename;
298 //String full_map_filename = geodataDirectory + "mymap.map";
299
300 map_view.setMapFile(new File(full_map_filename));
301
302 LayoutParams map_view_layout
303 = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
304 ViewGroup.LayoutParams.WRAP_CONTENT, 1);
305
306 map_view.setLayoutParams(map_view_layout);
307
308
309 return map_view;
310 }
311
312 protected MapView createMapViewFromAsset(String map_filename)
313 {
314 // Transfer asset to file in dataDirectory if it does not already exist
315
316 String asset_filename = "geodata" + File.separator + map_filename;
317 String external_storage_filename = geodataDirectory + map_filename;
318
319 assetToExternalStorage(asset_filename,external_storage_filename,debug_mode);
320
321 return createMapView(map_filename);
322
323 }
324
325 protected TextView createTextView()
326 {
327 // Text view in middle (ultimately on top of map view)
328 TextView text_view = new TextView(this);
329
330 LayoutParams text_view_layout
331 = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
332 ViewGroup.LayoutParams.WRAP_CONTENT, 1);
333 text_view.setLayoutParams(text_view_layout);
334
335 text_view.setGravity(Gravity.BOTTOM|Gravity.FILL_HORIZONTAL);
336
337 text_view.setPadding(12, 12, 12, 12);
338 text_view.setTextColor(0xffffffff);
339 text_view.setBackgroundColor(0xCC000000);
340 text_view.setTextSize(20.0f);
341
342 text_view.setVerticalScrollBarEnabled(true);
343 text_view.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
344
345 text_view.setMovementMethod(new ScrollingMovementMethod());
346
347 text_view.setVisibility(View.INVISIBLE);
348
349 return text_view;
350 }
351
352 protected FrameLayout compositTextViewOnMapView(MapView map_view, TextView text_view)
353 {
354 FrameLayout frame_layout = new FrameLayout(this);
355
356 LayoutParams view_layout
357 = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
358 ViewGroup.LayoutParams.WRAP_CONTENT, 1);
359
360 frame_layout.setLayoutParams(view_layout);
361 frame_layout.addView(map_view);
362 frame_layout.addView(text_view);
363
364 return frame_layout;
365 }
366
367 protected AudioPlayerView createAudioPlayerView()
368 {
369 // Player at the bottom
370 AudioPlayerView audio_player_view = new AudioPlayerView(this, text_view_);
371
372 LayoutParams audio_player_layout
373 = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT, 0);
374 audio_player_view.setLayoutParams(audio_player_layout);
375
376 return audio_player_view;
377 }
378
379
380 protected void refreshPreferences()
381 {
382
383
384 // Get the preferences and start storing them in our class's variables
385 sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
386
387 // set the default values, but only if the user hasn't changed the preferences themselves
388 PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
389
390 //shared_preferences_ = getPreferences(MODE_PRIVATE);
391 showScaleBar = sharedPreferences.getBoolean("showScaleBar", false);
392 centreOnGPSLocation = sharedPreferences.getBoolean("centreOnGPSLoc", false);
393
394 showSights = sharedPreferences.getBoolean("showSights", true);
395
396 showUserTrail = sharedPreferences.getBoolean("showUserTrail", false);
397
398 String textAudioModeStr = sharedPreferences.getString("textAudioMode", "AUDIO_PLUS_TEXT");
399 textAudioMode = Enum.valueOf(TextAudioModeEnum.class, textAudioModeStr);
400
401 }
402
403
404 @Override
405 protected void onResume()
406 {
407 System.err.println("*** TippleActivity::onResume()");
408
409 super.onResume();
410
411 refreshPreferences();
412 audio_player_view_.refreshView();
413
414
415 map_view_.getMapScaleBar().setShowMapScaleBar(showScaleBar);
416
417
418 /*
419 * The code below is REALLY bad, but I decided to comment it out instead.
420 * TippleActivity's onResume() gets called many times, and so TipLocationManager
421 * is actually adding lots and lots of tour locations.
422 */
423
424 /*
425
426 if (tip_location_manager_ != null) {
427 if (showSights) {
428 //tip_location_manager_.createTourLocationsOverlay(map_view_,locations_);
429 tip_location_manager_.addTourLocations();
430 }
431 else {
432 tip_location_manager_.removeTourLocations();
433 }
434
435 if (user_trail_filename_ != null) {
436
437 if (showUserTrail) {
438 //tip_location_manager_.createLogRouteLocationsOverlay(map_view_,user_trail_);
439 tip_location_manager_.addLogRouteLocations();
440 }
441 else {
442 tip_location_manager_.removeLogRouteLocations();
443 }
444 }
445 }
446
447 */
448
449 }
450
451 public void buildAlertMessageNoGps()
452 {
453 final AlertDialog.Builder builder = new AlertDialog.Builder(this);
454
455 builder.setMessage("Your GPS doesn't seem to be enabled. Enable it then re-launch Tipple.")
456 .setCancelable(false)
457 .setPositiveButton("Enable in Settings", new DialogInterface.OnClickListener()
458 {
459 @Override
460 public void onClick(DialogInterface dialog, int which)
461 {
462 startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
463 }
464 });
465
466 final AlertDialog alert = builder.create();
467 alert.show();
468 }
469
470 protected void onActivityResult(int requestCode, int resultCode, Intent data)
471 {
472 Log.d("TippleActivity::onActivityResult()", "requestCode: " + requestCode);
473
474 if (requestCode == TTS_DATA_CHECK) {
475 if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
476
477 if(first_time_starting)
478 {
479 // success, create the TTS instance
480 tts_ = new TextToSpeech(this, (TextToSpeech.OnInitListener) this);
481 tts_.setLanguage(Locale.UK);
482
483 // now TTS initialized, init TTS aware place-locations
484 String loc_filename = geodataDirectory + DEFAULT_LOC_FILE + ".loc";
485 System.err.println("*** loc filename = " + loc_filename);
486
487 tip_location_manager_ = new TipLocationManager(this, audio_player_view_, tts_, map_view_);
488 tip_location_manager_.createTipLocations(DEFAULT_NO_GPS_LONGITUDE, DEFAULT_NO_GPS_LATITUDE);
489 tip_location_manager_.createMapLocations();
490
491 // Set up a callback method for handling GPS location updates connected with our place-locations
492 location_manager_ = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
493 if ( !location_manager_.isProviderEnabled( LocationManager.GPS_PROVIDER ) )
494 {
495 buildAlertMessageNoGps();
496 }
497 else
498 {
499
500 location_listener_
501 = new TippleLocationListener(this,map_view_,longlat_view_,tip_location_manager_);
502
503 Criteria location_criteria_ = new Criteria();
504 location_criteria_.setAccuracy(Criteria.ACCURACY_LOW);
505 location_manager_.requestLocationUpdates(location_manager_.getBestProvider(location_criteria_, true), 0, 0, location_listener_);
506 }
507
508
509 tip_location_manager_.addMapLocations();
510
511 first_time_starting = false;
512
513 }
514
515 } else {
516 // missing data, install it
517 Intent installIntent = new Intent();
518 installIntent.setAction(
519 TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
520 startActivity(installIntent);
521 }
522 }
523
524 else if (requestCode == SELECT_LOG_FILE) {
525
526 if (resultCode == RESULT_OK) {
527 if (data != null && data.getStringExtra("logFile") != null) {
528 if (user_trail_filename_ != null) {
529 // have a previously loaded route => scrub it
530 tip_location_manager_.removeLogRouteLocations();
531 user_trail_filename_ = null;
532 }
533 // set up route overlay
534 user_trail_filename_ = data.getStringExtra("logFile");
535 user_trail_ = tip_location_manager_.loadUserTrail(user_trail_filename_);
536 tip_location_manager_.createLogRouteLocationsOverlay(user_trail_);
537 }
538 } else if (resultCode == RESULT_CANCELED) {
539 // nothing to do
540 }
541
542 }
543
544 }
545
546
547 @Override
548 public void onInit(int status)
549 {
550
551 Log.d("TippleActivity::onInit()", "Status (zero == good) is: " + status);
552
553 if (status == TextToSpeech.SUCCESS)
554 {
555 Log.d("TippleActivity::onInit()","Text-to-speech engine initialized");
556 }
557 else if (status == TextToSpeech.ERROR)
558 {
559 Log.e("TippleActivity::onInit()","Text-to-speech engine failed initialized");
560 }
561
562
563
564 }
565
566 @Override
567 public boolean onCreateOptionsMenu(Menu menu)
568 {
569 getMenuInflater().inflate(R.menu.options_menu, menu);
570 return true;
571 }
572
573 @Override
574 public boolean onOptionsItemSelected(MenuItem item)
575 {
576 int item_id = item.getItemId();
577
578 if (item_id == R.id.menu_info) {
579 startActivity(new Intent(this, InfoView.class));
580
581 return true;
582 }
583 else if (item_id == R.id.menu_preferences) {
584
585 startActivity(new Intent(this, EditPreferences.class));
586 return true;
587 }
588 else if (item_id == R.id.menu_logfile) {
589 startActivityForResult(new Intent(this, TippleLogFileBrowser.class), SELECT_LOG_FILE);
590 return true;
591 }
592 else {
593 return false;
594 }
595 }
596
597
598
599 @Override
600 protected void onStop()
601 {
602 System.err.println("*** TippleActivity::onStop()");
603 super.onStop();
604
605 // Is this needed?
606 // Go through an Editor object to make preference changes stick
607 SharedPreferences.Editor editor = sharedPreferences.edit();
608 editor.commit();
609
610 }
611
612 @Override
613 protected void onPause()
614 {
615 System.err.println("*** TippleActivity::onPause()");
616 super.onPause();
617 }
618
619 @Override
620 protected void onDestroy()
621 {
622 System.err.println("*** TippleActivity::onDestroy()");
623 super.onDestroy();
624
625 tts_.shutdown();
626 tts_ = null;
627
628 // Switch off location updates
629 if (location_manager_ != null) {
630
631 if (location_listener_ != null) {
632
633 location_manager_.removeUpdates(location_listener_);
634 location_listener_ = null;
635 }
636 location_manager_ = null;
637
638 user_trail_filename_ = null;
639 }
640
641
642 // http://stackoverflow.com/questions/3957253/what-is-this-log-when-i-coded-thread-stop
643 TipLocationManager.stopOverlayThreads();
644
645
646 log.optStopLog();
647 }
648
649}
Note: See TracBrowser for help on using the repository browser.