Android Open Source - Fast Main Activity






From Project

Back to project page Fast.

License

The source code is released under:

GNU General Public License

If you think the Android project Fast listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.example.fast;
//from   w w  w .j  av  a2s.c  om
import java.text.DecimalFormat;
import java.util.ArrayList;

import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.widget.DrawerLayout;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;

import com.example.fast.adapter.NavDrawerListAdapter;
import com.example.fast.heart.HeartFragment;
import com.example.fast.home.HomeFragment;
import com.example.fast.model.NavDrawerItem;
import com.example.fast.preferences.FastPreferences;
import com.example.fast.run.RunFragment;
import com.example.fast.share.ShareFragment;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks;
import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMapOptions;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;
import com.google.android.gms.plus.PlusClient;


/***
 *  Main activity.  Implements ConnectionCallbacks and OnConnectionFailedListener to 
 *  allow the use of Google APIs for Google+ posting.
 * @author michael
 *
 */
public class MainActivity extends FragmentActivity implements ConnectionCallbacks, OnConnectionFailedListener {
  
  /* DrawerLayout (Android) */
  private DrawerLayout mDrawerLayout; // Layout that holds the data for the Drawer object
  private ListView mDrawerList; // List for Drawer to show
  private ActionBarDrawerToggle mDrawerToggle; // handles drawer actions
  private CharSequence mDrawerTitle; // nav drawer title
  private CharSequence mTitle; // used to store app title
  private Integer backStackCount = 0;
  private Long milliseconds = 0L;

  /* Array Holding Drawer Strings, Icons, and Objects */
  private String[] navMenuTitles;
  private TypedArray navMenuIcons;
  private ArrayList<NavDrawerItem> navDrawerItems;
  private NavDrawerListAdapter adapter;
  
  /* Keeps track of current screen */
  private Fragment currentFragment;
  private HomeFragment homeFragment;
  private RunFragment runFragment;
  private HeartFragment heartFragment;
  private ShareFragment shareFragment;
  private MapFragment mapFragment;
  
  /* GPS Items */
  private GPSTracker gpsTracker;
  private Handler mHandler;
  private Handler timeHandler;
  private final int REFRESH_RATE = 1000 * 3; /* 3 second per update */
  private final int TIMER = 100;
  private Statistics statistics;
  private Location previousLocation;
  
  /* SQL Lite Database, schema */
  private Database database;
  public static final String TABLE_NAME = "android_metadata";
  
  /* Google+ */
  private ProgressDialog mConnectionProgressDialog;
  private PlusClient mPlusClient;
  private ConnectionResult mConnectionResult;
   
  /* Google Maps! */
  private GoogleMap map;
  private PolylineOptions path;
  
  /* Shared Preferences */
  private SharedPreferences prefs;
  private OnSharedPreferenceChangeListener listener;
  private boolean usingMetric;
  

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    /* Google Plus */
    mPlusClient = new PlusClient.Builder(this, this, this)
        .setActions("http://schemas.google.com/AddActivity",
            "http://schemas.google.com/BuyActivity")
        .build();

    mConnectionProgressDialog = new ProgressDialog(this);
    mConnectionProgressDialog.setMessage("Signing in...");
    
    
    /* SQL Lite */
    database = new Database(this);
  
    
    /* Setup GPS Tracking, timers */
    gpsTracker = new GPSTracker(this);
    mHandler =  new Handler();
    timeHandler = new Handler();
    gpsTracker.startUsingGPS();
    
    /* Statistics Handler */
    statistics = new Statistics();
    
