com.androzic.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.androzic.MainActivity.java

Source

/*
 * Androzic - android navigation client that uses OziExplorer maps (ozf2, ozfx3).
 * Copyright (C) 2010-2014 Andrey Novikov <http://andreynovikov.info/>
 * 
 * This file is part of Androzic application.
 * 
 * Androzic 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 3 of the License, or
 * (at your option) any later version.
 * 
 * Androzic 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 Androzic. If not, see <http://www.gnu.org/licenses/>.
 */

package com.androzic;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Stack;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.StrictMode;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.util.Pair;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;

import com.androzic.data.MapObject;
import com.androzic.data.Route;
import com.androzic.data.Track;
import com.androzic.data.Waypoint;
import com.androzic.map.BaseMap;
import com.androzic.map.MapInformation;
import com.androzic.map.OnMapActionListener;
import com.androzic.route.OnRouteActionListener;
import com.androzic.route.RouteDetails;
import com.androzic.route.RouteList;
import com.androzic.route.RouteProperties;
import com.androzic.route.RouteSave;
import com.androzic.route.RouteStart;
import com.androzic.track.OnTrackActionListener;
import com.androzic.track.TrackDetails;
import com.androzic.track.TrackList;
import com.androzic.track.TrackProperties;
import com.androzic.track.TrackSave;
import com.androzic.track.TrackToRoute;
import com.androzic.ui.DrawerAdapter;
import com.androzic.ui.DrawerItem;
import com.androzic.util.StringFormatter;
import com.androzic.vnspeech.MapFragment;
import com.androzic.waypoint.OnWaypointActionListener;
import com.androzic.waypoint.WaypointDetails;
import com.androzic.waypoint.WaypointInfo;
import com.androzic.waypoint.WaypointList;
import com.androzic.waypoint.WaypointProperties;

