Java tutorial
/******************************************************************************* * Copyright (C) 2010 Atlas of Living Australia * All Rights Reserved. * * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. ******************************************************************************/ package au.org.ala.fielddata.mobile; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import android.annotation.TargetApi; import android.app.AlertDialog; import android.app.Dialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.pm.PackageManager; import android.location.LocationManager; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.provider.Settings; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.app.FragmentTransaction; import android.support.v4.content.LocalBroadcastManager; import android.support.v4.view.ViewPager; import android.util.Log; import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; import au.org.ala.fielddata.mobile.dao.GenericDAO; import au.org.ala.fielddata.mobile.dao.RecordDAO; import au.org.ala.fielddata.mobile.model.Record; import au.org.ala.fielddata.mobile.model.User; import au.org.ala.fielddata.mobile.nrmplus.R; import au.org.ala.fielddata.mobile.pref.EditPreferences; import au.org.ala.fielddata.mobile.pref.Preferences; import au.org.ala.fielddata.mobile.service.FieldDataService; import au.org.ala.fielddata.mobile.service.FieldDataServiceClient; import au.org.ala.fielddata.mobile.service.LocationServiceHelper; import au.org.ala.fielddata.mobile.service.SurveyDownloadService; import au.org.ala.fielddata.mobile.ui.MenuHelper; import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.ActionBar.Tab; import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.actionbarsherlock.view.Window; /** * This class is the main activity for the Mobile Field Data application. */ public class MobileFieldDataDashboard extends SherlockFragmentActivity implements OnSharedPreferenceChangeListener { public static final String SELECTED_TAB_BUNDLE_KEY = "tab"; public static final int RECORDS_TAB_INDEX = 2; private static final String GPS_QUESTION_BUNDLE_KEY = "gps"; private static final String REDIRECTED_TO_LOGIN_BUNDLE_KEY = "loginRedirect"; @TargetApi(11) static public <T> void executeAsyncTask(AsyncTask<T, ?, ?> task, T... params) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); } else { task.execute(params); } } protected Dialog splashDialog; private Preferences preferences; private TextView status; private ViewPager viewPager; private BroadcastReceiver broadcastReceiver; private boolean redirectedToLogin; /** * Tracks whether we have asked the user if they want to turn on their * GPS */ private boolean askedAboutGPS; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Only show the splash screen on startup, and if the variant has been configured to do so. if (savedInstanceState == null && getResources().getBoolean(R.bool.show_splash_screen)) { showSplashScreen(getResources().getInteger(R.integer.splash_screen_duration)); } requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); setContentView(R.layout.activity_mobile_data_dashboard); getSupportActionBar().setDisplayUseLogoEnabled(true); getSupportActionBar().setLogo(R.drawable.ic_launcher); preferences = new Preferences(this); PreferenceManager.setDefaultValues(getApplicationContext(), R.xml.preference1, true); PreferenceManager.setDefaultValues(getApplicationContext(), R.xml.network_preferences, true); status = (TextView) findViewById(R.id.status); getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); String[] titles = getResources().getStringArray(R.array.tab_titles); viewPager = (ViewPager) findViewById(R.id.tabContent); TabsAdapter tabsAdapter = new TabsAdapter(this, viewPager); viewPager.setAdapter(tabsAdapter); int selectedTabIndex = 0; if (savedInstanceState != null) { askedAboutGPS = savedInstanceState.getBoolean(GPS_QUESTION_BUNDLE_KEY); redirectedToLogin = savedInstanceState.getBoolean(REDIRECTED_TO_LOGIN_BUNDLE_KEY); selectedTabIndex = savedInstanceState.getInt(SELECTED_TAB_BUNDLE_KEY, 0); } selectedTabIndex = getIntent().getIntExtra(SELECTED_TAB_BUNDLE_KEY, selectedTabIndex); for (int i = 0; i < titles.length; i++) { String title = titles[i]; ActionBar.Tab tab = getSupportActionBar().newTab(); tab.setText(title); tab.setTabListener(tabsAdapter); getSupportActionBar().addTab(tab); } getSupportActionBar().setSelectedNavigationItem(selectedTabIndex); } protected void showSplashScreen(int duration) { splashDialog = new Dialog(this, R.style.SplashScreen) { @Override public void onBackPressed() { removeSplashScreen(); MobileFieldDataDashboard.this.onBackPressed(); } }; splashDialog.setContentView(R.layout.splash_screen); splashDialog.setCancelable(false); splashDialog.show(); // Set Runnable to remove splash screen final Handler handler = new Handler(); handler.postDelayed(new Runnable() { public void run() { removeSplashScreen(); } }, duration); } /** * Removes the Dialog that displays the splash screen */ protected void removeSplashScreen() { if (splashDialog != null) { splashDialog.dismiss(); splashDialog = null; } } public static class TabsAdapter extends FragmentPagerAdapter implements ActionBar.TabListener, ViewPager.OnPageChangeListener { private String[] tabClasses = { SurveyListFragment.class.getName(), SpeciesListActivity.class.getName(), ViewSavedRecordsActivity.class.getName() }; private boolean[] needsReload = new boolean[tabClasses.length]; private SherlockFragmentActivity ctx; private ViewPager viewPager; private Fragment current; public TabsAdapter(SherlockFragmentActivity ctx, ViewPager viewPager) { super(ctx.getSupportFragmentManager()); this.ctx = ctx; this.viewPager = viewPager; Arrays.fill(needsReload, false); viewPager.setOnPageChangeListener(this); } public void onTabSelected(Tab tab, FragmentTransaction ft) { if (viewPager.getCurrentItem() != tab.getPosition()) { viewPager.setCurrentItem(tab.getPosition()); } } public void onTabUnselected(Tab tab, FragmentTransaction ft) { } public void onTabReselected(Tab tab, FragmentTransaction ft) { } @Override public Fragment getItem(int arg0) { return Fragment.instantiate(ctx, tabClasses[arg0]); } @Override public Object instantiateItem(ViewGroup container, int position) { Object f = super.instantiateItem(container, position); current = (Fragment) f; if (needsReload[position]) { reload(current, position); } return f; } public void reload() { Arrays.fill(needsReload, true); reload(current, viewPager.getCurrentItem()); } private void reload(Fragment f, int position) { if (f instanceof Reloadable) { ((Reloadable) current).reload(); needsReload[position] = false; } } @Override public int getCount() { return tabClasses.length; } public void onPageScrollStateChanged(int arg0) { } public void onPageScrolled(int arg0, float arg1, int arg2) { } public void onPageSelected(int arg0) { ctx.getSupportActionBar().setSelectedNavigationItem(arg0); } } @Override public void onStart() { super.onStart(); if (isLoggedIn()) { if (!preferences.getAskedAboutWifi()) { showWifiPreferenceDialog(); } if (!askedAboutGPS) { if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS)) { LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { showNoGpsDialog(); } } } } } @Override public void onDestroy() { super.onDestroy(); Intent locationIntent = new Intent(MobileFieldDataDashboard.this, LocationServiceHelper.class); stopService(locationIntent); } private void showNoGpsDialog() { final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Enable GPS?").setMessage( "The GPS on this device is currently disabled, do you want to enable it? \nEnabling GPS will allow accurate survey locations to be recorded.") .setCancelable(false).setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick(final DialogInterface dialog, final int id) { startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)); } }).setNegativeButton("No", new DialogInterface.OnClickListener() { public void onClick(final DialogInterface dialog, final int id) { dialog.cancel(); } }); builder.create().show(); askedAboutGPS = true; } private void showWifiPreferenceDialog() { final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Uploading records").setMessage( "Do you want to use your phone's data connection to upload records? \nIf you select 'No' saved records will only be uploaded when your phone is connected to a WIFI network.") .setCancelable(false).setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick(final DialogInterface dialog, final int id) { preferences.setUploadOverWifiOnly(false); } }).setNegativeButton("No", new DialogInterface.OnClickListener() { public void onClick(final DialogInterface dialog, final int id) { preferences.setUploadOverWifiOnly(true); } }); builder.create().show(); preferences.setAskedAboutWifi(); } class Model { private User user; private String portal; public Model(User user, String portal) { this.user = user; this.portal = portal; } public User getUser() { return user; } public String getPortal() { return portal; } } class InitDataTask extends AsyncTask<Void, Void, Model> { @Override protected Model doInBackground(Void... params) { GenericDAO<User> userDAO = new GenericDAO<User>(getApplicationContext()); List<User> users = userDAO.loadAll(User.class); User user = null; if (users.size() > 0) { user = users.get(0); } return new Model(user, ""); } @Override protected void onPostExecute(Model model) { User user = model.getUser(); if (user != null) { getSupportActionBar().setSubtitle(Utils.bold("Welcome " + user.firstName + " " + user.lastName)); } } } class StatusTask extends AsyncTask<Void, Void, AppStatus> { @Override protected AppStatus doInBackground(Void... params) { return checkStatus(); } @Override protected void onPostExecute(AppStatus result) { if (result.isInitialised()) { if (result.isOnline()) { status.setText("Online"); } else { status.setText("Offline"); } } else { if (!result.isOnline()) { showConnectionError(); } else { redirectToLogin(); } } setSupportProgressBarIndeterminateVisibility(false); } } @Override protected void onResume() { super.onResume(); if (SurveyDownloadService.isDownloading()) { listenForSurveyDownload(); } SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); prefs.registerOnSharedPreferenceChangeListener(this); refreshPage(); // If the user has changed their login, we need to reload surveys/species from // the database. if (redirectedToLogin) { redirectedToLogin = false; reloadTabs(); } } @Override public void onPause() { super.onPause(); stopListeningForSurveyDownload(); removeSplashScreen(); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); prefs.unregisterOnSharedPreferenceChangeListener(this); } @Override public void onStop() { super.onStop(); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt(SELECTED_TAB_BUNDLE_KEY, getSupportActionBar().getSelectedNavigationIndex()); outState.putBoolean(GPS_QUESTION_BUNDLE_KEY, askedAboutGPS); outState.putBoolean(REDIRECTED_TO_LOGIN_BUNDLE_KEY, redirectedToLogin); } private void refreshPage() { // check if the preferences are set if not redirect if (preferences.getFieldDataServerHostName().equals("") || preferences.getFieldDataContextName().equals("")) { redirectToPreferences(); } else { setSupportProgressBarIndeterminateVisibility(true); executeAsyncTask(new InitDataTask()); executeAsyncTask(new StatusTask()); } } class AppStatus { private boolean online; private boolean initialised; public AppStatus(boolean initialised, boolean online) { this.online = online; this.initialised = initialised; } public boolean isOnline() { return online; } public boolean isInitialised() { return initialised; } } private AppStatus checkStatus() { boolean online = canAccessFieldDataServer(); boolean initialised = isLoggedIn(); return new AppStatus(initialised, online); } private void showConnectionError() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.initialisationErrorTitle); builder.setMessage(String.format(getResources().getString(R.string.initialisationError), preferences.getFieldDataServerUrl())); builder.setNegativeButton(R.string.close, new Dialog.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.show(); return; } private void redirectToPreferences() { Intent intent = new Intent(this, EditPreferences.class); startActivity(intent); } private void redirectToLogin() { redirectedToLogin = true; Intent intent = new Intent(this, LoginActivity.class); startActivity(intent); } private boolean isLoggedIn() { String sessionKey = preferences.getFieldDataSessionKey(); return sessionKey != null; } private boolean canAccessFieldDataServer() { boolean success = false; String fieldDataServer = preferences.getFieldDataServerHostName(); try { FieldDataServiceClient service = new FieldDataServiceClient(this); success = service.ping(5000); if (!success) { if (Utils.DEBUG) { Log.i("Status", "Field data server at: " + fieldDataServer + " is not reachable"); } } } catch (Exception e) { if (Utils.DEBUG) { Log.e("Error", "Unable to location field data server at: " + preferences.getFieldDataServerHostName(), e); } } return success; } private MenuItem newRecordMenuItem; @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = new MenuInflater(this); inflater.inflate(R.menu.common_menu_items, menu); inflater.inflate(R.menu.dashboard_menu, menu); newRecordMenuItem = menu.add("New Record"); newRecordMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.sync) { RecordDAO recordDAO = new RecordDAO(this); if (recordDAO.count(Record.class) > 0) { new AlertDialog.Builder(this).setTitle("Unable to reload surveys") .setMessage("Please upload your saved Records and try again.").setPositiveButton("OK", null) .show(); } else { setSupportProgressBarIndeterminateVisibility(true); Intent downloadSurveys = new Intent(MobileFieldDataDashboard.this, SurveyDownloadService.class); listenForSurveyDownload(); startService(downloadSurveys); } return true; } else if (item == newRecordMenuItem) { Intent intent = new Intent(this, CollectSurveyData.class); intent.putExtra(CollectSurveyData.SURVEY_BUNDLE_KEY, new Preferences(this).getCurrentSurvey()); startActivity(intent); } else if (item.getItemId() == R.id.login_screen) { redirectToLogin(); } else { return new MenuHelper(this).handleMenuItemSelection(item); } return true; } private void listenForSurveyDownload() { broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { boolean success = intent.getBooleanExtra(SurveyDownloadService.RESULT_EXTRA, false); if (success) { Toast.makeText(MobileFieldDataDashboard.this, "Surveys refreshed", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(MobileFieldDataDashboard.this, "Refresh failed - please check your network", Toast.LENGTH_LONG).show(); } reloadTabs(); setSupportProgressBarIndeterminateVisibility(false); stopListeningForSurveyDownload(); } }; IntentFilter downloadFilter = new IntentFilter(SurveyDownloadService.FINISHED_ACTION); LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, downloadFilter); } private void stopListeningForSurveyDownload() { if (broadcastReceiver != null) { LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver); } } public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (key.equals("serverHostName") || key.equals("contextName")) { preferences.setFieldDataSessionKey(null); } } private void reloadTabs() { ((TabsAdapter) viewPager.getAdapter()).reload(); } }