    /* Preferences Handling */
    prefs = PreferenceManager.getDefaultSharedPreferences(this);
    usingMetric = prefs.getBoolean("metric", false);
    listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
        public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
          usingMetric = prefs.getBoolean("metric", false);    
      }
    };
    prefs.registerOnSharedPreferenceChangeListener(listener);
    
    
    /* Drawer Layout (Android) */
    mTitle = mDrawerTitle = getTitle();
    navMenuTitles = getResources().getStringArray(R.array.nav_drawer_items); 
    navMenuIcons = getResources().obtainTypedArray(R.array.nav_drawer_items);
    mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
    mDrawerList = (ListView) findViewById(R.id.list_slidermenu);
    setDrawerItems();
    setDrawerListeners();

    if (savedInstanceState == null) {
      displayView(0);
    }
  }
  
  @Override
  protected void onStart() {
    super.onStart();
  }
  
  @Override
  protected void onPause() {
    super.onPause();
  }
  
  @Override
  protected void onResume() {
    super.onResume();
    updateEverything();
  }
  
  
  @Override
  protected void onDestroy() {
    gpsTracker.stopUsingGPS();
    super.onDestroy();
  }

  
  /** Inflates our menu (preferences only currently) */
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.fast_preferences_menu, menu);
    return true;
  }
  
  /** Handle preferences selected. */
  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    /* toggle nav drawer on selecting action bar app icon/title*/
    if (mDrawerToggle.onOptionsItemSelected(item)) {
      return true;
    }
    // Handle action bar actions click
    switch (item.getItemId()) {
    case R.id.menu_preferences:
      // Display Settings page
      Intent intent = new Intent(this, FastPreferences.class);
      startActivity(intent);
      return true;
    default:
      return super.onOptionsItemSelected(item);
    }
  }

  /**
   * Called when invalidateOptionsMenu() is triggered
   */
  @Override
  public boolean onPrepareOptionsMenu(Menu menu) {
    // if nav drawer is opened, hide the action items
    boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
    menu.findItem(R.id.menu_preferences).setVisible(!drawerOpen);
    return super.onPrepareOptionsMenu(menu);
  }
  
  @Override
  protected void onStop() {
    super.onStop();
    mPlusClient.disconnect();
  }

  /**
   * Displaying fragment view for selected navigation drawer list item
   */
  private void displayView(int position) {

    /* update the main content by replacing fragments */
    FragmentManager fragmentManager = getFragmentManager();
    FragmentTransaction transaction = fragmentManager.beginTransaction();
    
    Fragment previous = currentFragment;
    switch (position) {
    case 0:
      if(homeFragment == null){
        homeFragment = new HomeFragment();
        transaction.add(R.id.frame_container, homeFragment);
      }
      currentFragment = homeFragment;
      break;
    case 1:
      if(runFragment == null){
        runFragment = new RunFragment();
        transaction.add(R.id.frame_container, runFragment);
      }
      currentFragment = runFragment;
      break;
    case 2:
      if(heartFragment == null){
        heartFragment = new HeartFragment();
        transaction.add(R.id.frame_container, heartFragment);
      }
      currentFragment = heartFragment;
      break;
    case 3:
      if(shareFragment == null){
        shareFragment = new ShareFragment();
        transaction.add(R.id.frame_container, shareFragment);
      }
      currentFragment = shareFragment;
      break;
    case 4:
      if(mapFragment == null){
        mapFragment = createMapFragment();  
      }
      currentFragment = mapFragment;
      break;

    default:
      break;
    }

    if (currentFragment != null) {
      if(previous != null){
        transaction.addToBackStack((backStackCount++).toString());
        /* Hide last fragment */
        transaction.hide(previous);
      }

      /* Add new Fragment */
      transaction.show(currentFragment).commit();
        
      // update selected item and title, then close the drawer
      mDrawerList.setItemChecked(position, true);
      mDrawerList.setSelection(position);
      setTitle(navMenuTitles[position]);
      mDrawerLayout.closeDrawer(mDrawerList);
    }
  }

  /**
   * Sets title of app based on davigation drawer item selected
   * (Sets it to the name of the option)
   */
  @Override
  public void setTitle(CharSequence title) {
    mTitle = title;
    getActionBar().setTitle(mTitle);
  }

  /**
   * When using the ActionBarDrawerToggle, you must call it during onPostCreate() and onConfigurationChanged()...
   */

  @Override
  protected void onPostCreate(Bundle savedInstanceState) {
    super.onPostCreate(savedInstanceState);
    // Sync the toggle state after onRestoreInstanceState has occurred.
    mDrawerToggle.syncState();
  }

  @Override
  public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    // Pass any configuration change to the drawer toggle
    mDrawerToggle.onConfigurationChanged(newConfig);
  }



  /*
   * Slide menu item click listener
   */
  private class SlideMenuClickListener implements ListView.OnItemClickListener {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
      // display view for selected nav drawer item
      displayView(position);
    }
  }

  
  /*
   * adds need items to Drawer object 
   * 1 for no errors else 0
   */
  private int setDrawerItems() {
    navDrawerItems = new ArrayList<NavDrawerItem>();
    // Home
    navDrawerItems.add(new NavDrawerItem(navMenuTitles[0], navMenuIcons.getResourceId(0, -1)));
    // Run Now
    navDrawerItems.add(new NavDrawerItem(navMenuTitles[1], navMenuIcons.getResourceId(1, -1)));
    // Heart Rate
    navDrawerItems.add(new NavDrawerItem(navMenuTitles[2], navMenuIcons.getResourceId(2, -1)));
    // Share
    navDrawerItems.add(new NavDrawerItem(navMenuTitles[3], navMenuIcons.getResourceId(3, -1)));
    // Map
    navDrawerItems.add(new NavDrawerItem(navMenuTitles[4], navMenuIcons.getResourceId(4, -1)));

    // Recycle the typed array
    navMenuIcons.recycle();
    return 1;
  }

  /*
   * creates and sets the Drawer Listeners 
   * return 1 for no errors
   */
  private int setDrawerListeners() {

    /* Creates default slide listener */
    mDrawerList.setOnItemClickListener(new SlideMenuClickListener());

    /* setting the navigation drawer list adapter */
    adapter = new NavDrawerListAdapter(getApplicationContext(), navDrawerItems);
    mDrawerList.setAdapter(adapter);

    /* enabling action bar app icon and behaving it as toggle button */
    getActionBar().setDisplayHomeAsUpEnabled(true);
    getActionBar().setHomeButtonEnabled(true);

    mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.drawable.ic_drawer, // nav menu toggle icon
        R.string.app_name, // nav drawer open
        R.string.app_name // nav drawer close
    ) {
      public void onDrawerClosed(View view) {
        getActionBar().setTitle(mTitle);
        /* calling onPrepareOptionsMenu() to show action bar icons */
        invalidateOptionsMenu();
      }

      public void onDrawerOpened(View drawerView) {
        getActionBar().setTitle(mDrawerTitle);
        /* calling onPrepareOptionsMenu() to hide action bar icons */
        invalidateOptionsMenu();
      }
    };
    mDrawerLayout.setDrawerListener(mDrawerToggle);

    return 1;
  }
  
  
  /* Time Updater for run screen.  Every 100 milliseconds callback.
   * Check if location is null, that way we don't start loggin statistics until we
   * have a successful GPS lock. */
  private Runnable timeUpdater = new Runnable() {
      public void run() {

        mHandler.postDelayed(this, TIMER);
        
        if(runFragment != null && gpsTracker.getLocation() != null)
          runFragment.getGpsText().setText(formatTime(milliseconds+=TIMER));
        
     }
   };
  
  /* Data (GPS) Updater for run screen.  Every 3 seconds callback. */
  private Runnable statisticsUpdater = new Runnable() {
      public void run() {
        
        double heartRate = getHeartRate();         
        /* Statistics update handles all logic for stats (check new location against old) */
        if(gpsTracker.getLocation() != null && previousLocation != null && !gpsTracker.getLocation().equals(previousLocation)){
         statistics.update(gpsTracker.getLocation(), heartRate);
        
         /* Update Google Map */  
         redrawGoogleMap(gpsTracker.getLatitude(), gpsTracker.getLongitude());
        }   
        previousLocation = gpsTracker.getLocation();
        
        mHandler.postDelayed(this, REFRESH_RATE);
        
        if(runFragment != null){
         runFragment.updateRunTextViews();
       }
          
        
     }
   };
   
   /*
    * Redraws and refocuses the google map, including drawing the line between here and the 
    * previous location, as well as moving the camera. (If this is called before the map is made,
    * then the map making methods are called in order to make the map.
    */
   private void redrawGoogleMap(double latitude, double longitude){
     if(map != null){
       if(path == null){
         path = new PolylineOptions().color(Color.RED).add(new LatLng(latitude, longitude));
       }
       else{
         path.add(new LatLng(latitude, longitude));
       }
       Polyline polyline = map.addPolyline(path);
       polyline.setVisible(true);
       
       /* Camera follows the user */
       map.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(latitude, longitude), 20.0f));
     }
     
     else if(mapFragment != null){
       map = createMap(latitude, longitude);
     }
     
     /* Create the fragment to start the logging */
     else{
       mapFragment = createMapFragment();
     }
   }
   
   /* Creates and stores a google map object */
   private GoogleMap createMap(double lat, double lon) {
     GoogleMap map = mapFragment.getMap();
    map.setMyLocationEnabled(true);
    /* Set initial maps position */
    map.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lon), 20.0f));
    return map;
  }

   /* Creates the map fragment that holds a google map */
  private MapFragment createMapFragment() {
    
     MapFragment mapFragment = MapFragment.newInstance(new GoogleMapOptions().zoomControlsEnabled(false));
     getFragmentManager().beginTransaction().add(R.id.frame_container, mapFragment).hide(mapFragment).commit();
    getFragmentManager().executePendingTransactions();
    
    return mapFragment;
  }

  /**
   *  Starts the thread that runs the Statistics updater (Speed, Distance, etc.).
   */
  public void startStatisticsUpdater(){
    
    updateEverything();
     gpsTracker.startUsingGPS();
     
     /* Start handlers */     
        timeHandler.postDelayed(timeUpdater, TIMER);
     mHandler.postDelayed(statisticsUpdater, REFRESH_RATE);
   }
  
  
   
  /**
   *  Stops collecting and calculating data, and removes all messages from the handler.
   */
   public void stopStatisticsUpdater(){
     mHandler.removeCallbacks(statisticsUpdater);
     mHandler.removeMessages(0);
     timeHandler.removeCallbacks(timeUpdater);
     timeHandler.removeMessages(0);
     gpsTracker.stopUsingGPS();
   }
   
   public Database getDatabase(){
     return database;
   }
   

  /* Google plus activity */
   @Override
   protected void onActivityResult(int requestCode, int responseCode, Intent intent) {
       if (requestCode == 9000 && responseCode == RESULT_OK) {
           mConnectionResult = null;
           mPlusClient.connect();
       }
   }
   
   /* Used by google APIs for Google + */
  @Override
  public void onConnectionFailed(ConnectionResult result) {
     if (mConnectionProgressDialog.isShowing()) {

             if (result.hasResolution()) {
                     try {
                             result.startResolutionForResult(this, 9000);
                     } catch (SendIntentException e) {
                             mPlusClient.connect();
                     }
             }
     }

     mConnectionResult = result;
    
  }

  /* Google Plus */
  @Override
  public void onConnected(Bundle connectionHint) {
      mConnectionProgressDialog.dismiss();
      Toast.makeText(this, mPlusClient.getAccountName() + " is connected!", Toast.LENGTH_LONG).show();
      updateEverything();
  }

  /* Google Plus */
  @Override
  public void onDisconnected() {
     Log.d("MainActivity", "disconnected");
  }
  
  
  /* Getters for fragments, statics */
  public GPSTracker getGpsTracker(){
    return gpsTracker;
  }
  
  public Handler getHandler(){
    return mHandler;
  }
  
  public Runnable getStatisticsUpdater(){
    return statisticsUpdater;
  }
  
  public Statistics getStatistics(){
    return statistics;
  }
  
  public boolean getUsingMetric(){
    return usingMetric;
  }
  
  public Statistics getAllTimeStatistics(){  
    
    return database.selectStatistics("TEST");
  }
  
  /**
   *  Updates as many components as possible, including all TextViews and Buttons on 
   *  all fragments attached to this activity.
   */
  public void updateEverything(){
    if(runFragment != null){
      runFragment.updateRunTextViews();
    }
    if(homeFragment != null){
      homeFragment.updateHomeTextViews();
    }
  }
  
  /** 
   * Signs into a Google account attached to this phone 
   **/
  public void signInToGoogleAccount() {  
    /* Need to authenticate a google account */
    if(!mPlusClient.isConnected()){
      mConnectionProgressDialog.setMessage("Signing in...");
      mConnectionProgressDialog.show();
      mPlusClient.connect();
    }    
  }
  
  
  /**
   * Signs out of the Google Account that is currently signed in.
   */
  public void signOutOfGoogleAccount() {
    /* Need to authenticate a google account */
    if(mPlusClient.isConnected()){
      mConnectionProgressDialog.setMessage("Signing out...");
      mConnectionProgressDialog.show();
      mPlusClient.connect();
    }    
  }
  
  public PlusClient getPlusClient(){
    return mPlusClient;
  }
  
  public void setConnectionResult(ConnectionResult conn){
    this.mConnectionResult = conn;
  }
  
  public ConnectionResult getConnectionResult(){
    return mConnectionResult;
  }
  
  public ProgressDialog getProgressDialog(){
    return mConnectionProgressDialog;
  }
  
  /**
   * Formats an extremely long floating point value to 2 decimal places.
   * @param value
   * @return
   */
  public static String format(double value){
    DecimalFormat df = new DecimalFormat("#0.00");
    return df.format(value);
  }
  
  /**
   * Gets the current heartrate.
   * @return Current heartrate.
   */
  public double getHeartRate(){
    if(heartFragment != null){
      return Double.parseDouble(heartFragment.getHeart());
    }
    else return 0;
  }
  
  /**
   * Returns the current Status of the heartrate monitor connection.
   * @return Heartrate monitor connection status.
   */
  public String getConnection(){
    if(heartFragment != null){
      return heartFragment.getConnection().getText().toString();
    }
    else{
      return getString(R.string.heartRateCurrent);
    }
  }
  
  /* Formats the timer into human readable string format */
  private CharSequence formatTime(long time) {
    
      Integer seconds = (int) ((time/1000));
    Integer minutes = seconds / 60;
    Integer hours = minutes / 60;
    
    seconds = seconds % 60;
    minutes = minutes % 60;
    String hoursString = hours > 9 ? hours.toString() : "0" + hours.toString();
    String minutesString = minutes > 9 ? minutes.toString() : "0" + minutes.toString();;
    String secondsString = seconds > 9 ? seconds.toString() : "0" + seconds.toString();;

    String msString = String.valueOf(time % 360000);
    Character msChar = msString.charAt(msString.length() -3);
    
    String concat = hoursString + ":" + minutesString + ":" + secondsString + "."+ msChar;
    
    return concat;
  }
}




Java Source Code List

com.example.fast.DatabaseHelper.java
com.example.fast.Database.java
com.example.fast.GPSTracker.java
com.example.fast.MainActivity.java
com.example.fast.StatisticsContentResolver.java
com.example.fast.Statistics.java
com.example.fast.adapter.NavDrawerListAdapter.java
com.example.fast.dummy.DummyContent.java
com.example.fast.heart.ConnectedListener.java
com.example.fast.heart.HeartFragment.java
com.example.fast.heart.HxmBluetoothHelper.java
com.example.fast.home.HomeFragment.java
com.example.fast.model.NavDrawerItem.java
com.example.fast.preferences.FastPreferences.java
com.example.fast.run.RunFragment.java
com.example.fast.share.ShareFragment.java