com.moro.synapsemod.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.moro.synapsemod.MainActivity.java

Source

/**
 * Author: Andrei F.
 *
 * This file is part of the "Synapse" software and is licensed under
 * under the Microsoft Reference Source License (MS-RSL).
 *
 * Please see the attached LICENSE.txt for the full license.
 */

package com.moro.synapsemod;

import android.app.ActionBar;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.widget.DrawerLayout;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import net.minidev.json.JSONObject;
import net.minidev.json.JSONArray;

import com.moro.synapsemod.elements.*;
import com.moro.synapsemod.lib.ActionValueNotifierHandler;
import com.moro.synapsemod.lib.BootService;
import com.moro.synapsemod.lib.ActionValueClient;
import com.moro.synapsemod.lib.ActionValueUpdater;
import com.moro.synapsemod.lib.ActivityListener;
import com.moro.synapsemod.lib.ElementSelector;
import com.moro.synapsemod.utils.ElementFailureException;
import com.moro.synapsemod.utils.L;
import com.moro.synapsemod.utils.NamedRunnable;
import com.moro.synapsemod.utils.Utils;
import com.readystatesoftware.systembartint.SystemBarTintManager;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;

public class MainActivity extends FragmentActivity {

    /**
     * The {@link android.support.v4.view.PagerAdapter} that will provide
     * fragments for each of the sections. We use a
     * {@link android.support.v4.app.FragmentPagerAdapter} derivative, which
     * will keep every loaded fragment in memory. If this becomes too memory
     * intensive, it may be best to switch to a
     * {@link android.support.v4.app.FragmentStatePagerAdapter}.
     */
    private SectionsPagerAdapter mSectionsPagerAdapter;
    private ListView mDrawerList;
    private ActionBarDrawerToggle mDrawerToggle;
    private DrawerLayout mDrawerLayout;
    private Dialog dlg_restaurar = null;

    /**
     * The {@link android.support.v4.view.ViewPager} that will host the section contents.
     */
    public static ViewPager mViewPager;

    public static TabSectionFragment[] fragments = null;
    private static AtomicInteger fragmentsDone = new AtomicInteger(0);
    long startTime;

    public static int topPadding = 0;
    public static int bottomPadding = 0;

    public static String BB;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        startTime = System.nanoTime();

        // Define Busybox
        if (new File("/su/xbin/busybox").exists())
            BB = "/su/xbin/busybox";
        else if (new File("/sbin/busybox").exists())
            BB = "/sbin/busybox";
        else
            BB = "/system/xbin/busybox";

