package org.greenstone.android.tipple.base; import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Locale; import android.location.LocationManager; import android.os.Bundle; import android.os.Environment; import android.preference.PreferenceManager; import android.speech.tts.TextToSpeech; import android.speech.tts.TextToSpeech.OnInitListener; import android.text.method.ScrollingMovementMethod; import android.util.Log; import android.view.Gravity; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.AssetManager; import android.location.LocationListener; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.LinearLayout.LayoutParams; import android.widget.TextView; import org.greenstone.android.tipple.R; import org.mapsforge.android.maps.MapActivity; import org.mapsforge.android.maps.MapView; public class TippleActivity extends MapActivity implements OnInitListener { enum TextAudioModeEnum { TEXT_ONLY, TEXT_PLUS_AUDIO, AUDIO_ONLY, AUDIO_PLUS_TEXT }; // File storage public static String geodataDirectory; public static String logDirectory; public static String audioDirectory; // Preferences public static SharedPreferences sharedPreferences; public static boolean centreOnGPSLocation; public static boolean showScaleBar; public static boolean showSights; public static boolean showUserTrail; public static TextAudioModeEnum textAudioMode; // Logging public static TippleLog log; // Views protected TextView longlat_view_; protected MapView map_view_; protected TextView text_view_; protected FrameLayout text_map_composite_; protected AudioPlayerView audio_player_view_; protected TipLocationManager tip_location_manager_; protected ArrayList locations_ = null; protected ArrayList user_trail_ = null; protected String user_trail_filename_ = null; // Text to Speech protected TextToSpeech tts_ = null; protected LocationManager location_manager_ = null; protected LocationListener location_listener_ = null; // Request codes protected final int TTS_DATA_CHECK = 0; private static final int SELECT_LOG_FILE = 1; protected boolean assetToExternalStorage(String asset_filename, String external_storage_filename) { boolean status = true; try { File external_storage_file = new File(external_storage_filename); if (!external_storage_file.exists()) { // Need to create the /sdcard version AssetManager assetManager = getAssets(); InputStream ais = assetManager.open(asset_filename); // ais = asset input stream FileOutputStream fos = new FileOutputStream(external_storage_file); // fos = file output stream byte [] buffer = new byte[1024]; int buflen; while ((buflen = ais.read(buffer))>0) { fos.write(buffer,0,buflen); } ais.close(); fos.close(); } } catch (Exception e) { e.printStackTrace(); status = false; } return status; } protected boolean initTippleStore(String location) { // Locate map data directory File external_root_file = Environment.getExternalStorageDirectory(); String external_root = external_root_file.getAbsolutePath(); String tipple_store_dir = external_root + "/tipple-store"; geodataDirectory = tipple_store_dir + "/geodata/"; logDirectory = tipple_store_dir + "/logs/"; audioDirectory = tipple_store_dir + "/audio/"; File tipple_store_file = new File(tipple_store_dir); if (!tipple_store_file.exists()) { if (!tipple_store_file.mkdir()) { System.err.println("Failed to create directory: " + tipple_store_dir); return false; } } File geodataDirFile = new File(geodataDirectory); if (!geodataDirFile.exists()) { if (!geodataDirFile.mkdir()) { System.err.println("Failed to create directory: " + geodataDirectory); return false; } } File logDirFile = new File(logDirectory); if (!logDirFile.exists()) { if (!logDirFile.mkdir()) { System.err.println("Failed to create directory: " + logDirectory); return false; } } File audioDirFile = new File(audioDirectory); if (!audioDirFile.exists()) { if (!audioDirFile.mkdir()) { System.err.println("Failed to create directory: " + audioDirectory); return false; } } // dig out the audio files String[] audio_filenames = { "BeepMorseSonar.wav","Ding.wav","DingExtended.wav" }; for (String audio_filename: audio_filenames) { String audio_asset_filename = "audio/" + audio_filename; String audio_exstore_filename = audioDirectory + audio_filename; if (!assetToExternalStorage(audio_asset_filename,audio_exstore_filename)) { System.err.println("Failed to transfer asset " + audio_asset_filename + " to " + audio_exstore_filename); return false; } } if ((location != null) && (!location.equals(""))) { // get out map and XML location file String map_asset_filename = "geodata/" + location + ".map"; String map_exstore_filename = geodataDirectory + location + ".map"; if (!assetToExternalStorage(map_asset_filename,map_exstore_filename)) { System.err.println("Failed to transfer asset " + map_asset_filename + " to " + map_exstore_filename); return false; } String loc_asset_filename = "geodata/" + location + ".loc"; String loc_exstore_filename = geodataDirectory + location + ".loc"; if (!assetToExternalStorage(loc_asset_filename,loc_exstore_filename)) { System.err.println("Failed to transfer asset " + loc_asset_filename + " to " + loc_exstore_filename); return false; } } return true; } protected boolean initTippleStore() { return initTippleStore(null); } protected TextView createLongLatView() { // Lat,Long line at top TextView longlat_view = new TextView(this); longlat_view.setText("(Long,Lat): "); LayoutParams longlat_view_layout = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 35, 0); longlat_view.setLayoutParams(longlat_view_layout); return longlat_view; } protected MapView createMapView(String map_filename) { // Map view in middle MapView map_view = new MapView(this); map_view.setClickable(true); map_view.setBuiltInZoomControls(true); String full_map_filename = geodataDirectory + map_filename; map_view.setMapFile(full_map_filename); LayoutParams map_view_layout = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1); map_view.setLayoutParams(map_view_layout); return map_view; } protected MapView createMapViewFromAsset(String map_filename) { // Transfer asset to file in dataDirectory if it does not already exist String asset_filename = "geodata" + File.separator + map_filename; String external_storage_filename = geodataDirectory + map_filename; assetToExternalStorage(asset_filename,external_storage_filename); return createMapView(map_filename); } protected TextView createTextView() { // Text view in middle (ultimately on top of map view) TextView text_view = new TextView(this); LayoutParams text_view_layout = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1); text_view.setLayoutParams(text_view_layout); text_view.setGravity(Gravity.BOTTOM|Gravity.FILL_HORIZONTAL); text_view.setPadding(12, 12, 12, 12); text_view.setTextColor(0xffffffff); text_view.setBackgroundColor(0xCC000000); text_view.setTextSize(20.0f); text_view.setVerticalScrollBarEnabled(true); text_view.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET); text_view.setMovementMethod(new ScrollingMovementMethod()); text_view.setVisibility(View.INVISIBLE); return text_view; } protected FrameLayout compositTextViewOnMapView(MapView map_view, TextView text_view) { FrameLayout frame_layout = new FrameLayout(this); LayoutParams view_layout = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1); frame_layout.setLayoutParams(view_layout); frame_layout.addView(map_view); frame_layout.addView(text_view); return frame_layout; } protected AudioPlayerView createAudioPlayerView() { // Player at the bottom AudioPlayerView audio_player_view = new AudioPlayerView(this, text_view_); LayoutParams audio_player_layout = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,100, 0); audio_player_view.setLayoutParams(audio_player_layout); return audio_player_view; } protected void refreshPreferences() { // Restore preferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); //shared_preferences_ = getPreferences(MODE_PRIVATE); showScaleBar = sharedPreferences.getBoolean("showScaleBar", false); centreOnGPSLocation = sharedPreferences.getBoolean("centreOnGPSLoc", false); showSights = sharedPreferences.getBoolean("showSights", true); showUserTrail = sharedPreferences.getBoolean("showUserTrail", false); String textAudioModeStr = sharedPreferences.getString("textAudioMode", "AUDIO_PLUS_TEXT"); textAudioMode = Enum.valueOf(TextAudioModeEnum.class, textAudioModeStr); } protected void onCreateXXX(Bundle savedInstanceState) { System.err.println("*** TippleActivity::onCreate()"); super.onCreate(savedInstanceState); if (!initTippleStore("hamilton")) { System.err.println("Failed to initialize TippleStore on sdcard. Quiting"); onDestroy(); } // Set up logging log = new TippleLog(this,logDirectory); log.optStartLog(); // "refresh" preferences here so views can be configured correctly // and ensure showUserTrail is reset to off (as not log file has been selected yet) refreshPreferences(); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putBoolean("showUserTrail",false); // Set up Text to Speech Intent checkIntent = new Intent(); checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA); startActivityForResult(checkIntent, TTS_DATA_CHECK); //startActivityForResult(new Intent(this, LogFileBrowser.class), SELECT_LOG_FILE); // Screen dived into: // Top: GPS location // Middle: Map view // Bottom: Media player LinearLayout linearLayout = new LinearLayout(this); linearLayout.setOrientation(LinearLayout.VERTICAL); longlat_view_ = createLongLatView(); //map_view_ = createMapView("new-zealand.map"); map_view_ = createMapViewFromAsset("hamilton.map"); text_view_ = createTextView(); text_map_composite_ = compositTextViewOnMapView(map_view_,text_view_); audio_player_view_ = createAudioPlayerView(); linearLayout.addView(longlat_view_); linearLayout.addView(text_map_composite_); linearLayout.addView(audio_player_view_); setContentView(linearLayout); } @Override protected void onResume() { System.err.println("*** TippleActivity::onResume()"); super.onResume(); refreshPreferences(); audio_player_view_.refreshView(); map_view_.setScaleBar(showScaleBar); if (tip_location_manager_ != null) { if (showSights) { //tip_location_manager_.createTourLocationsOverlay(map_view_,locations_); tip_location_manager_.addTourLocations(map_view_); } else { tip_location_manager_.removeTourLocations(map_view_); } if (user_trail_filename_ != null) { if (showUserTrail) { //tip_location_manager_.createLogRouteLocationsOverlay(map_view_,user_trail_); tip_location_manager_.addLogRouteLocations(map_view_); } else { tip_location_manager_.removeLogRouteLocations(map_view_); } } } } protected void onActivityResult(int requestCode, int resultCode, Intent data) { System.err.println("*** TippleActivity::onActivityResult(), requestCode: " + requestCode); if (requestCode == TTS_DATA_CHECK) { if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) { // success, create the TTS instance tts_ = new TextToSpeech(this, (TextToSpeech.OnInitListener) this); tts_.setLanguage(Locale.UK); // now TTS initialized, init TTS aware place-locations String loc_filename = geodataDirectory + "hamilton.loc"; tip_location_manager_ = new TipLocationManager(this,audio_player_view_,tts_); locations_ = tip_location_manager_.loadTour(loc_filename); tip_location_manager_.createTourLocationsOverlay(map_view_,locations_); // Set up a callback method for handling GPS location updates connected with our place-locations location_manager_ = (LocationManager)getSystemService(Context.LOCATION_SERVICE); location_listener_ = new TippleLocationListener(this,map_view_,longlat_view_,tip_location_manager_, locations_); location_manager_.requestLocationUpdates(LocationManager.GPS_PROVIDER,0, 0, location_listener_); } else { // missing data, install it Intent installIntent = new Intent(); installIntent.setAction( TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA); startActivity(installIntent); } } else if (requestCode == SELECT_LOG_FILE) { if (resultCode == RESULT_OK) { if (data != null && data.getStringExtra("logFile") != null) { if (user_trail_filename_ != null) { // have a previously loaded route => scrub it tip_location_manager_.removeLogRouteLocations(map_view_); user_trail_filename_ = null; } // set up route overlay user_trail_filename_ = data.getStringExtra("logFile"); user_trail_ = tip_location_manager_.loadUserTrail(user_trail_filename_); tip_location_manager_.createLogRouteLocationsOverlay(map_view_,user_trail_); } } else if (resultCode == RESULT_CANCELED) { // nothing to do } } } @Override public void onInit(int status) { System.err.println("*** TippleActivity::onInit(), status (zero == good): " + status); if (status == TextToSpeech.SUCCESS) { Log.d("TippleActivity::onInit()","Text-to-speech engine initialized"); } else if (status == TextToSpeech.ERROR){ Log.e("TippleActivity::onInit()","Text-to-speech engine failed initialized"); System.err.println("Error occured while initializing text-to-speech engine"); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.options_menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_info: startActivity(new Intent(this, InfoView.class)); return true; case R.id.menu_preferences: startActivity(new Intent(this, EditPreferences.class)); return true; case R.id.menu_logfile: startActivityForResult(new Intent(this, TippleLogFileBrowser.class), SELECT_LOG_FILE); return true; default: return false; } } @Override protected void onStop() { System.err.println("*** TippleActivity::onStop()"); super.onStop(); // Is this needed? // Go through an Editor object to make preference changes stick SharedPreferences.Editor editor = sharedPreferences.edit(); editor.commit(); } @Override protected void onDestroy() { System.err.println("*** TippleActivity::onDestroy()"); super.onDestroy(); tts_.shutdown(); tts_ = null; // Switch off location updates if (location_manager_ != null) { if (location_listener_ != null) { location_manager_.removeUpdates(location_listener_); location_listener_ = null; } location_manager_ = null; user_trail_filename_ = null; } TipLocationManager.stopOverlayThreads(); log.optStopLog(); } }