com.mendhak.gpslogger.GpsMainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.mendhak.gpslogger.GpsMainActivity.java

Source

/*******************************************************************************
 * This file is part of GPSLogger for Android.
 *
 * GPSLogger for Android is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * GPSLogger for Android is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GPSLogger for Android.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/

package com.mendhak.gpslogger;

import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
import android.location.LocationManager;
import android.net.Uri;
import android.os.*;
import android.support.annotation.NonNull;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.menu.ActionMenuItemView;
import android.support.v7.widget.ActionMenuView;
import android.support.v7.widget.Toolbar;
import android.text.InputType;
import android.util.DisplayMetrics;
import android.view.*;
import android.widget.*;
import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.amulyakhare.textdrawable.TextDrawable;
import com.mendhak.gpslogger.common.*;
import com.mendhak.gpslogger.common.events.CommandEvents;
import com.mendhak.gpslogger.common.events.ProfileEvents;
import com.mendhak.gpslogger.common.events.ServiceEvents;
import com.mendhak.gpslogger.common.events.UploadEvents;
import com.mendhak.gpslogger.common.slf4j.Logs;
import com.mendhak.gpslogger.common.slf4j.SessionLogcatAppender;
import com.mendhak.gpslogger.loggers.Files;
import com.mendhak.gpslogger.senders.FileSender;
import com.mendhak.gpslogger.senders.FileSenderFactory;
import com.mendhak.gpslogger.ui.Dialogs;
import com.mendhak.gpslogger.ui.components.GpsLoggerDrawerItem;
import com.mendhak.gpslogger.ui.fragments.display.*;
import com.mikepenz.materialdrawer.AccountHeader;
import com.mikepenz.materialdrawer.AccountHeaderBuilder;
import com.mikepenz.materialdrawer.Drawer;
import com.mikepenz.materialdrawer.DrawerBuilder;
import com.mikepenz.materialdrawer.model.DividerDrawerItem;
import com.mikepenz.materialdrawer.model.ProfileDrawerItem;
import com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem;
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
import com.mikepenz.materialdrawer.model.interfaces.IProfile;
import de.greenrobot.event.EventBus;
import org.slf4j.Logger;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.*;

public class GpsMainActivity extends AppCompatActivity
        implements Toolbar.OnMenuItemClickListener, ActionBar.OnNavigationListener {

    private static boolean userInvokedUpload;
    private static Intent serviceIntent;
    private ActionBarDrawerToggle drawerToggle;
    private static final Logger LOG = Logs.of(GpsMainActivity.class);

    Drawer materialDrawer;
    AccountHeader drawerHeader;
    private PreferenceHelper preferenceHelper = PreferenceHelper.getInstance();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        loadPresetProperties();
        loadVersionSpecificProperties();
        setLocale();

        setContentView(R.layout.activity_gps_main);

        setUpToolbar();
        setUpNavigationDrawer(savedInstanceState);

        loadDefaultFragmentView();
        startAndBindService();
        registerEventBus();

        if (preferenceHelper.shouldStartLoggingOnAppLaunch()) {
            LOG.debug("Start logging on app launch");
            EventBus.getDefault().postSticky(new CommandEvents.RequestStartStop(true));
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {

        //Save the drawer's selected values to bundle
        //useful if activity recreated due to rotation
        outState = materialDrawer.saveInstanceState(outState);
        outState = drawerHeader.saveInstanceState(outState);

        super.onSaveInstanceState(outState);
    }

    private void registerEventBus() {
        EventBus.getDefault().register(this);
    }

    private void unregisterEventBus() {
        try {
            EventBus.getDefault().unregister(this);
        } catch (Throwable t) {
            //this may crash if registration did not go through. just be safe
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        startAndBindService();
    }

    @Override
    protected void onResume() {
        super.onResume();
        startAndBindService();

        if (Session.hasDescription()) {
            setAnnotationReady();
        }

        populateProfilesList();
        enableDisableMenuItems();
    }

    @Override
    protected void onPause() {
        stopAndUnbindServiceIfRequired();
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        stopAndUnbindServiceIfRequired();
        unregisterEventBus();
        super.onDestroy();

    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        drawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        drawerToggle.onConfigurationChanged(newConfig);
    }

    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_MENU) {
            toggleDrawer();
        }

        return super.onKeyUp(keyCode, event);
    }

    /**
     * Handles the hardware back-button press
     */
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && Session.isBoundToService()) {
            stopAndUnbindServiceIfRequired();
        }

        if (keyCode == KeyEvent.KEYCODE_BACK) {
            DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
            if (drawerLayout.isDrawerOpen(Gravity.LEFT)) {
                toggleDrawer();
                return true;
            }
        }

        return super.onKeyDown(keyCode, event);
    }

    private void setLocale() {

        if (!Strings.isNullOrEmpty(preferenceHelper.getUserSpecifiedLocale())) {
            LOG.debug("Setting language to " + preferenceHelper.getUserSpecifiedLocale());

            String language, country = "";

            if (preferenceHelper.getUserSpecifiedLocale().contains("-")) {
                language = preferenceHelper.getUserSpecifiedLocale().split("-")[0];
                country = preferenceHelper.getUserSpecifiedLocale().split("-")[1];
            } else {
                language = preferenceHelper.getUserSpecifiedLocale();
            }

            Locale locale = new Locale(language, country);
            Locale.setDefault(locale);
            getResources().getConfiguration().locale = locale;
            getBaseContext().getResources().updateConfiguration(getResources().getConfiguration(),
                    getBaseContext().getResources().getDisplayMetrics());
        }
    }

    private void loadVersionSpecificProperties() {
        PackageInfo packageInfo;
        try {
            packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
            int versionCode = packageInfo.versionCode;

            if (preferenceHelper.getLastVersionSeen() <= 71) {
                LOG.debug("preferenceHelper.getLastVersionSeen() " + preferenceHelper.getLastVersionSeen());
                //Specifically disable passive provider... just once
                if (preferenceHelper.getChosenListeners().contains("passive")) {
                    Set<String> listeners = new HashSet<>();
                    if (preferenceHelper.getChosenListeners().contains(LocationManager.GPS_PROVIDER)) {
                        listeners.add(LocationManager.GPS_PROVIDER);
                    }
                    if (preferenceHelper.getChosenListeners().contains(LocationManager.NETWORK_PROVIDER)) {
                        listeners.add(LocationManager.NETWORK_PROVIDER);
                    }
                    preferenceHelper.setChosenListeners(listeners);
                }
            }

            if (preferenceHelper.getLastVersionSeen() <= 74) {
                LOG.debug("preferenceHelper.getLastVersionSeen() " + preferenceHelper.getLastVersionSeen());
                LOG.debug("Overriding minimum accuracy to 40");

                if (preferenceHelper.getMinimumAccuracy() == 0) {
                    preferenceHelper.setMinimumAccuracy(40);
                }
            }

            preferenceHelper.setLastVersionSeen(versionCode);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

    }

    private void loadPresetProperties() {

        //Either look for /<appfolder>/gpslogger.properties or /sdcard/gpslogger.properties
        File file = new File(Files.storageFolder(getApplicationContext()) + "/gpslogger.properties");
        if (!file.exists()) {
            file = new File(Environment.getExternalStorageDirectory() + "/gpslogger.properties");
            if (!file.exists()) {
                return;
            }
        }

        try {
            preferenceHelper.setPreferenceFromPropertiesFile(file);
        } catch (Exception e) {
            LOG.error("Could not load preset properties", e);
        }
    }

    /**
     * Helper method, launches activity in a delayed handler, less stutter
     */
    private void launchPreferenceScreen(final String whichFragment) {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Intent targetActivity = new Intent(getApplicationContext(), MainPreferenceActivity.class);
                targetActivity.putExtra("preference_fragment", whichFragment);
                startActivity(targetActivity);
            }
        }, 250);
    }

    public Toolbar getToolbar() {
        return (Toolbar) findViewById(R.id.toolbar);
    }

    public void setUpToolbar() {
        try {
            Toolbar toolbar = getToolbar();
            setSupportActionBar(toolbar);
            if (getSupportActionBar() != null) {
                getSupportActionBar().setDisplayShowTitleEnabled(false);
            }

            //Deprecated in Lollipop but required if targeting 4.x
            SpinnerAdapter spinnerAdapter = ArrayAdapter.createFromResource(getApplicationContext(),
                    R.array.gps_main_views, R.layout.spinner_dropdown_item);
            getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
            getSupportActionBar().setListNavigationCallbacks(spinnerAdapter, this);
            getSupportActionBar().setSelectedNavigationItem(getUserSelectedNavigationItem());

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                Window window = getWindow();
                window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            }
        } catch (Exception ex) {
            //http://stackoverflow.com/questions/26657348/appcompat-v7-v21-0-0-causing-crash-on-samsung-devices-with-android-v4-2-2
            LOG.error("Thanks for this, Samsung", ex);
        }

    }

    public void setUpNavigationDrawer(Bundle savedInstanceState) {

        final DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);

        drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, getToolbar(), R.string.navigation_drawer_open,
                R.string.navigation_drawer_close) {

            public void onDrawerClosed(View view) {
                invalidateOptionsMenu();
            }

            public void onDrawerOpened(View drawerView) {
                invalidateOptionsMenu();
            }
        };

        drawerHeader = new AccountHeaderBuilder().withActivity(this).withCompactStyle(true)
                .withAccountHeader(R.layout.smaller_header).withSavedInstance(savedInstanceState)
                .withProfileImagesVisible(false)
                .withHeaderBackground(new ColorDrawable(getResources().getColor(R.color.accentColor)))
                .withOnAccountHeaderListener(new AccountHeader.OnAccountHeaderListener() {

                    @Override
                    public boolean onProfileChanged(View view, IProfile profile, boolean currentProfile) {

                        //Add new profile
                        if (profile.getIdentifier() == 101) {
                            new MaterialDialog.Builder(GpsMainActivity.this)
                                    .title(getString(R.string.profile_create_new))
                                    .inputType(InputType.TYPE_CLASS_TEXT).negativeText(R.string.cancel)
                                    .input("", "", false, new MaterialDialog.InputCallback() {
                                        @Override
                                        public void onInput(@NonNull MaterialDialog materialDialog,
                                                CharSequence charSequence) {
                                            String profileName = charSequence.toString().trim();
                                            if (!Strings.isNullOrEmpty(profileName)) {
                                                final String[] ReservedChars = { "|", "\\", "?", "*", "<", "\"",
                                                        ":", ">", ".", "/", "'", ";" };

                                                for (String c : ReservedChars) {
                                                    profileName = profileName.replace(c, "");
                                                }

                                                EventBus.getDefault()
                                                        .post(new ProfileEvents.CreateNewProfile(profileName));
                                            }
                                        }
                                    }).show();
                            return true;
                        }

                        //Clicked on profile name
                        String newProfileName = profile.getName().getText();
                        EventBus.getDefault().post(new ProfileEvents.SwitchToProfile(newProfileName));

                        refreshProfileIcon(profile.getName().getText());
                        return true;
                    }
                })
                .withOnAccountHeaderItemLongClickListener(new AccountHeader.OnAccountHeaderItemLongClickListener() {
                    @Override
                    public boolean onProfileLongClick(View view, final IProfile iProfile, boolean b) {
                        if (iProfile.getIdentifier() > 150) {

                            if (preferenceHelper.getCurrentProfileName().equals(iProfile.getName().getText())) {
                                Dialogs.alert(getString(R.string.sorry),
                                        getString(R.string.profile_switch_before_delete), GpsMainActivity.this);
                            } else {
                                new MaterialDialog.Builder(GpsMainActivity.this)
                                        .title(getString(R.string.profile_delete))
                                        .content(iProfile.getName().getText()).positiveText(R.string.ok)
                                        .negativeText(R.string.cancel)
                                        .onPositive(new MaterialDialog.SingleButtonCallback() {
                                            @Override
                                            public void onClick(@NonNull MaterialDialog materialDialog,
                                                    @NonNull DialogAction dialogAction) {
                                                EventBus.getDefault().post(new ProfileEvents.DeleteProfile(
                                                        iProfile.getName().getText()));
                                            }
                                        }).show();
                            }
                        }
                        return false;
                    }
                }).build();

        populateProfilesList();

        materialDrawer = new DrawerBuilder().withActivity(this).withSavedInstance(savedInstanceState)
                .withToolbar(getToolbar()).withActionBarDrawerToggle(drawerToggle).withDrawerGravity(Gravity.LEFT)
                .withAccountHeader(drawerHeader).withSelectedItem(-1).build();

        materialDrawer.addItem(GpsLoggerDrawerItem.newPrimary(R.string.pref_general_title,
                R.string.pref_general_summary, R.drawable.settings, 1000));
        materialDrawer.addItem(GpsLoggerDrawerItem.newPrimary(R.string.pref_logging_title,
                R.string.pref_logging_summary, R.drawable.loggingsettings, 1001));
        materialDrawer.addItem(GpsLoggerDrawerItem.newPrimary(R.string.pref_performance_title,
                R.string.pref_performance_summary, R.drawable.performance, 1002));
        materialDrawer.addItem(new DividerDrawerItem());

        materialDrawer.addItem(GpsLoggerDrawerItem.newPrimary(R.string.pref_autosend_title,
                R.string.pref_autosend_summary, R.drawable.autosend, 1003));
        materialDrawer.addItem(
                GpsLoggerDrawerItem.newSecondary(R.string.gdocs_setup_title, R.drawable.googledrive, 1004));
        materialDrawer
                .addItem(GpsLoggerDrawerItem.newSecondary(R.string.dropbox_setup_title, R.drawable.dropbox, 1005));
        materialDrawer.addItem(GpsLoggerDrawerItem.newSecondary(R.string.autoemail_title, R.drawable.email, 1006));
        materialDrawer
                .addItem(GpsLoggerDrawerItem.newSecondary(R.string.autoftp_setup_title, R.drawable.ftp, 1007));
        materialDrawer
                .addItem(GpsLoggerDrawerItem.newSecondary(R.string.opengts_setup_title, R.drawable.opengts, 1008));
        materialDrawer.addItem(
                GpsLoggerDrawerItem.newSecondary(R.string.osm_setup_title, R.drawable.openstreetmap, 1009));
        materialDrawer.addItem(
                GpsLoggerDrawerItem.newSecondary(R.string.owncloud_setup_title, R.drawable.owncloud, 1010));
        materialDrawer.addItem(new DividerDrawerItem());

        materialDrawer
                .addStickyFooterItem(GpsLoggerDrawerItem.newSecondary(R.string.menu_faq, R.drawable.helpfaq, 1011));
        materialDrawer
                .addStickyFooterItem(GpsLoggerDrawerItem.newSecondary(R.string.menu_exit, R.drawable.exit, 1012));

        materialDrawer.setOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
            @Override
            public boolean onItemClick(View view, int i, IDrawerItem iDrawerItem) {

                switch (iDrawerItem.getIdentifier()) {
                case 1000:
                    launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.GENERAL);
                    break;
                case 1001:
                    launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.LOGGING);
                    break;
                case 1002:
                    launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.PERFORMANCE);
                    break;
                case 1003:
                    launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.UPLOAD);
                    break;
                case 1004:
                    launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.GDOCS);
                    break;
                case 1005:
                    launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.DROPBOX);
                    break;
                case 1006:
                    launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.EMAIL);
                    break;
                case 1007:
                    launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.FTP);
                    break;
                case 1008:
                    launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.OPENGTS);
                    break;
                case 1009:
                    launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.OSM);
                    break;
                case 1010:
                    launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.OWNCLOUD);
                    break;
                case 1011:
                    Intent faqtivity = new Intent(getApplicationContext(), Faqtivity.class);
                    startActivity(faqtivity);
                    break;
                case 1012:
                    EventBus.getDefault().post(new CommandEvents.RequestStartStop(false));
                    finish();
                    break;

                }
                return false;
            }
        });

        ImageButton helpButton = (ImageButton) findViewById(R.id.imgHelp);
        helpButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent faqtivity = new Intent(getApplicationContext(), Faqtivity.class);
                startActivity(faqtivity);
            }
        });

    }

    private void refreshProfileIcon(String profileName) {

        ImageView imgLetter = (ImageView) drawerHeader.getView().findViewById(R.id.profiletextletter);
        TextDrawable drawLetter = TextDrawable.builder().beginConfig().bold()
                .textColor(getResources().getColor(R.color.golden)).useFont(Typeface.SANS_SERIF).endConfig()
                .buildRound(profileName.substring(0, 1).toUpperCase(),
                        getResources().getColor(R.color.primaryColorLight));

        imgLetter.setImageDrawable(drawLetter);
    }

    private void populateProfilesList() {

        LOG.debug("Current profile:" + preferenceHelper.getCurrentProfileName());

        drawerHeader.clear();

        drawerHeader.addProfiles(
                new ProfileDrawerItem().withName(getString(R.string.profile_default)).withIdentifier(100)
                        .withTag("PROFILE_DEFAULT").withTextColorRes(R.color.primaryColorText),
                new ProfileSettingDrawerItem().withIcon(android.R.drawable.ic_menu_add).withIdentifier(101)
                        .withName(getString(R.string.profile_add_new)).withTag("PROFILE_ADD")
                        .withTextColorRes(R.color.primaryColorText),
                new ProfileSettingDrawerItem());

        File gpsLoggerDir = Files.storageFolder(this);
        File[] propertyFiles = gpsLoggerDir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File file, String fileName) {
                return fileName.endsWith(".properties")
                        && !fileName.equalsIgnoreCase(getString(R.string.profile_default) + ".properties");
            }
        });

        if (propertyFiles == null) {
            return;
        }

        for (File propertyFile : propertyFiles) {

            String name = propertyFile.getName();
            int pos = name.lastIndexOf(".");
            if (pos > 0) {
                name = name.substring(0, pos);
            }

            ProfileDrawerItem pdi = new ProfileDrawerItem().withName(name)
                    .withTextColorRes(R.color.primaryColorText);

            drawerHeader.addProfile(pdi, 1);

            if (name.equals(preferenceHelper.getCurrentProfileName())) {
                pdi.withSetSelected(true);
                drawerHeader.setActiveProfile(pdi);
            }

        }

        refreshProfileIcon(preferenceHelper.getCurrentProfileName());

    }

    public void toggleDrawer() {
        if (materialDrawer.isDrawerOpen()) {
            materialDrawer.closeDrawer();

        } else {
            materialDrawer.openDrawer();
        }
    }

    private int getUserSelectedNavigationItem() {
        return preferenceHelper.getUserSelectedNavigationItem();
    }

    private void loadDefaultFragmentView() {
        int currentSelectedPosition = getUserSelectedNavigationItem();
        loadFragmentView(currentSelectedPosition);
    }

    private void loadFragmentView(int position) {
        FragmentTransaction transaction = getFragmentManager().beginTransaction();

        switch (position) {
        default:
        case 0:
            transaction.replace(R.id.container, GpsSimpleViewFragment.newInstance());
            break;
        case 1:
            transaction.replace(R.id.container, GpsDetailedViewFragment.newInstance());
            break;
        case 2:
            transaction.replace(R.id.container, GpsBigViewFragment.newInstance());
            break;
        case 3:
            transaction.replace(R.id.container, GpsLogViewFragment.newInstance());
            break;

        }
        transaction.commitAllowingStateLoss();
    }

    private GenericViewFragment getCurrentFragment() {
        Fragment currentFragment = getFragmentManager().findFragmentById(R.id.container);
        if (currentFragment instanceof GenericViewFragment) {
            return ((GenericViewFragment) currentFragment);
        }
        return null;
    }

    @Override
    public boolean onNavigationItemSelected(int position, long itemId) {
        preferenceHelper.setUserSelectedNavigationItem(position);
        loadFragmentView(position);
        return true;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        Toolbar toolbarBottom = (Toolbar) findViewById(R.id.toolbarBottom);

        if (toolbarBottom.getMenu().size() > 0) {
            return true;
        }

        toolbarBottom.inflateMenu(R.menu.gps_main);
        setupEvenlyDistributedToolbar();
        toolbarBottom.setOnMenuItemClickListener(this);

        enableDisableMenuItems();
        return true;
    }

    public void setupEvenlyDistributedToolbar() {
        //http://stackoverflow.com/questions/26489079/evenly-spaced-menu-items-on-toolbar

        // Use Display metrics to get Screen Dimensions
        Display display = getWindowManager().getDefaultDisplay();
        DisplayMetrics metrics = new DisplayMetrics();
        display.getMetrics(metrics);

        // Toolbar
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbarBottom);

        // Add 10 spacing on either side of the toolbar
        toolbar.setContentInsetsAbsolute(10, 10);

        // Get the ChildCount of your Toolbar, this should only be 1
        int childCount = toolbar.getChildCount();
        // Get the Screen Width in pixels
        int screenWidth = metrics.widthPixels;

        // Create the Toolbar Params based on the screenWidth
        Toolbar.LayoutParams toolbarParams = new Toolbar.LayoutParams(screenWidth,
                Toolbar.LayoutParams.WRAP_CONTENT);

        // Loop through the child Items
        for (int i = 0; i < childCount; i++) {
            // Get the item at the current index
            View childView = toolbar.getChildAt(i);
            // If its a ViewGroup
            if (childView instanceof ViewGroup) {
                // Set its layout params
                childView.setLayoutParams(toolbarParams);
                // Get the child count of this view group, and compute the item widths based on this count & screen size
                int innerChildCount = ((ViewGroup) childView).getChildCount();
                int itemWidth = (screenWidth / innerChildCount);
                // Create layout params for the ActionMenuView
                ActionMenuView.LayoutParams params = new ActionMenuView.LayoutParams(itemWidth,
                        Toolbar.LayoutParams.WRAP_CONTENT);
                // Loop through the children
                for (int j = 0; j < innerChildCount; j++) {
                    View grandChild = ((ViewGroup) childView).getChildAt(j);
                    if (grandChild instanceof ActionMenuItemView) {
                        // set the layout parameters on each View
                        grandChild.setLayoutParams(params);
                    }
                }
            }
        }
    }

    private void enableDisableMenuItems() {

        onWaitingForLocation(Session.isWaitingForLocation());
        setBulbStatus(Session.isStarted());

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbarBottom);
        MenuItem mnuAnnotate = toolbar.getMenu().findItem(R.id.mnuAnnotate);
        MenuItem mnuOnePoint = toolbar.getMenu().findItem(R.id.mnuOnePoint);
        MenuItem mnuAutoSendNow = toolbar.getMenu().findItem(R.id.mnuAutoSendNow);

        if (mnuOnePoint != null) {
            mnuOnePoint.setEnabled(!Session.isStarted());
            mnuOnePoint.setIcon((Session.isStarted() ? R.drawable.singlepoint_disabled : R.drawable.singlepoint));
        }

        if (mnuAutoSendNow != null) {
            mnuAutoSendNow.setEnabled(Session.isStarted());
        }

        if (mnuAnnotate != null) {

            if (!preferenceHelper.shouldLogToGpx() && !preferenceHelper.shouldLogToKml()
                    && !preferenceHelper.shouldLogToCustomUrl()) {
                mnuAnnotate.setIcon(R.drawable.annotate2_disabled);
                mnuAnnotate.setEnabled(false);
            } else {
                if (Session.isAnnotationMarked()) {
                    mnuAnnotate.setIcon(R.drawable.annotate2_active);
                } else {
                    mnuAnnotate.setIcon(R.drawable.annotate2);
                }
            }

        }
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        LOG.debug("Menu Item: " + String.valueOf(item.getTitle()));

        switch (id) {
        case R.id.mnuAnnotate:
            annotate();
            return true;
        case R.id.mnuOnePoint:
            logSinglePoint();
            return true;
        case R.id.mnuShare:
            share();
            return true;
        case R.id.mnuOSM:
            uploadToOpenStreetMap();
            return true;
        case R.id.mnuDropBox:
            uploadToDropBox();
            return true;
        case R.id.mnuGDocs:
            uploadToGoogleDocs();
            return true;
        case R.id.mnuOpenGTS:
            sendToOpenGTS();
            return true;
        case R.id.mnuFtp:
            sendToFtp();
            return true;
        case R.id.mnuEmail:
            selectAndEmailFile();
            return true;
        case R.id.mnuAutoSendNow:
            forceAutoSendNow();
        case R.id.mnuOwnCloud:
            uploadToOwnCloud();
            return true;
        default:
            return true;
        }
    }

    private void forceAutoSendNow() {
        LOG.debug("User forced an auto send");

        if (preferenceHelper.isAutoSendEnabled()) {
            Dialogs.progress(this, getString(R.string.autosend_sending), getString(R.string.please_wait));
            EventBus.getDefault().post(new CommandEvents.AutoSend(null));

        } else {
            launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.UPLOAD);
        }
    }

    private void logSinglePoint() {
        EventBus.getDefault().post(new CommandEvents.LogOnce());
        enableDisableMenuItems();
    }

    /**
     * Annotates GPX and KML files, TXT files are ignored.
     * The user is prompted for the content of the <name> tag. If a valid
     * description is given, the logging service starts in single point mode.
     */
    private void annotate() {

        if (!preferenceHelper.shouldLogToGpx() && !preferenceHelper.shouldLogToKml()
                && !preferenceHelper.shouldLogToCustomUrl()) {
            Toast.makeText(getApplicationContext(), getString(R.string.annotation_requires_logging),
                    Toast.LENGTH_SHORT).show();
            return;
        }

        new MaterialDialog.Builder(this).title(R.string.add_description).inputType(InputType.TYPE_CLASS_TEXT)
                .negativeText(R.string.cancel)
                .input(getString(R.string.letters_numbers), "", new MaterialDialog.InputCallback() {
                    @Override
                    public void onInput(MaterialDialog materialDialog, CharSequence input) {
                        LOG.info("Annotation entered : " + input.toString());
                        EventBus.getDefault().postSticky(new CommandEvents.Annotate(input.toString()));
                    }
                }).onNegative(new MaterialDialog.SingleButtonCallback() {
                    @Override
                    public void onClick(@NonNull MaterialDialog materialDialog,
                            @NonNull DialogAction dialogAction) {
                        materialDialog.dismiss();
                    }
                }).show();

    }

    private void uploadToOpenStreetMap() {
        if (!FileSenderFactory.getOsmSender().isAvailable()) {
            launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.OSM);
            return;
        }

        showFileListDialog(FileSenderFactory.getOsmSender());
    }

    private void uploadToDropBox() {

        if (!FileSenderFactory.getDropBoxSender().isAvailable()) {
            launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.DROPBOX);
            return;
        }

        showFileListDialog(FileSenderFactory.getDropBoxSender());
    }

    private void uploadToOwnCloud() {

        if (!FileSenderFactory.getOwnCloudSender().isAvailable()) {
            launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.OWNCLOUD);
            return;
        }

        showFileListDialog(FileSenderFactory.getOwnCloudSender());
    }

    private void sendToOpenGTS() {
        if (!FileSenderFactory.getOpenGTSSender().isAvailable()) {
            launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.OPENGTS);
        } else {
            showFileListDialog(FileSenderFactory.getOpenGTSSender());
        }
    }

    private void uploadToGoogleDocs() {
        if (!FileSenderFactory.getGoogleDriveSender().isAvailable()) {
            launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.GDOCS);
            return;
        }

        showFileListDialog(FileSenderFactory.getGoogleDriveSender());
    }

    private void sendToFtp() {
        if (!FileSenderFactory.getFtpSender().isAvailable()) {
            launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.FTP);
        } else {
            showFileListDialog(FileSenderFactory.getFtpSender());
        }
    }

    private void selectAndEmailFile() {
        if (!FileSenderFactory.getEmailSender().isAvailable()) {
            launchPreferenceScreen(MainPreferenceActivity.PREFERENCE_FRAGMENTS.EMAIL);
        } else {
            showFileListDialog(FileSenderFactory.getEmailSender());
        }
    }

    private void showFileListDialog(final FileSender sender) {

        if (!Systems.isNetworkAvailable(this)) {
            Dialogs.alert(getString(R.string.sorry), getString(R.string.no_network_message), this);
            return;
        }

        final File gpxFolder = new File(preferenceHelper.getGpsLoggerFolder());

        if (gpxFolder.exists() && Files.fromFolder(gpxFolder, sender).length > 0) {
            File[] enumeratedFiles = Files.fromFolder(gpxFolder, sender);

            //Order by last modified
            Arrays.sort(enumeratedFiles, new Comparator<File>() {
                public int compare(File f1, File f2) {
                    if (f1 != null && f2 != null) {
                        return -1 * Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());
                    }
                    return -1;
                }
            });

            List<String> fileList = new ArrayList<>(enumeratedFiles.length);

            for (File f : enumeratedFiles) {
                fileList.add(f.getName());
            }

            final String[] files = fileList.toArray(new String[fileList.size()]);

            new MaterialDialog.Builder(this).title(R.string.osm_pick_file).items(files).positiveText(R.string.ok)
                    .itemsCallbackMultiChoice(null, new MaterialDialog.ListCallbackMultiChoice() {
                        @Override
                        public boolean onSelection(MaterialDialog materialDialog, Integer[] integers,
                                CharSequence[] charSequences) {

                            List<Integer> selectedItems = Arrays.asList(integers);

                            List<File> chosenFiles = new ArrayList<>();

                            for (Object item : selectedItems) {
                                LOG.info("Selected file to upload- " + files[Integer.valueOf(item.toString())]);
                                chosenFiles.add(new File(gpxFolder, files[Integer.valueOf(item.toString())]));
                            }

                            if (chosenFiles.size() > 0) {
                                Dialogs.progress(GpsMainActivity.this, getString(R.string.please_wait),
                                        getString(R.string.please_wait));
                                userInvokedUpload = true;
                                sender.uploadFile(chosenFiles);

                            }
                            return true;
                        }
                    }).show();

        } else {
            Dialogs.alert(getString(R.string.sorry), getString(R.string.no_files_found), this);
        }
    }

    /**
     * Allows user to send a GPX/KML file along with location, or location only
     * using a provider. 'Provider' means any application that can accept such
     * an intent (Facebook, SMS, Twitter, Email, K-9, Bluetooth)
     */
    private void share() {

        try {

            final String locationOnly = getString(R.string.sharing_location_only);
            final File gpxFolder = new File(preferenceHelper.getGpsLoggerFolder());
            if (gpxFolder.exists()) {

                File[] enumeratedFiles = Files.fromFolder(gpxFolder);

                Arrays.sort(enumeratedFiles, new Comparator<File>() {
                    public int compare(File f1, File f2) {
                        return -1 * Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());
                    }
                });

                List<String> fileList = new ArrayList<>(enumeratedFiles.length);

                for (File f : enumeratedFiles) {
                    fileList.add(f.getName());
                }

                fileList.add(0, locationOnly);
                final String[] files = fileList.toArray(new String[fileList.size()]);

                new MaterialDialog.Builder(this).title(R.string.osm_pick_file).items(files)
                        .positiveText(R.string.ok)
                        .itemsCallbackMultiChoice(null, new MaterialDialog.ListCallbackMultiChoice() {
                            @Override
                            public boolean onSelection(MaterialDialog materialDialog, Integer[] integers,
                                    CharSequence[] charSequences) {
                                List<Integer> selectedItems = Arrays.asList(integers);

                                final Intent intent = new Intent(Intent.ACTION_SEND);
                                intent.setType("*/*");

                                if (selectedItems.size() <= 0) {
                                    return false;
                                }

                                if (selectedItems.contains(0)) {

                                    intent.setType("text/plain");

                                    intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.sharing_mylocation));
                                    if (Session.hasValidLocation()) {
                                        String bodyText = getString(R.string.sharing_googlemaps_link,
                                                String.valueOf(Session.getCurrentLatitude()),
                                                String.valueOf(Session.getCurrentLongitude()));
                                        intent.putExtra(Intent.EXTRA_TEXT, bodyText);
                                        intent.putExtra("sms_body", bodyText);
                                        startActivity(
                                                Intent.createChooser(intent, getString(R.string.sharing_via)));
                                    }
                                } else {

                                    intent.setAction(Intent.ACTION_SEND_MULTIPLE);
                                    intent.putExtra(Intent.EXTRA_SUBJECT, "Here are some files.");
                                    intent.setType("*/*");

                                    ArrayList<Uri> chosenFiles = new ArrayList<>();

                                    for (Object path : selectedItems) {
                                        File file = new File(gpxFolder, files[Integer.valueOf(path.toString())]);
                                        Uri uri = Uri.fromFile(file);
                                        chosenFiles.add(uri);
                                    }

                                    intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, chosenFiles);
                                    startActivity(Intent.createChooser(intent, getString(R.string.sharing_via)));
                                }
                                return true;
                            }
                        }).show();

            } else {
                Dialogs.alert(getString(R.string.sorry), getString(R.string.no_files_found), this);
            }
        } catch (Exception ex) {
            LOG.error("Sharing problem", ex);
        }
    }

    /**
     * Provides a connection to the GPS Logging Service
     */
    private final ServiceConnection gpsServiceConnection = new ServiceConnection() {

        public void onServiceDisconnected(ComponentName name) {
            LOG.debug("Disconnected from GPSLoggingService from MainActivity");
            //loggingService = null;
        }

        public void onServiceConnected(ComponentName name, IBinder service) {
            LOG.debug("Connected to GPSLoggingService from MainActivity");
            //loggingService = ((GpsLoggingService.GpsLoggingBinder) service).getService();
        }
    };

    /**
     * Starts the service and binds the activity to it.
     */
    private void startAndBindService() {
        serviceIntent = new Intent(this, GpsLoggingService.class);
        // Start the service in case it isn't already running
        startService(serviceIntent);
        // Now bind to service
        bindService(serviceIntent, gpsServiceConnection, Context.BIND_AUTO_CREATE);
        Session.setBoundToService(true);
    }

    /**
     * Stops the service if it isn't logging. Also unbinds.
     */
    private void stopAndUnbindServiceIfRequired() {
        if (Session.isBoundToService()) {

            try {
                unbindService(gpsServiceConnection);
                Session.setBoundToService(false);
            } catch (Exception e) {
                LOG.warn(SessionLogcatAppender.MARKER_INTERNAL, "Could not unbind service", e);
            }
        }

        if (!Session.isStarted()) {
            LOG.debug("Stopping the service");
            try {
                stopService(serviceIntent);
            } catch (Exception e) {
                LOG.error("Could not stop the service", e);
            }
        }
    }

    private void setBulbStatus(boolean started) {
        ImageView bulb = (ImageView) findViewById(R.id.notification_bulb);
        bulb.setImageResource(started ? R.drawable.circle_green : R.drawable.circle_none);
    }

    public void setAnnotationReady() {
        Session.setAnnotationMarked(true);
        enableDisableMenuItems();
    }

    public void setAnnotationDone() {
        Session.setAnnotationMarked(false);
        enableDisableMenuItems();
    }

    public void onWaitingForLocation(boolean inProgress) {
        ProgressBar fixBar = (ProgressBar) findViewById(R.id.progressBarGpsFix);
        fixBar.setVisibility(inProgress ? View.VISIBLE : View.INVISIBLE);
    }

    @EventBusHook
    public void onEventMainThread(UploadEvents.OpenGTS upload) {
        LOG.debug("Open GTS Event completed, success: " + upload.success);
        Dialogs.hideProgress();

        if (!upload.success) {
            LOG.error(getString(R.string.opengts_setup_title) + "-" + getString(R.string.upload_failure));

            if (userInvokedUpload) {
                Dialogs.error(getString(R.string.sorry), getString(R.string.upload_failure), upload.message,
                        upload.throwable, this);
                userInvokedUpload = false;
            }
        }
    }

    @EventBusHook
    public void onEventMainThread(UploadEvents.AutoEmail upload) {
        LOG.debug("Auto Email Event completed, success: " + upload.success);
        Dialogs.hideProgress();

        if (!upload.success) {
            LOG.error(getString(R.string.autoemail_title) + "-" + getString(R.string.upload_failure));
            if (userInvokedUpload) {
                Dialogs.error(getString(R.string.sorry), getString(R.string.upload_failure), upload.message,
                        upload.throwable, this);
                userInvokedUpload = false;
            }
        }
    }

    @EventBusHook
    public void onEventMainThread(UploadEvents.OpenStreetMap upload) {
        LOG.debug("OSM Event completed, success: " + upload.success);
        Dialogs.hideProgress();

        if (!upload.success) {
            LOG.error(getString(R.string.osm_setup_title) + "-" + getString(R.string.upload_failure));
            if (userInvokedUpload) {
                Dialogs.error(getString(R.string.sorry), getString(R.string.upload_failure), upload.message,
                        upload.throwable, this);
                userInvokedUpload = false;
            }
        }
    }

    @EventBusHook
    public void onEventMainThread(UploadEvents.Dropbox upload) {
        LOG.debug("Dropbox Event completed, success: " + upload.success);
        Dialogs.hideProgress();

        if (!upload.success) {
            LOG.error(getString(R.string.dropbox_setup_title) + "-" + getString(R.string.upload_failure));
            if (userInvokedUpload) {
                Dialogs.error(getString(R.string.sorry), getString(R.string.upload_failure), upload.message,
                        upload.throwable, this);
                userInvokedUpload = false;
            }
        }
    }

    @EventBusHook
    public void onEventMainThread(UploadEvents.GDocs upload) {
        LOG.debug("GDocs Event completed, success: " + upload.success);
        Dialogs.hideProgress();

        if (!upload.success) {
            LOG.error(getString(R.string.gdocs_setup_title) + "-" + getString(R.string.upload_failure));
            if (userInvokedUpload) {
                Dialogs.error(getString(R.string.sorry), getString(R.string.upload_failure), upload.message,
                        upload.throwable, this);
                userInvokedUpload = false;
            }
        }
    }

    @EventBusHook
    public void onEventMainThread(UploadEvents.Ftp upload) {
        LOG.debug("FTP Event completed, success: " + upload.success);
        Dialogs.hideProgress();

        if (!upload.success) {
            LOG.error(getString(R.string.autoftp_setup_title) + "-" + getString(R.string.upload_failure));
            if (userInvokedUpload) {
                Dialogs.error(getString(R.string.sorry), getString(R.string.upload_failure), upload.message,
                        upload.throwable, this);
                userInvokedUpload = false;
            }
        }
    }

    @EventBusHook
    public void onEventMainThread(UploadEvents.OwnCloud upload) {
        LOG.debug("OwnCloud Event completed, success: " + upload.success);
        Dialogs.hideProgress();

        if (!upload.success) {
            LOG.error(getString(R.string.owncloud_setup_title) + "-" + getString(R.string.upload_failure));

            if (userInvokedUpload) {
                Dialogs.error(getString(R.string.sorry), getString(R.string.upload_failure), upload.message,
                        upload.throwable, this);
                userInvokedUpload = false;
            }
        }
    }

    @EventBusHook
    public void onEventMainThread(ServiceEvents.WaitingForLocation waitingForLocation) {
        onWaitingForLocation(waitingForLocation.waiting);
    }

    @EventBusHook
    public void onEventMainThread(ServiceEvents.AnnotationStatus annotationStatus) {
        if (annotationStatus.annotationWritten) {
            setAnnotationDone();
        } else {
            setAnnotationReady();
        }
    }

    @EventBusHook
    public void onEventMainThread(ServiceEvents.LoggingStatus loggingStatus) {
        enableDisableMenuItems();
    }

    @EventBusHook
    public void onEventMainThread(ProfileEvents.CreateNewProfile createProfileEvent) {

        LOG.debug("Creating profile: " + createProfileEvent.newProfileName);

        try {
            File f = new File(Files.storageFolder(GpsMainActivity.this),
                    createProfileEvent.newProfileName + ".properties");
            f.createNewFile();

            populateProfilesList();

        } catch (IOException e) {
            LOG.error("Could not create properties file for new profile ", e);
        }

    }

    @EventBusHook
    public void onEventMainThread(ProfileEvents.DeleteProfile deleteProfileEvent) {
        LOG.debug("Deleting profile: " + deleteProfileEvent.profileName);
        File f = new File(Files.storageFolder(GpsMainActivity.this),
                deleteProfileEvent.profileName + ".properties");
        f.delete();

        populateProfilesList();
    }
}