        // Comprobar carpeta backup
        File bk_folder = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator
                + getString(R.string.dir_backups));
        if (!bk_folder.exists()) {
            bk_folder.mkdirs();
        }

        Utils.mainActivity = this;
        Utils.density = getResources().getDisplayMetrics().density;
        Utils.imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);

        Synapse.openExecutor();
        requestWindowFeature(Window.FEATURE_ACTION_BAR);
        Settings.setWallpaper(this);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            SystemBarTintManager tintManager = new SystemBarTintManager(this);

            if (Settings.getAppTheme() == Settings.Theme.TRANSLUCENT_DARK) {
                tintManager.setStatusBarTintEnabled(true);
                tintManager.setStatusBarTintResource(R.drawable.black_gradient_270);
            }

            if (Utils.hasSoftKeys(getWindowManager())) {
                tintManager.setNavigationBarTintEnabled(true);
                tintManager.setNavigationBarTintResource(R.drawable.black_gradient_90);
            }
        }

        getActionBar().hide();

        setPaddingDimensions();
        setContentView(R.layout.activity_loading);

        super.onCreate(fragments == null ? null : savedInstanceState);

        if (fragments == null) {
            if (Synapse.currentEnvironmentState != Synapse.environmentState.VALID_ENVIRONMENT) {
                findViewById(R.id.initialProgressBar).setVisibility(View.INVISIBLE);
                switch (Synapse.currentEnvironmentState) {
                case ROOT_FAILURE:
                    ((TextView) findViewById(R.id.initialText)).setText(R.string.initial_no_root);
                    break;
                case UCI_FAILURE:
                    ((TextView) findViewById(R.id.initialText)).setText(R.string.initial_no_uci);
                    break;
                case JSON_FAILURE:
                    ((TextView) findViewById(R.id.initialText)).setText(R.string.initial_json_parse);
                }

                return;
            }
        }

        mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

        /**
         *  The UI building continues in buildFragment after fragment generation, or if
         *  the fragments are already live, continue here.
         */

        if (fragmentsDone.get() == Utils.configSections.size())
            continueCreate();
    }

    @SuppressWarnings("ConstantConditions")
    private void continueCreate() {
        View v = LayoutInflater.from(this).inflate(R.layout.activity_main, null);

        mViewPager = (ViewPager) v.findViewById(R.id.mainPager);
        mViewPager.setAdapter(mSectionsPagerAdapter);
        mViewPager.setOnPageChangeListener(new ViewPagerPageChangeListener());
        mDrawerList = (ListView) v.findViewById(R.id.left_drawer);

        String[] section_titles = new String[Utils.configSections.size()];
        for (int i = 0; i < Utils.configSections.size(); i++)
            section_titles[i] = Utils.localise(((JSONObject) Utils.configSections.get(i)).get("name"));

        mDrawerList.setAdapter(new ArrayAdapter<>(this, R.layout.drawer_item, section_titles));
        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
        mDrawerList.setItemChecked(0, true);

        mDrawerLayout = (DrawerLayout) v.findViewById(R.id.drawer_layout);
        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.drawable.ic_action_drawer,
                R.string.drawer_open, R.string.drawer_close);
        mDrawerLayout.setDrawerListener(mDrawerToggle);

        ActionBar actionBar = getActionBar();

        actionBar.setDisplayHomeAsUpEnabled(true);
        actionBar.setHomeButtonEnabled(true);

        mDrawerToggle.syncState();

        // Comprobamos "aplicar_cambios_auto" si esta activo cancelamos para que deje entrar al nuevo perfil
        SharedPreferences prefs = getSharedPreferences("moro_prefs", Context.MODE_PRIVATE);
        int auto = prefs.getInt("aplicar_cambios_auto", 0);

        // Si es 1 cancelamos para que entre el perfil y reiniciamos
        if (auto == 1) {
            SharedPreferences.Editor editor = prefs.edit();
            editor.putInt("aplicar_cambios_auto", 2);
            editor.commit();
            // cancelamos
            ActionValueUpdater.cancelElements();
            // reiniciamos
            Utils.runCommand("/res/synapse/uci restart", false);
        }
        // Si es 2 aplicamos para que coja los voltajes
        else if (auto == 2) {
            SharedPreferences.Editor editor = prefs.edit();
            editor.putInt("aplicar_cambios_auto", 0);
            editor.commit();
            // aplicamos
            ActionValueUpdater.applyElements();
        }
        // Si es 0 no hacemos nada
        else if (auto == 0)
            ActionValueUpdater.refreshButtons(true);

        for (TabSectionFragment f : fragments)
            f.onElementsMainStart();

        setContentView(v);
        actionBar.show();
        Utils.appStarted = true;

        setPaddingDimensions();
        L.i("Interface creation finished in " + (System.nanoTime() - startTime) + "ns");

        if (!BootService.getBootFlag() && !BootService.getBootFlagPending()) {
            new AlertDialog.Builder(this).setTitle(R.string.popup_failed_boot_title)
                    .setMessage(R.string.popup_failed_boot_message).setCancelable(true)
                    .setPositiveButton(R.string.popup_failed_boot_ack, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                        }
                    }).show();
        }
    }

    private void setPaddingDimensions() {
        int resourceId;

        topPadding = 0;
        resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0)
            topPadding += getResources().getDimensionPixelSize(resourceId);

        TypedValue tv = new TypedValue();
        if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true))
            topPadding += TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());

        View v;

        v = findViewById(R.id.activity_loading);
        if (v != null)
            v.setPadding(0, topPadding, 0, 0);

        v = findViewById(R.id.activity_main);
        if (v != null)
            v.setPadding(0, topPadding, 0, 0);

        if (Utils.appStarted && Utils.hasSoftKeys(getWindowManager())) {
            bottomPadding = 0;

            resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
            if (resourceId > 0)
                bottomPadding += getResources().getDimensionPixelSize(resourceId);

            if (bottomPadding == 0)
                return;

            for (TabSectionFragment f : fragments) {
                if (f != null && f.fragmentView != null)
                    f.fragmentView.findViewById(R.id.section_container_linear_layout).setPadding(0, 0, 0,
                            bottomPadding);
            }
        }
    }

    // Dialogo Restaurar perfil
    private void dialogo_restaurar() {

        File ficheros = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator
                + getString(R.string.dir_backups));
        FileFilter ff = new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                String ruta;
                if (pathname.isFile()) {
                    ruta = pathname.getAbsolutePath().toLowerCase();
                    //compruebo que el nombre completo, con ruta, del archivo tiene la extensin que yo uso en la apk para backups
                    if (ruta.contains("." + getString(R.string.ext_backups))) {
                        return true;
                    }
                }
                return false;
            }
        };
        File fa[] = ficheros.listFiles(ff);
        if (fa.length == 0) {
            Toast toast = Toast.makeText(getApplicationContext(), getString(R.string.no_backups),
                    Toast.LENGTH_LONG);
            toast.show();
        } else {

            AdapterBackups ab = new AdapterBackups();
            ab.AdapterBackups(this, fa);
            ListView lista = new ListView(this);
            lista.setAdapter(ab);
            lista.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    TextView tv = (TextView) view.findViewById(android.R.id.text1);
                    String archivo = tv.getText().toString();
                    dlg_restaurar.dismiss();
                    dlg_restaurar = null;
                    File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator
                            + getString(R.string.dir_backups) + archivo + "." + getString(R.string.ext_backups));
                    //compruebo que fsicamente existe de verdad (otra vez)
                    if (f.exists())
                        confirmar_restaurar(archivo);
                    else {
                        Toast toast = Toast.makeText(getApplicationContext(), getString(R.string.no_backups),
                                Toast.LENGTH_LONG);
                        toast.show();
                    }
                }
            });
            AlertDialog.Builder abd = new AlertDialog.Builder(this);
            abd.setTitle(R.string.dlg_restore_title);
            abd.setMessage(R.string.dlg_restore_message);
            abd.setIcon(R.drawable.ic_action_restore);
            abd.setView(lista);
            dlg_restaurar = abd.create();
            dlg_restaurar.show();
        }

    }

    //Dialogo confirmar restauracion perfil
    private void confirmar_restaurar(final String backup) {

        AlertDialog.Builder adb = new AlertDialog.Builder(this);
        adb.setTitle(R.string.dlg_conf_title);
        adb.setIcon(R.drawable.ic_alert);
        adb.setMessage(getString(R.string.dlg_conf_message, backup));
        adb.setPositiveButton(R.string.btn_yes, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();

                // Guardo boolean true para el cambio automatico del perfil
                SharedPreferences prefs = getSharedPreferences("moro_prefs", Context.MODE_PRIVATE);
                SharedPreferences.Editor editor = prefs.edit();
                editor.putInt("aplicar_cambios_auto", 1);
                editor.commit();

                // Restauramos perfil
                Utils.runCommand(BB + " mount -o remount,rw /", false);
                Utils.runCommand("/res/synapse/actions/sqlite ImportConfigSynapse " + backup, false);
                Utils.runCommand("/res/synapse/uci restart", false);
                Utils.runCommand(BB + " mount -o remount,ro /", false);
            }
        });
        adb.setNegativeButton(R.string.btn_no, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        adb.create().show();
    }

    // Cuadro dialogo de guardar perfil
    protected void guardar_perfil() {

        AlertDialog.Builder adb = new AlertDialog.Builder(MainActivity.this);
        adb.setTitle(R.string.dlg_backup_title);
        adb.setIcon(R.drawable.ic_action_save);
        adb.setMessage(R.string.dlg_backup_message);

        final EditText editText = new EditText(MainActivity.this);
        editText.setHint(R.string.dlg_backup_box);
        adb.setView(editText);

        // Si pulsamos OK, cargamos el dialogo de confirmacion de carga de perfil
        adb.setPositiveButton(R.string.btn_ok, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                // Guardamos el perfil
                String name = editText.getText().toString().replace(' ', '_');
                Utils.runCommand(BB + " mount -o remount,rw /", false);
                Utils.runCommand("/res/synapse/actions/sqlite ExportConfigSynapse " + name, false);
                Utils.runCommand(BB + " mount -o remount,ro /", false);

                Toast toast = Toast.makeText(getApplicationContext(),
                        getString(R.string.dlg_bk_profile_toast) + " " + name, Toast.LENGTH_LONG);
                toast.show();
            }
        });
        // Si pulsamos Cancelar salimos
        adb.setNegativeButton(R.string.btn_cancel, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                dialog.cancel();
            }
        });

        // create an alert dialog
        AlertDialog alert = adb.create();
        alert.show();
    }

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

    @Override
    public void onDestroy() {
        if (!isChangingConfigurations()) {
            fragments = null;
            fragmentsDone = new AtomicInteger(0);
            Utils.appStarted = false;

            Settings.wallpaper = null;
            ActionValueNotifierHandler.clear();
            ActionValueUpdater.clear();
        }
        super.onDestroy();
        Utils.mainActivity = null;
        System.gc();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        ActionValueUpdater.setMenu(menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (mDrawerToggle != null && mDrawerToggle.onOptionsItemSelected(item))
            return true;

        // Handle presses on the action bar items
        switch (item.getItemId()) {
        case R.id.action_apply:
            ActionValueUpdater.applyElements();
            return true;
        case R.id.action_cancel:
            ActionValueUpdater.cancelElements();
            return true;
        //case R.id.action_select_multi:
        //   startActionMode(ElementSelector.callback);
        //   return true;
        case R.id.action_settings:
            Intent intent = new Intent(this, Settings.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
            this.startActivity(intent);
            return true;
        case R.id.menu_backup:
            guardar_perfil();
            return true;
        case R.id.menu_restore:
            dialogo_restaurar();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    private class DrawerItemClickListener implements ListView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView parent, View view, int position, long id) {
            mViewPager.setCurrentItem(position, true);
            mDrawerLayout.closeDrawer(Gravity.START);
        }
    }

    private class ViewPagerPageChangeListener implements ViewPager.OnPageChangeListener {
        int previousPosition = 0;

        @Override
        public void onPageScrolled(int i, float v, int i2) {
        }

        @Override
        public void onPageSelected(int i) {
            mDrawerList.setItemChecked(i, true);
            fragments[i].onElementsResume();

            if (previousPosition != i)
                fragments[previousPosition].onElementsPause();

            previousPosition = i;
        }

        @Override
        public void onPageScrollStateChanged(int i) {
        }
    }

    /**
     * A {@link android.support.v4.app.FragmentPagerAdapter} that returns a fragment
     * corresponding to one of the sections/tabs/pages.
     */
    public class SectionsPagerAdapter extends FragmentPagerAdapter {
        private void buildFragment(int position) {
            if (fragments[position] != null)
                return;

            TabSectionFragment fragment = new TabSectionFragment();
            Bundle args = new Bundle();
            args.putInt(TabSectionFragment.ARG_SECTION_NUMBER, position);
            fragment.setArguments(args);
            fragments[position] = fragment;
            fragment.prepareView();
            fragmentsDone.incrementAndGet();

            if (fragmentsDone.get() < Utils.configSections.size())
                return;

            /**
             *  After all fragments are created, continue building the UI.
             */
            Synapse.handler.post(new Runnable() {
                @Override
                public void run() {
                    continueCreate();
                }
            });
        }

        SectionsPagerAdapter(FragmentManager fm) {
            super(fm);

            if (fragmentsDone.get() > 0)
                return;

            if (fragments == null)
                fragments = new TabSectionFragment[Utils.configSections.size()];

            for (int i = 0; i < Utils.configSections.size(); i++) {
                /**
                 *  Spawn a builder thread for each section/fragment
                 */
                final int position = i;

                Synapse.executor.execute(new NamedRunnable(new Runnable() {
                    @Override
                    public void run() {
                        buildFragment(position);
                    }
                }) {
                    @Override
                    public String getName() {
                        return Utils.localise(((JSONObject) Utils.configSections.get(position)).get("name"));
                    }
                });
            }
        }

        @Override
        public Fragment getItem(int position) {
            return fragments[position];
        }

        @Override
        public int getCount() {
            return Utils.configSections.size();
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            fragments[position].onDetach();
            super.destroyItem(container, position, object);
        }

        @Override
        public CharSequence getPageTitle(int position) {
            JSONObject section = (JSONObject) Utils.configSections.get(position);
            return Utils.localise(section.get("name"));
        }
    }

    public static class TabSectionFragment extends Fragment {
        /**
         * The fragment argument representing the section number for this fragment.
         */

        public static final String ARG_SECTION_NUMBER = "section_number";
        private int sectionNumber;

        public View fragmentView = null;
        public ArrayList<BaseElement> fragmentElements = new ArrayList<>();

        public TabSectionFragment() {
            this.setRetainInstance(true);
        }

        public void prepareView() {
            if (fragmentView != null)
                return;

            sectionNumber = getArguments().getInt(ARG_SECTION_NUMBER);
            ScrollView tabSectionView = (ScrollView) LayoutInflater.from(Utils.mainActivity)
                    .inflate(R.layout.section_container, null);
            assert tabSectionView != null;
            LinearLayout tabContentLayout = (LinearLayout) tabSectionView.getChildAt(0);
            assert tabContentLayout != null;

            JSONObject section = (JSONObject) Utils.configSections.get(sectionNumber);
            JSONArray sectionElements = (JSONArray) section.get("elements");

            for (Object sectionElement : sectionElements) {
                JSONObject elm = (JSONObject) sectionElement;
                String type = Utils.getEnclosure(elm);
                JSONObject parameters = (JSONObject) elm.get(type);

                BaseElement elementObj;

                try {
                    elementObj = BaseElement.createObject(type, parameters, tabContentLayout, this);
                } catch (ElementFailureException e) {
                    tabContentLayout.addView(Utils.createElementErrorView(e));
                    continue;
                }

                if (elementObj instanceof ActionValueClient)
                    ActionValueUpdater.registerPerpetual((ActionValueClient) elementObj, sectionNumber);

                /**
                 *  Simple standalone elements may not add themselves to the layout, if so, add
                 *  them here after their creation.
                 */

                View elementView;

                try {
                    elementView = elementObj.getView();
                } catch (ElementFailureException e) {
                    View errorView = Utils.createElementErrorView(e);
                    if (errorView != null)
                        tabContentLayout.addView(errorView);
                    continue;
                }

                if (elementView != null)
                    tabContentLayout.addView(elementView);

                fragmentElements.add(elementObj);
            }

            fragmentView = tabSectionView;
        }

        //public boolean containsElement(BaseElement element) {
        //    return fragmentElements.contains(element);
        //}

        public void addElement(BaseElement element) {
            fragmentElements.add(element);
        }

        public void removeElement(BaseElement element) {
            fragmentElements.remove(element);
        }

        public int getSectionNumber() {
            return sectionNumber;
        }

        @Override
        public void setArguments(Bundle args) {
            super.setArguments(args);
            prepareView();
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            prepareView();
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            return fragmentView;
        }

        public void onElementsMainStart() {
            for (BaseElement elm : fragmentElements)
                if (elm instanceof ActivityListener)
                    try {
                        ((ActivityListener) elm).onMainStart();
                    } catch (ElementFailureException e) {
                        Utils.createElementErrorView(e);
                    }
        }

        @Override
        public void onStart() {
            super.onStart();
            onElementsStart();
        }

        public void onElementsStart() {
            for (BaseElement elm : fragmentElements)
                if (elm instanceof ActivityListener)
                    try {
                        ((ActivityListener) elm).onStart();
                    } catch (ElementFailureException e) {
                        Utils.createElementErrorView(e);
                    }
        }

        @Override
        public void onResume() {
            super.onResume();
            if (mViewPager.getCurrentItem() == sectionNumber)
                onElementsResume();
        }

        public void onElementsResume() {
            for (BaseElement elm : fragmentElements)
                if (elm instanceof ActivityListener)
                    try {
                        ((ActivityListener) elm).onResume();
                    } catch (ElementFailureException e) {
                        Utils.createElementErrorView(e);
                    }
        }

        @Override
        public void onPause() {
            super.onPause();
            if (mViewPager.getCurrentItem() == sectionNumber)
                onElementsPause();
        }

        public void onElementsPause() {
            for (BaseElement elm : fragmentElements)
                if (elm instanceof ActivityListener)
                    try {
                        ((ActivityListener) elm).onPause();
                    } catch (ElementFailureException e) {
                        Utils.createElementErrorView(e);
                    }
        }

        @Override
        public void onDetach() {
            /**
             *  On main activity destruction we are keeping the fragments instead of killing them.
             *  However on the next activity re-creation they need to get added to that new View
             *  instance. So we remove the child view from the old instance so that it can be
             *  added to the new one.
             */

            if (fragmentView != null) {
                ViewGroup parent = (ViewGroup) fragmentView.getParent();
                if (parent != null)
                    parent.removeView(fragmentView);
            }
            super.onDetach();
        }
    }

    @Override
    public void onBackPressed() {
        if (Utils.appStarted)
            finish();
    }

    @Override
    public void onStop() {
        super.onStop();
        System.gc();
    }

    @Override
    public void onPause() {
        super.onPause();
        System.gc();
    }

    @Override
    public void onResume() {
        super.onResume();
        if (Utils.appStarted)
            for (TabSectionFragment f : fragments)
                f.onElementsMainStart();

        System.gc();
    }
}