public class MainActivity extends AppCompatActivity implements FragmentHolder, OnWaypointActionListener,
        OnMapActionListener, OnRouteActionListener, OnTrackActionListener, OnSharedPreferenceChangeListener {
    private static final String TAG = "MainActivity";

    public static final String SHOW_FRAGMENT = "show";
    public static final String LAUNCH_ACTIVITY = "launch";

    private DrawerLayout mDrawerLayout;
    private ListView mDrawerList;
    private CoordinatorLayout mCoordinatorLayout;
    private DrawerAdapter mDrawerAdapter;
    private ActionBarDrawerToggle mDrawerToggle;
    private Drawable mHomeDrawable;
    private Toolbar mToolbar;
    private int mToolbarHeight;
    private FloatingActionButton mActionButton;

    private CharSequence mDrawerTitle;
    private CharSequence mTitle;
    private ArrayList<DrawerItem> mDrawerItems;

    private int exitConfirmation;
    private boolean secondBack;
    private Toast backToast;

    protected Androzic application;
    private boolean restarting = false;

    @SuppressLint({ "ShowToast", "NewApi" })
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e(TAG, "onCreate()");

        if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD)
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());

        application = Androzic.getApplication();

        // check if called after crash
        if (!application.mapsInited) {
            restarting = true;
            startActivity(new Intent(this, Splash.class)
                    .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
                    .putExtras(getIntent()));
            finish();
            return;
        }

        setContentView(R.layout.activity_main);

        mToolbar = (Toolbar) findViewById(R.id.action_toolbar);
        setSupportActionBar(mToolbar);

        mActionButton = (FloatingActionButton) findViewById(R.id.toolbar_action_button);

        backToast = Toast.makeText(this, R.string.backQuit, Toast.LENGTH_SHORT);

        SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
        onSharedPreferenceChanged(settings, getString(R.string.pref_exit));
        onSharedPreferenceChanged(settings, getString(R.string.pref_hidestatusbar));
        onSharedPreferenceChanged(settings, getString(R.string.pref_orientation));
        settings.registerOnSharedPreferenceChangeListener(this);

        mTitle = mDrawerTitle = getTitle();
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        // set a custom shadow that overlays the main content when the drawer opens
        mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
        // set up the drawer's list view with items and click listener
        mDrawerItems = new ArrayList<>();
        mDrawerList = (ListView) findViewById(R.id.left_drawer);
        mDrawerAdapter = new DrawerAdapter(this, mDrawerItems);
        mDrawerList.setAdapter(mDrawerAdapter);
        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
        initializeDrawerItems();

        mCoordinatorLayout = (CoordinatorLayout) findViewById(R.id.main_content);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeButtonEnabled(true);

        mHomeDrawable = getDrawerToggleDelegate().getThemeUpIndicator();

        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar, R.string.drawer_open,
                R.string.drawer_close) {
            public void onDrawerClosed(View drawerView) {
                if (drawerView == mDrawerList) {
                    getSupportActionBar().setTitle(mTitle);
                    supportInvalidateOptionsMenu();
                }
            }

            public void onDrawerOpened(View drawerView) {
                if (drawerView == mDrawerList) {
                    getSupportActionBar().setTitle(mDrawerTitle);
                    supportInvalidateOptionsMenu();
                }
            }
        };
        mDrawerLayout.setDrawerListener(mDrawerToggle);

        getSupportFragmentManager().addOnBackStackChangedListener(mBackStackChangedListener);

        if (savedInstanceState == null) {
            mDrawerAdapter.setSelectedItem(-1);
            selectItem(0);
        }
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.e(TAG, "onNewIntent()");
        if (intent.hasExtra(LAUNCH_ACTIVITY)) {
            Serializable object = intent.getExtras().getSerializable(LAUNCH_ACTIVITY);
            if (Class.class.isInstance(object)) {
                Intent launch = new Intent(this, (Class<?>) object);
                launch.putExtras(intent);
                launch.removeExtra(LAUNCH_ACTIVITY);
                startActivity(launch);
            }
        } else if (intent.hasExtra(SHOW_FRAGMENT)) {
            Serializable object = intent.getExtras().getSerializable(SHOW_FRAGMENT);
            if (Class.class.isInstance(object)) {
                @SuppressWarnings("rawtypes")
                String name = ((Class) object).getName();
                Fragment f = Fragment.instantiate(this, name);
                intent.removeExtra(SHOW_FRAGMENT);
                f.setArguments(intent.getExtras());
                if (DialogFragment.class.isInstance(f))
                    ((DialogFragment) f).show(getSupportFragmentManager(), "show");
                else
                    addFragment(f, name);
            }
        } else if (intent.hasExtra("lat") && intent.hasExtra("lon")) {
            application.ensureVisible(intent.getExtras().getDouble("lat"), intent.getExtras().getDouble("lon"));
            selectItem(0);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e(TAG, "onResume()");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.e(TAG, "onPause()");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy()");

        getSupportFragmentManager().removeOnBackStackChangedListener(mBackStackChangedListener);
        PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this);

        if (isFinishing() && !restarting)
            application.clear();

        restarting = false;

        application = null;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action buttons
        switch (item.getItemId()) {
        case android.R.id.home:
            FragmentManager fm = getSupportFragmentManager();
            if (fm.getBackStackEntryCount() > 0) {
                View v = getCurrentFocus();
                if (v != null) {
                    // Hide keyboard
                    final InputMethodManager imm = (InputMethodManager) getSystemService(
                            Context.INPUT_METHOD_SERVICE);
                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                }
                fm.popBackStack();
                return true;
            } else {
                if (mDrawerToggle.onOptionsItemSelected(item)) {
                    return true;
                }
            }
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    /* The click listener for ListView in the navigation drawer */
    private class DrawerItemClickListener implements ListView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            selectItem(position);
        }
    }

    private void selectItem(int position) {
        if (mDrawerAdapter.getSelectedItem() == position)
            return;

        DrawerItem item = mDrawerItems.get(position);
        // Actions
        if (item.type == DrawerItem.ItemType.INTENT) {
            if (position > 0)
                startActivity(item.intent);
        }
        // Fragments
        else if (item.type == DrawerItem.ItemType.FRAGMENT) {
            FragmentManager fm = getSupportFragmentManager();
            if (fm.getBackStackEntryCount() > 0) {
                fm.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);
            }
            FragmentTransaction ft = fm.beginTransaction();
            Fragment parent = fm.findFragmentById(R.id.content_frame);
            if (parent != null) {
                ft.detach(parent);
            }
            Fragment fragment = fm.findFragmentByTag(item.name);
            if (fragment != null) {
                ft.attach(fragment);
            } else {
                ft.add(R.id.content_frame, item.fragment, item.name);
            }
            ft.commit();
            // update selected item and title, then close the drawer
            updateDrawerUI(item, position);
        } else if (item.type == DrawerItem.ItemType.ACTION) {
            Log.e(TAG, "ACTION");
            runOnUiThread(item.action);
        }
        mDrawerLayout.closeDrawer(mDrawerList);
    }

    @Override
    public void setTitle(CharSequence title) {
        mTitle = title;
        getSupportActionBar().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 toggles
        mDrawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        savedInstanceState.putInt("drawerPosition", mDrawerAdapter.getSelectedItem());
        savedInstanceState.putString("title", (String) getSupportActionBar().getTitle());
        super.onSaveInstanceState(savedInstanceState);
    }

    @Override
    public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        int pos = savedInstanceState.getInt("drawerPosition");
        DrawerItem item = mDrawerItems.get(pos);
        updateDrawerUI(item, pos);
        restoreDrawerUI();
        getSupportActionBar().setTitle(savedInstanceState.getString("title"));
    }

    @Override
    public void onWaypointView(Waypoint waypoint) {
        application.ensureVisible(waypoint);
        selectItem(0);
    }

    @Override
    public void onWaypointShow(Waypoint waypoint) {
        Location loc = application.getLocationAsLocation();
        FragmentManager fm = getSupportFragmentManager();
        WaypointInfo waypointInfo = (WaypointInfo) fm.findFragmentByTag("waypoint_info");
        if (waypointInfo == null)
            waypointInfo = new WaypointInfo();
        waypointInfo.setWaypoint(waypoint);
        Bundle args = new Bundle();
        args.putDouble("lat", loc.getLatitude());
        args.putDouble("lon", loc.getLongitude());
        waypointInfo.setArguments(args);
        waypointInfo.show(fm, "waypoint_info");
    }

    @Override
    public void onWaypointDetails(Waypoint waypoint) {
        Location loc = application.getLocationAsLocation();
        FragmentManager fm = getSupportFragmentManager();
        WaypointDetails waypointDetails = (WaypointDetails) fm.findFragmentByTag("waypoint_details");
        if (waypointDetails == null)
            waypointDetails = new WaypointDetails();
        waypointDetails.setWaypoint(waypoint);
        Bundle args = new Bundle();
        args.putDouble("lat", loc.getLatitude());
        args.putDouble("lon", loc.getLongitude());
        waypointDetails.setArguments(args);
        addFragment(waypointDetails, "waypoint_details");
    }

    @Override
    public void onWaypointNavigate(Waypoint waypoint) {
        application.startNavigation(waypoint);
        selectItem(0);
    }

    @Override
    public void onWaypointEdit(Waypoint waypoint) {
        FragmentManager fm = getSupportFragmentManager();
        WaypointProperties waypointProperties = (WaypointProperties) fm.findFragmentByTag("waypoint_properties");
        if (waypointProperties == null)
            waypointProperties = (WaypointProperties) Fragment.instantiate(this,
                    WaypointProperties.class.getName());
        waypointProperties.setWaypoint(waypoint);
        addFragment(waypointProperties, "waypoint_properties");
    }

    @Override
    public void onWaypointShare(Waypoint waypoint) {
        Intent i = new Intent(android.content.Intent.ACTION_SEND);
        i.setType("text/plain");
        i.putExtra(Intent.EXTRA_SUBJECT, R.string.currentloc);
        String coords = StringFormatter.coordinates(" ", waypoint.latitude, waypoint.longitude);
        i.putExtra(Intent.EXTRA_TEXT, waypoint.name + " @ " + coords);
        startActivity(Intent.createChooser(i, getString(R.string.menu_share)));
    }

    @Override
    public void onWaypointRemove(final Waypoint waypoint) {
        application.undoWaypoint = waypoint;
        application.removeWaypoint(waypoint);
        application.saveWaypoints(waypoint.set);
        application.getMapHolder().refreshMap();

        Snackbar.make(mCoordinatorLayout, R.string.waypoint_deleted, Snackbar.LENGTH_LONG)
                .setAction(R.string.undo, new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        if (application.undoWaypoint == null)
                            return;
                        application.addWaypoint(application.undoWaypoint);
                        application.saveWaypoints(waypoint.set);
                        application.getMapHolder().refreshMap();
                        application.undoWaypoint = null;
                    }
                }).show();
    }

    @Override
    public void onOpenMap() {
        MapList mapList = (MapList) Fragment.instantiate(this, MapList.class.getName());
        addFragment(mapList, "map_list");
    }

    @Override
    public void onMapDetails(BaseMap map) {
        //TODO Should show any map information, not only current
        MapInformation mapInformation = (MapInformation) Fragment.instantiate(this, MapInformation.class.getName());
        addFragment(mapInformation, "map_information");
    }

    @Override
    public void onMapSelectedAtPosition(BaseMap map) {
        application.setMap(map, true);
    }

    @Override
    public void onMapSelected(BaseMap map) {
        application.loadMap(map);
    }

    @Override
    public void onRouteDetails(Route route) {
        FragmentManager fm = getSupportFragmentManager();
        RouteDetails routeDetails = (RouteDetails) fm.findFragmentByTag("route_details");
        if (routeDetails == null)
            routeDetails = (RouteDetails) Fragment.instantiate(this, RouteDetails.class.getName());
        routeDetails.setRoute(route);
        addFragment(routeDetails, "route_details");
    }

    @Override
    public void onRouteNavigate(Route route) {
        FragmentManager fm = getSupportFragmentManager();
        RouteStart routeStartDialog = new RouteStart(route);
        routeStartDialog.show(fm, "route_start");
    }

    @Override
    public void onRouteNavigate(Route route, int direction, int waypointIndex) {
        application.startNavigation(route, direction, waypointIndex);
        selectItem(0);
    }

    @Override
    public void onRouteEdit(Route route) {
        FragmentManager fm = getSupportFragmentManager();
        RouteProperties routeProperties = (RouteProperties) fm.findFragmentByTag("route_properties");
        if (routeProperties == null)
            routeProperties = (RouteProperties) Fragment.instantiate(this, RouteProperties.class.getName());
        routeProperties.setRoute(route);
        addFragment(routeProperties, "route_properties");
    }

    @Override
    public void onRouteEditPath(Route route) {
        application.editingRoute = route;
        application.editingRoute.show = true;
        application.editingRoute.editing = true;
        application.routeEditingWaypoints = new Stack<>();
        application.dispatchRoutePropertiesChanged(route);
        selectItem(0);
    }

    @Override
    public void onRouteSave(Route route) {
        FragmentManager fm = getSupportFragmentManager();
        RouteSave routeSaveDialog = new RouteSave(route);
        routeSaveDialog.show(fm, "route_save");
    }

    @Override
    public void onRouteWaypointEdit(Route route, Waypoint waypoint) {
        FragmentManager fm = getSupportFragmentManager();
        WaypointProperties waypointProperties = (WaypointProperties) fm.findFragmentByTag("waypoint_properties");
        if (waypointProperties == null)
            waypointProperties = (WaypointProperties) Fragment.instantiate(this,
                    WaypointProperties.class.getName());
        waypointProperties.setWaypoint(waypoint, route);
        addFragment(waypointProperties, "waypoint_properties");
    }

    @Override
    public void onTrackView(Track track) {
        Track.TrackPoint tp = track.getPoint(0);
        MapObject mo = new MapObject(tp.latitude, tp.longitude);
        application.ensureVisible(mo);
        selectItem(0);
    }

    @Override
    public void onTrackDetails(Track track) {
        FragmentManager fm = getSupportFragmentManager();
        TrackDetails trackDetails = (TrackDetails) fm.findFragmentByTag("track_details");
        if (trackDetails == null)
            trackDetails = new TrackDetails();
        trackDetails.setTrack(track);
        addFragment(trackDetails, "track_details");
    }

    @Override
    public void onTrackEdit(Track track) {
        FragmentManager fm = getSupportFragmentManager();
        TrackProperties trackProperties = (TrackProperties) fm.findFragmentByTag("track_properties");
        if (trackProperties == null)
            trackProperties = (TrackProperties) Fragment.instantiate(this, TrackProperties.class.getName());
        trackProperties.setTrack(track);
        addFragment(trackProperties, "track_properties");
    }

    @Override
    public void onTrackEditPath(Track track) {
        Toast.makeText(this, R.string.msg_notimplemented, Toast.LENGTH_LONG).show();
        //      setResult(RESULT_OK, new Intent().putExtra("index", application.getTrackIndex(track)));
    }

    @Override
    public void onTrackToRoute(Track track) {
        FragmentManager fm = getSupportFragmentManager();
        TrackToRoute trackToRouteDialog = new TrackToRoute(track);
        trackToRouteDialog.show(fm, "track_to_route");
    }

    @Override
    public void onTrackSave(Track track) {
        FragmentManager fm = getSupportFragmentManager();
        TrackSave trackSaveDialog = new TrackSave(track);
        trackSaveDialog.show(fm, "track_save");
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        Resources resources = getResources();

        if (getString(R.string.pref_exit).equals(key)) {
            exitConfirmation = Integer.parseInt(sharedPreferences.getString(key, "0"));
            initializeDrawerItems();
            secondBack = false;
        } else if (getString(R.string.pref_hidestatusbar).equals(key)) {
            if (sharedPreferences.getBoolean(key, resources.getBoolean(R.bool.def_hidestatusbar)))
                getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                        WindowManager.LayoutParams.FLAG_FULLSCREEN);
            else
                getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        } else if (getString(R.string.pref_orientation).equals(key)) {
            //noinspection ResourceType
            setRequestedOrientation(Integer.parseInt(sharedPreferences.getString(key, "-1")));
        }
    }

    private void initializeDrawerItems() {
        if (mDrawerItems == null)
            return;

        mDrawerItems.clear();

        Resources resources = getResources();

        Drawable icon;
        Intent action;
        Fragment fragment;
        FragmentManager fm = getSupportFragmentManager();

        // add main items to drawer list
        icon = resources.getDrawable(R.drawable.ic_map_white_24dp);
        fragment = fm.findFragmentByTag(getString(R.string.menu_map));
        if (fragment == null)
            fragment = Fragment.instantiate(this, MapFragment.class.getName());
        mDrawerItems.add(new DrawerItem(icon, getString(R.string.menu_map), fragment));

        icon = resources.getDrawable(R.drawable.ic_place_white_24dp);
        fragment = fm.findFragmentByTag(getString(R.string.menu_waypoints));
        if (fragment == null)
            fragment = Fragment.instantiate(this, WaypointList.class.getName());
        mDrawerItems.add(new DrawerItem(icon, getString(R.string.menu_waypoints), fragment));

        icon = resources.getDrawable(R.drawable.ic_directions_white_24dp);
        fragment = fm.findFragmentByTag(getString(R.string.menu_routes));
        if (fragment == null)
            fragment = Fragment.instantiate(this, RouteList.class.getName());
        mDrawerItems.add(new DrawerItem(icon, getString(R.string.menu_routes), fragment));

        icon = resources.getDrawable(R.drawable.ic_gesture_white_24dp);
        fragment = fm.findFragmentByTag(getString(R.string.menu_tracks));
        if (fragment == null)
            fragment = Fragment.instantiate(this, TrackList.class.getName());
        mDrawerItems.add(new DrawerItem(icon, getString(R.string.menu_tracks), fragment));

        // add plugins to drawer list
        mDrawerItems.add(new DrawerItem());
        icon = resources.getDrawable(R.drawable.ic_my_location_white_24dp);
        action = new Intent(this, HSIActivity.class);
        mDrawerItems.add(new DrawerItem(icon, getString(R.string.menu_hsi), action).makeMinor());

        java.util.Map<String, Pair<Drawable, Intent>> plugins = application.getPluginsViews();
        for (String plugin : plugins.keySet()) {
            mDrawerItems
                    .add(new DrawerItem(plugins.get(plugin).first, plugin, plugins.get(plugin).second).makeMinor());
        }

        // add supplementary items to drawer list
        mDrawerItems.add(new DrawerItem());
        icon = resources.getDrawable(R.drawable.ic_settings_white_24dp);
        fragment = fm.findFragmentByTag(getString(R.string.menu_preferences));
        if (fragment == null)
            fragment = Fragment.instantiate(this, Preferences.class.getName());
        mDrawerItems.add(new DrawerItem(icon, getString(R.string.menu_preferences), fragment).makeMinor()
                .makeSupplementary());

        icon = resources.getDrawable(R.drawable.ic_info_white_24dp);
        fragment = fm.findFragmentByTag(getString(R.string.menu_about));
        if (fragment == null)
            fragment = Fragment.instantiate(this, About.class.getName());
        mDrawerItems.add(
                new DrawerItem(icon, getString(R.string.menu_about), fragment).makeMinor().makeSupplementary());

        if (exitConfirmation == 3) {
            icon = resources.getDrawable(R.drawable.ic_open_in_new_white_24dp);
            Runnable exit = new Runnable() {
                @Override
                public void run() {
                    Log.e(TAG, "Exit");
                    MainActivity.this.finish();
                }
            };
            mDrawerItems
                    .add(new DrawerItem(icon, getString(R.string.menu_exit), exit).makeMinor().makeSupplementary());
        }

        mDrawerAdapter.notifyDataSetChanged();
    }

    private void updateDrawerUI(DrawerItem item, int position) {
        mDrawerList.setItemChecked(position, true);
        mDrawerAdapter.setSelectedItem(position);
        setTitle(item.name);
    }

    private void restoreDrawerUI() {
        FragmentManager fm = getSupportFragmentManager();
        if (fm.getBackStackEntryCount() > 0) {
            mDrawerToggle.setDrawerIndicatorEnabled(false);

            // FIXME This is the uggliest hack I have ever seen!
            getDrawerToggleDelegate().setActionBarUpIndicator(mHomeDrawable, R.string.cancel);
            setSupportActionBar(mToolbar);
            // End of hack

            mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, mDrawerList);
        } else {
            mDrawerToggle.setDrawerIndicatorEnabled(true);
            mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, mDrawerList);

            int pos = mDrawerAdapter.getSelectedItem();
            DrawerItem item = mDrawerItems.get(pos);
            if (item.type == DrawerItem.ItemType.FRAGMENT)
                updateDrawerUI(item, pos);
        }
    }

    private FragmentManager.OnBackStackChangedListener mBackStackChangedListener = new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            restoreDrawerUI();
        }
    };

    final Handler backHandler = new Handler();

    @Override
    public void onBackPressed() {
        if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
            super.onBackPressed();
            return;
        } else if (mDrawerAdapter.getSelectedItem() != 0) {
            selectItem(0);
            return;
        }

        switch (exitConfirmation) {
        case 0:
            // wait for second back
            if (secondBack) {
                backToast.cancel();
                MainActivity.this.finish();
            } else {
                secondBack = true;
                backToast.show();
                backHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        secondBack = false;
                    }
                }, 2000);
            }
            return;
        case 1:
            // Ask the user if they want to quit
            new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert)
                    .setTitle(R.string.quitQuestion)
                    .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            MainActivity.this.finish();
                        }
                    }).setNegativeButton(R.string.no, null).show();
            return;
        case 3:
            // Quit is performed from menu
            return;
        default:
            super.onBackPressed();
        }
    }

    @Override
    public void addFragment(Fragment fragment, String tag) {
        FragmentManager fm = getSupportFragmentManager();
        // Get topmost fragment
        Fragment parent;
        if (fm.getBackStackEntryCount() > 0) {
            FragmentManager.BackStackEntry bse = fm.getBackStackEntryAt(fm.getBackStackEntryCount() - 1);
            parent = fm.findFragmentByTag(bse.getName());
        } else {
            parent = fm.findFragmentById(R.id.content_frame);
        }
        FragmentTransaction ft = fm.beginTransaction();
        // Detach parent
        ft.detach(parent);
        // Add new fragment to back stack
        ft.add(R.id.content_frame, fragment, tag);
        ft.addToBackStack(tag);
        ft.commit();
    }

    @Override
    public FloatingActionButton enableActionButton() {
        ViewGroup.LayoutParams params = mToolbar.getLayoutParams();
        mToolbarHeight = params.height;
        params.height = getResources().getDimensionPixelSize(R.dimen.floating_action_button_toolbar_height);
        mActionButton.setVisibility(View.VISIBLE);
        return mActionButton;
    }

    @Override
    public void disableActionButton() {
        ViewGroup.LayoutParams params = mToolbar.getLayoutParams();
        params.height = mToolbarHeight;
        mActionButton.setOnClickListener(null);
        mActionButton.setVisibility(View.GONE);
    }

}