com.jtschohl.androidfirewall.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.jtschohl.androidfirewall.MainActivity.java

Source

/**
 * Main application activity.
 * This is the screen displayed when you open the application
 *
 * Copyright (C) 2009-2011  Rodrigo Zechin Rosauro
 * Copyright (C) 2012-2014   Jason Tschohl
 *
 * This program 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.
 *
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author Rodrigo Zechin Rosauro
 * @author Jason Tschohl
 * @version 1.0
 */

package com.jtschohl.androidfirewall;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.Method;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Map.Entry;
import java.util.concurrent.RejectedExecutionException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.UserManager;
import android.preference.PreferenceManager;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.actionbarsherlock.app.SherlockActivity;
import com.actionbarsherlock.internal.widget.IcsAdapterView;
import com.actionbarsherlock.internal.widget.IcsSpinner;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.jtschohl.androidfirewall.Api.DroidApp;
import com.jtschohl.androidfirewall.RootShell.RootCommand;

/**
 * Main application activity. This is the screen displayed when you open the
 * application
 */

@SuppressLint("DefaultLocale")
public class MainActivity extends SherlockActivity implements OnCheckedChangeListener, OnClickListener {

    /** progress dialog instance */
    private ListView listview = null;
    /** indicates if the view has been modified and not yet saved */
    private boolean dirty = false;
    /**
     * variables for profile names
     */
    private String[] profileposition;

    private Menu abs_menu;

    /**
     * Variable for userid
     */
    int userid;

    /** tag for logcat */
    public static final String TAG = "{AF}";

    /**
     * Variables for spinner
     */
    private IcsSpinner spinner;
    public ArrayAdapter<String> adapter1;

    /**
     * Navigation drawer variables
     */

    private DrawerLayout mDrawerLayout;
    private ListView mDrawerList;
    private ActionBarDrawerToggle mDrawerToggle;
    private CharSequence mDrawerTitle;
    private CharSequence mTitle;
    private String[] mMenuTitles;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        try {
            /* enable hardware acceleration on Android >= 3.0 */
            final int FLAG_HARDWARE_ACCELERATED = WindowManager.LayoutParams.class
                    .getDeclaredField("FLAG_HARDWARE_ACCELERATED").getInt(null);
            getWindow().setFlags(FLAG_HARDWARE_ACCELERATED, FLAG_HARDWARE_ACCELERATED);
        } catch (Exception e) {
        }
        checkPreferences();
        setContentView(R.layout.main);

        // set Nav drawer

        mTitle = mDrawerTitle = getTitle();
        mMenuTitles = getResources().getStringArray(R.array.drawer_menu);

        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.left_drawer);

        mDrawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list, mMenuTitles));

        // Capture button clicks on side menu
        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

        // Enable ActionBar app icon to behave as action to toggle nav drawer
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeButtonEnabled(true);

        // ActionBarDrawerToggle ties together the the proper interactions
        // between the sliding drawer and the action bar app icon
        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.drawable.ic_drawer, R.string.drawer_open,
                R.string.drawer_close) {

            public void onDrawerClosed(View view) {
                getSupportActionBar().setTitle(mTitle);
                supportInvalidateOptionsMenu();
            }

            public void onDrawerOpened(View drawerView) {
                getSupportActionBar().setTitle(mDrawerTitle);
                supportInvalidateOptionsMenu();
            }
        };

        mDrawerLayout.setDrawerListener(mDrawerToggle);

        this.findViewById(R.id.label_mode).setOnClickListener(this);
        this.findViewById(R.id.label_clear).setOnClickListener(this);
        this.findViewById(R.id.label_data).setOnClickListener(this);
        this.findViewById(R.id.label_wifi).setOnClickListener(this);
        this.findViewById(R.id.label_roam).setOnClickListener(this);
        this.findViewById(R.id.label_vpn).setOnClickListener(this);
        this.findViewById(R.id.label_invert).setOnClickListener(this);
        this.findViewById(R.id.label_lan).setOnClickListener(this);
        this.findViewById(R.id.label_input_wifi).setOnClickListener(this);

        toggleVPNbutton(getApplicationContext());
        toggleRoambutton(getApplicationContext());
        toggleLANbutton(getApplicationContext());
        toggleInputWifiButton(getApplicationContext());

        toggleLogtarget();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            isCurrentUserOwner(getApplicationContext());
            SharedPreferences prefs2 = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
            final String chainName = prefs2.getString("chainName", "");
            Log.d(TAG, "Executed isCurrentUserOwner " + chainName);
        } else {
            final SharedPreferences prefs2 = getSharedPreferences(Api.PREFS_NAME, 0);
            final Editor editor = prefs2.edit();
            editor.putString("chainName", "droidwall");
            editor.commit();
            Log.d(TAG, "Skipping isCurrentUserOwner " + prefs2.getString("chainName", ""));
        }

        toggleUser();

        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        // use "" as default
        String language = prefs.getString("locale", "");
        Api.changeLanguage(getApplicationContext(), language);

        // create the spinner
        spinner = (IcsSpinner) findViewById(R.id.spinner);

        // profile names for spinner
        final List<String> profilestring = new ArrayList<String>();
        profilestring.add(prefs.getString("default", getString(R.string.defaultprofile)));
        profilestring.add(prefs.getString("profile1", getString(R.string.profile1)));
        profilestring.add(prefs.getString("profile2", getString(R.string.profile2)));
        profilestring.add(prefs.getString("profile3", getString(R.string.profile3)));
        profilestring.add(prefs.getString("profile4", getString(R.string.profile4)));
        profilestring.add(prefs.getString("profile5", getString(R.string.profile5)));
        profileposition = profilestring.toArray(new String[profilestring.size()]);

        // adapter for spinner
        adapter1 = new ArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item, profileposition);

        adapter1.setDropDownViewResource(R.layout.sherlock_spinner_dropdown_item);
        spinner.setAdapter(adapter1);
        spinner.setSelection(prefs.getInt("itemPosition", 0));
        spinner.post(new Runnable() {
            public void run() {
                spinner.setOnItemSelectedListener(new IcsAdapterView.OnItemSelectedListener() {
                    public void onItemSelected(IcsAdapterView<?> parent, View view, int position, long id) {
                        SharedPreferences prefs = PreferenceManager
                                .getDefaultSharedPreferences(getApplicationContext());
                        SharedPreferences.Editor editor = prefs.edit();
                        int index = parent.getSelectedItemPosition();
                        if (index == 0) {
                            editor.putInt("itemPosition", index);
                            editor.commit();
                            LoadDefaultProfile();
                        }
                        if (index == 1) {
                            editor.putInt("itemPosition", index);
                            editor.commit();
                            LoadProfile1();
                        }
                        if (index == 2) {
                            editor.putInt("itemPosition", index);
                            editor.commit();
                            LoadProfile2();
                        }
                        if (index == 3) {
                            editor.putInt("itemPosition", index);
                            editor.commit();
                            LoadProfile3();
                        }
                        if (index == 4) {
                            editor.putInt("itemPosition", index);
                            editor.commit();
                            LoadProfile4();
                        }
                        if (index == 5) {
                            editor.putInt("itemPosition", index);
                            editor.commit();
                            LoadProfile5();
                        }
                    }

                    public void onNothingSelected(IcsAdapterView<?> parent) {
                        // do nothing
                    }
                });
            }
        });

        /**
         * Search function call
         */
        searchapps();

        Api.assertBinaries(this, true);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (this.listview == null) {
            this.listview = (ListView) this.findViewById(R.id.listview);
        }
        refreshHeader();
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        final String pwd = prefs.getString("password", "");
        if (pwd.length() == 0) {
            // No password lock
            showOrLoadApplications();
        } else {
            // Check the password
            requestPassword(pwd);
        }
        toggleVPNbutton(getApplicationContext());
        toggleRoambutton(getApplicationContext());
        toggleLANbutton(getApplicationContext());
        toggleInputWifiButton(getApplicationContext());
        isCurrentUserOwner(getApplicationContext());
        toggleUser();
    }

    @Override
    protected void onPause() {
        super.onPause();
        this.listview.setAdapter(null);
    }

    /**
     * The click listener for ListView in the navigation drawer
     */

    private class DrawerItemClickListener implements ListView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int drawerposition, long id) {
            selectItem(drawerposition);
        }
    }

    private void selectItem(int drawerposition) {
        // Locate Position
        switch (drawerposition) {
        case 0:
            exportRules();
            break;
        case 1:
            importRules();
            break;
        case 2:
            manageRuleFiles();
            break;
        case 3:
            saveProfile();
            break;
        case 4:
            selectProfile();
            break;
        case 5:
            editProfileNames();
            break;
        case 6:
            showLog();
            break;
        case 7:
            showAcceptLog();
            break;
        case 8:
            clearLog();
            break;
        case 9:
            showRules();
            break;
        case 10:
            setPassword();
            break;
        case 11:
            setCustomScript();
            break;
        }
        mDrawerList.setItemChecked(drawerposition, true);
        // Close drawer
        mDrawerLayout.closeDrawer(mDrawerList);
    }

    @Override
    public void setTitle(CharSequence title) {
        mTitle = title;
        getSupportActionBar().setTitle(mTitle);
    }

    @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);
    }

    /**
     * search function
     */

    public void searchapps() {
        final EditText filterText = (EditText) findViewById(R.id.search);
        filterText.addTextChangedListener(filterTextWatcher);
        filterText.post(new Runnable() {
            @Override
            public void run() {
                filterText.requestFocus();
                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.showSoftInput(filterText, InputMethodManager.SHOW_IMPLICIT);
            }
        });
    }

    /**
     * update spinner with changed profile names
     */
    public void updateSpinner() {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        final List<String> profilestring = new ArrayList<String>();
        profilestring.add(prefs.getString("default", getString(R.string.defaultprofile)));
        profilestring.add(prefs.getString("profile1", getString(R.string.profile1)));
        profilestring.add(prefs.getString("profile2", getString(R.string.profile2)));
        profilestring.add(prefs.getString("profile3", getString(R.string.profile3)));
        profilestring.add(prefs.getString("profile4", getString(R.string.profile4)));
        profilestring.add(prefs.getString("profile5", getString(R.string.profile5)));
        profileposition = profilestring.toArray(new String[profilestring.size()]);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item,
                profileposition);
        adapter.notifyDataSetChanged();
        spinner.setAdapter(adapter);
        spinner.setSelection(prefs.getInt("itemPosition", 0));
    }

    /**
     * Check if the stored preferences are OK
     */
    private void checkPreferences() {
        final SharedPreferences prefs = getSharedPreferences(Api.PREFS_NAME, 0);
        final Editor editor = prefs.edit();
        boolean changed = false;
        if (prefs.getString(Api.PREF_MODE, "").length() == 0) {
            editor.putString(Api.PREF_MODE, Api.MODE_WHITELIST);
            changed = true;
        }
        /* delete the old preference names */
        if (prefs.contains("AllowedUids")) {
            editor.remove("AllowedUids");
            changed = true;
        }
        if (prefs.contains("Interfaces")) {
            editor.remove("Interfaces");
            changed = true;
        }
        if (changed)
            editor.commit();
    }

    /**
     * Refresh informative header
     */
    private void refreshHeader() {
        final SharedPreferences prefs = getSharedPreferences(Api.PREFS_NAME, 0);
        final String mode = prefs.getString(Api.PREF_MODE, Api.MODE_WHITELIST);
        final TextView labelmode = (TextView) this.findViewById(R.id.label_mode);
        final Resources res = getResources();
        int resid = (mode.equals(Api.MODE_WHITELIST) ? R.string.mode_whitelist : R.string.mode_blacklist);
        labelmode.setText(res.getString(R.string.mode_header, res.getString(resid)));
        resid = (Api.isEnabled(this) ? R.string.title_enabled : R.string.title_disabled);
        setTitle(res.getString(resid));
    }

    /**
     * refresh the spinner
     */
    private void refreshSpinner() {
        final SharedPreferences prefs = getSharedPreferences(Api.PREFS_NAME, 0);
        spinner.setSelection(prefs.getInt("itemPosition", 0));
    }

    /**
     * Displays a dialog box to select the operation mode (black or white list)
     */
    private void selectMode() {
        final Resources res = getResources();
        new AlertDialog.Builder(this).setItems(
                new String[] { res.getString(R.string.mode_whitelist), res.getString(R.string.mode_blacklist) },
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        final String mode = (which == 0 ? Api.MODE_WHITELIST : Api.MODE_BLACKLIST);
                        final Editor editor = getSharedPreferences(Api.PREFS_NAME, 0).edit();
                        editor.putString(Api.PREF_MODE, mode);
                        editor.commit();
                        refreshHeader();
                    }
                }).setTitle(R.string.select_mode).show();
    }

    /**
     * Set a new password lock
     * 
     * @param pwd
     *            new password (empty to remove the lock)
     */
    private void setPassword(String pwd) {
        final Resources res = getResources();
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        SharedPreferences.Editor editor = prefs.edit();
        String msg;
        String hash = md5(pwd);
        if (pwd.length() > 0) {
            editor.putString("password", hash);
            if (editor.commit()) {
                msg = res.getString(R.string.passdefined);
                getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
            } else {
                msg = res.getString(R.string.passerror);
            }
        } else {
            editor.putString("password", pwd);
            editor.commit();
            msg = res.getString(R.string.passremoved);
            getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
        }
        Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
    }

    /**
     * Request the password lock before displayed the main screen.
     */
    private void requestPassword(final String pwd) {
        new PassDialog(this, false, new android.os.Handler.Callback() {
            public boolean handleMessage(Message msg) {
                if (msg.obj == null) {
                    MainActivity.this.finish();
                    android.os.Process.killProcess(android.os.Process.myPid());
                    return false;
                }
                if (msg.obj != null) {
                    String encrypted = ((String) msg.obj);
                    String hash = md5(encrypted);
                    if (!pwd.equals(hash)) {
                        requestPassword(pwd);
                        return false;
                    }
                }
                // Password correct
                showOrLoadApplications();
                return false;
            }
        }).show();
    }

    /**
     * Hash the password
     */

    public static final String md5(final String s) {
        try {
            // Create MD5 Hash
            MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
            digest.update(s.getBytes());
            byte messageDigest[] = digest.digest();

            // Create Hex String
            StringBuffer hexString = new StringBuffer();
            for (int i = 0; i < messageDigest.length; i++) {
                String h = Integer.toHexString(0xFF & messageDigest[i]);
                while (h.length() < 2)
                    h = "0" + h;
                hexString.append(h);
            }
            return hexString.toString();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

    private void toggleVPNbutton(Context ctx) {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
        SharedPreferences.Editor editor = prefs.edit();
        boolean vpnenabled = ctx.getSharedPreferences(Api.PREFS_NAME, 0).getBoolean(Api.PREF_VPNENABLED, false);
        Button vpn = (Button) findViewById(R.id.label_vpn);
        if (vpnenabled) {
            vpn.setVisibility(View.VISIBLE);
            editor.putBoolean("vpnsupport", true);
            editor.commit();
        } else {
            vpn.setVisibility(View.GONE);
            editor.putBoolean("vpnsupport", false);
            editor.commit();
        }
    }

    private void toggleRoambutton(Context ctx) {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
        SharedPreferences.Editor editor = prefs.edit();
        boolean roamenabled = ctx.getSharedPreferences(Api.PREFS_NAME, 0).getBoolean(Api.PREF_ROAMENABLED, false);
        Button roam = (Button) findViewById(R.id.label_roam);
        if (roamenabled) {
            roam.setVisibility(View.VISIBLE);
            editor.putBoolean("roamingsupport", true);
            editor.commit();
        } else {
            roam.setVisibility(View.GONE);
            editor.putBoolean("roamingsupport", false);
            editor.commit();
        }
    }

    private void toggleLANbutton(Context ctx) {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
        SharedPreferences.Editor editor = prefs.edit();
        boolean lanenabled = ctx.getSharedPreferences(Api.PREFS_NAME, 0).getBoolean(Api.PREF_LANENABLED, false);
        Button lan = (Button) findViewById(R.id.label_lan);
        if (lanenabled) {
            lan.setVisibility(View.VISIBLE);
            editor.putBoolean("lansupport", true);
            editor.commit();
        } else {
            lan.setVisibility(View.GONE);
            editor.putBoolean("lansupport", false);
            editor.commit();
        }
    }

    private void toggleInputWifiButton(Context ctx) {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
        SharedPreferences.Editor editor = prefs.edit();
        boolean inputwifienabled = ctx.getSharedPreferences(Api.PREFS_NAME, 0).getBoolean(Api.PREF_INPUTENABLED,
                false);
        Button inputwifi = (Button) findViewById(R.id.label_input_wifi);
        if (inputwifienabled) {
            inputwifi.setVisibility(View.VISIBLE);
            editor.putBoolean("inputwifisupport", true);
            editor.commit();
        } else {
            inputwifi.setVisibility(View.GONE);
            editor.putBoolean("inputwifisupport", false);
            editor.commit();
        }
    }

    private void toggleUserSettings(Context ctx) {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
        SharedPreferences.Editor editor = prefs.edit();
        boolean ipv6support = ctx.getSharedPreferences(Api.PREFS_NAME, 0).getBoolean(Api.PREF_IP6TABLES, false);
        boolean logsupport = ctx.getSharedPreferences(Api.PREFS_NAME, 0).getBoolean(Api.PREF_LOGENABLED, false);
        boolean logacceptenabled = ctx.getSharedPreferences(Api.PREFS_NAME, 0).getBoolean(Api.PREF_LOGACCEPTENABLED,
                false);
        boolean notifysupport = ctx.getSharedPreferences(Api.PREFS_NAME, 0).getBoolean(Api.PREF_NOTIFY, false);
        boolean taskerenabled = ctx.getSharedPreferences(Api.PREFS_NAME, 0).getBoolean(Api.PREF_TASKERNOTIFY,
                false);
        boolean sdcard = ctx.getSharedPreferences(Api.PREFS_NAME, 0).getBoolean(Api.PREF_SDCARD, false);
        boolean vpnenabled = ctx.getSharedPreferences(Api.PREFS_NAME, 0).getBoolean(Api.PREF_VPNENABLED, false);
        boolean roamenabled = ctx.getSharedPreferences(Api.PREFS_NAME, 0).getBoolean(Api.PREF_ROAMENABLED, false);
        boolean lanenabled = ctx.getSharedPreferences(Api.PREFS_NAME, 0).getBoolean(Api.PREF_LANENABLED, false);
        boolean autorules = ctx.getSharedPreferences(Api.PREFS_NAME, 0).getBoolean(Api.PREF_AUTORULES, false);
        boolean tetherenabled = ctx.getSharedPreferences(Api.PREFS_NAME, 0).getBoolean(Api.PREF_TETHER, false);
        boolean multiuserenabled = ctx.getSharedPreferences(Api.PREFS_NAME, 0).getBoolean(Api.PREF_MULTIUSER,
                false);
        boolean inputenabled = ctx.getSharedPreferences(Api.PREFS_NAME, 0).getBoolean(Api.PREF_INPUTENABLED, false);
        if (ipv6support) {
            editor.putBoolean("ipv6enabled", true);
            editor.commit();
        } else {
            editor.putBoolean("ipv6enabled", false);
            editor.commit();
        }
        if (logsupport) {
            editor.putBoolean("logenabled", true);
            editor.commit();
        } else {
            editor.putBoolean("logenabled", false);
            editor.commit();
        }
        if (notifysupport) {
            editor.putBoolean("notifyenabled", true);
            editor.commit();
        } else {
            editor.putBoolean("notifyenabled", false);
            editor.commit();
        }
        if (taskerenabled) {
            editor.putBoolean("taskertoastenabled", true);
            editor.commit();
        } else {
            editor.putBoolean("taskertoastenabled", false);
            editor.commit();
        }
        if (sdcard) {
            editor.putBoolean("sdcard", true);
            editor.commit();
        } else {
            editor.putBoolean("sdcard", false);
            editor.commit();
        }
        if (vpnenabled) {
            editor.putBoolean("vpnsupport", true);
            editor.commit();
        } else {
            editor.putBoolean("vpnsupport", false);
            editor.commit();
        }
        if (roamenabled) {
            editor.putBoolean("roamingsupport", true);
            editor.commit();
        } else {
            editor.putBoolean("roamingsupport", false);
            editor.commit();
        }
        if (lanenabled) {
            editor.putBoolean("lansupport", true);
            editor.commit();
        } else {
            editor.putBoolean("lansupport", false);
            editor.commit();
        }
        if (autorules) {
            editor.putBoolean("connectchangerules", true);
            editor.commit();
        } else {
            editor.putBoolean("connectchangerules", false);
            editor.commit();
        }
        if (tetherenabled) {
            editor.putBoolean("tetheringsupport", true);
            editor.commit();
        } else {
            editor.putBoolean("tetheringsupport", false);
            editor.commit();
        }
        if (multiuserenabled) {
            editor.putBoolean("multiuser", true);
            editor.commit();
        } else {
            editor.putBoolean("multiuser", false);
            editor.commit();
        }
        if (inputenabled) {
            editor.putBoolean("inputenabled", true);
            editor.commit();
        } else {
            editor.putBoolean("inputenabled", false);
            editor.commit();
        }
        if (logacceptenabled) {
            editor.putBoolean("logacceptenabled", true);
            editor.commit();
        } else {
            editor.putBoolean("logacceptenabled", false);
            editor.commit();
        }
    }

    /**
     * If the applications are cached, just show them, otherwise load and show
     */
    public void showOrLoadApplications() {
        final Resources res = getResources();
        final String search = "";
        if (Api.applications == null) {
            // The applications are not cached.. so lets display the progress
            // dialog
            final ProgressDialog progress = ProgressDialog.show(this, res.getString(R.string.working),
                    res.getString(R.string.reading_apps), true);
            new AsyncTask<Void, Void, Void>() {
                @Override
                protected Void doInBackground(Void... params) {
                    Api.getApps(MainActivity.this);
                    return null;
                }

                @Override
                protected void onPostExecute(Void result) {
                    try {
                        progress.dismiss();
                    } catch (Exception ex) {
                        Log.d("{AF} - error in showorloadapplications", ex.getMessage());
                    }
                    createListView(search);
                }
            }.execute();
        } else {
            // the applications are cached, just show the list
            createListView(search);
        }
    }

    /**
     * sort apps when searched
     */

    class sortList implements Comparator<DroidApp> {

        @Override
        public int compare(DroidApp o1, DroidApp o2) {
            if (o1.firstseen != o2.firstseen) {
                return (o1.firstseen ? -1 : 1);
            }
            boolean o1_selected = o1.selected_3g || o1.selected_wifi || o1.selected_roaming || o1.selected_vpn
                    || o1.selected_lan || o1.selected_input_wifi;
            boolean o2_selected = o2.selected_3g || o2.selected_wifi || o2.selected_roaming || o2.selected_vpn
                    || o2.selected_lan || o2.selected_input_wifi;

            if (o1_selected == o2_selected) {
                return String.CASE_INSENSITIVE_ORDER.compare(o1.names.get(0).toString(),
                        o2.names.get(0).toString());
            }
            if (o1_selected)
                return -1;
            return 1;
        }
    }

    /**
     * Show the list of applications
     * 
     * Thanks to Ukanth for the Search code so I didn't have to reinvent the
     * wheel
     * 
     */
    private void createListView(final String searching) {
        this.dirty = false;
        List<DroidApp> namesearch = new ArrayList<DroidApp>();
        final List<DroidApp> appnames = Api.getApps(this);
        boolean isResultsFound = false;
        if (searching != null && searching.length() > 1) {
            for (DroidApp app : appnames) {
                for (String str : app.names) {
                    if (str.contains(searching.toLowerCase())
                            || str.toLowerCase().contains(searching.toLowerCase())) {
                        namesearch.add(app);
                        isResultsFound = true;
                    }
                }
            }
        }
        final List<DroidApp> apps = isResultsFound ? namesearch
                : searching.equals("") ? appnames : new ArrayList<Api.DroidApp>();
        // Sort applications - selected first, then alphabetically
        Collections.sort(apps, new sortList());

        final LayoutInflater inflater = getLayoutInflater();
        final ListAdapter adapter = new ArrayAdapter<DroidApp>(this, R.layout.listitem, R.id.itemtext, apps) {
            SharedPreferences prefs = getSharedPreferences(Api.PREFS_NAME, 0);
            boolean vpnenabled = prefs.getBoolean(Api.PREF_VPNENABLED, false);
            boolean roamenabled = prefs.getBoolean(Api.PREF_ROAMENABLED, false);
            boolean lanenabled = prefs.getBoolean(Api.PREF_LANENABLED, false);
            boolean inputwifienabled = prefs.getBoolean(Api.PREF_INPUTENABLED, false);

            @Override
            public View getView(final int position, View convertView, ViewGroup parent) {
                ListEntry entry;
                if (convertView == null) {
                    // Inflate a new view
                    convertView = inflater.inflate(R.layout.listitem, parent, false);
                    Log.d(TAG, ">> inflate(" + convertView + ")");
                    entry = new ListEntry();
                    entry.box_wifi = (CheckBox) convertView.findViewById(R.id.itemcheck_wifi);
                    entry.box_3g = (CheckBox) convertView.findViewById(R.id.itemcheck_3g);
                    entry.box_roaming = (CheckBox) convertView.findViewById(R.id.itemcheck_roam);
                    entry.box_vpn = (CheckBox) convertView.findViewById(R.id.itemcheck_vpn);
                    entry.box_lan = (CheckBox) convertView.findViewById(R.id.itemcheck_lan);
                    entry.box_input_wifi = (CheckBox) convertView.findViewById(R.id.itemcheck_input_wifi);
                    if (vpnenabled) {
                        entry.box_vpn.setVisibility(View.VISIBLE);
                    }
                    if (roamenabled) {
                        entry.box_roaming.setVisibility(View.VISIBLE);
                    }
                    if (lanenabled) {
                        entry.box_lan.setVisibility(View.VISIBLE);
                    }
                    if (inputwifienabled) {
                        entry.box_input_wifi.setVisibility(View.VISIBLE);
                    }
                    entry.text = (TextView) convertView.findViewById(R.id.itemtext);
                    entry.icon = (ImageView) convertView.findViewById(R.id.itemicon);
                    entry.box_wifi.setOnCheckedChangeListener(MainActivity.this);
                    entry.box_3g.setOnCheckedChangeListener(MainActivity.this);
                    entry.box_roaming.setOnCheckedChangeListener(MainActivity.this);
                    entry.box_vpn.setOnCheckedChangeListener(MainActivity.this);
                    entry.box_lan.setOnCheckedChangeListener(MainActivity.this);
                    entry.box_input_wifi.setOnCheckedChangeListener(MainActivity.this);
                    convertView.setTag(entry);
                } else {
                    // Convert an existing view
                    entry = (ListEntry) convertView.getTag();
                    entry.box_wifi = (CheckBox) convertView.findViewById(R.id.itemcheck_wifi);
                    entry.box_3g = (CheckBox) convertView.findViewById(R.id.itemcheck_3g);
                    if (vpnenabled) {
                        entry.box_vpn.setVisibility(View.VISIBLE);
                    }
                    if (roamenabled) {
                        entry.box_roaming.setVisibility(View.VISIBLE);
                    }
                    if (lanenabled) {
                        entry.box_lan.setVisibility(View.VISIBLE);
                    }
                    if (inputwifienabled) {
                        entry.box_input_wifi.setVisibility(View.VISIBLE);
                    }
                    entry.box_roaming = (CheckBox) convertView.findViewById(R.id.itemcheck_roam);
                    entry.box_vpn = (CheckBox) convertView.findViewById(R.id.itemcheck_vpn);
                    entry.box_lan = (CheckBox) convertView.findViewById(R.id.itemcheck_lan);
                    entry.box_input_wifi = (CheckBox) convertView.findViewById(R.id.itemcheck_input_wifi);
                }
                entry.app = apps.get(position);
                entry.text.setText(entry.app.toString());
                entry.icon.setImageDrawable(entry.app.cached_icon);
                if (!entry.app.icon_loaded && entry.app.appinfo != null) {
                    // this icon has not been loaded yet - load it on a
                    // separated thread
                    try {
                        new LoadIconTask().execute(entry.app, getPackageManager(), convertView);
                    } catch (RejectedExecutionException r) {

                    }
                }
                final CheckBox box_wifi = entry.box_wifi;
                box_wifi.setTag(entry.app);
                box_wifi.setChecked(entry.app.selected_wifi);
                final CheckBox box_3g = entry.box_3g;
                box_3g.setTag(entry.app);
                box_3g.setChecked(entry.app.selected_3g);
                final CheckBox box_roaming = entry.box_roaming;
                box_roaming.setTag(entry.app);
                box_roaming.setChecked(entry.app.selected_roaming);
                final CheckBox box_vpn = entry.box_vpn;
                box_vpn.setTag(entry.app);
                box_vpn.setChecked(entry.app.selected_vpn);
                final CheckBox box_lan = entry.box_lan;
                box_lan.setTag(entry.app);
                box_lan.setChecked(entry.app.selected_lan);
                final CheckBox box_input_wifi = entry.box_input_wifi;
                box_input_wifi.setTag(entry.app);
                box_input_wifi.setChecked(entry.app.selected_input_wifi);
                return convertView;
            }
        };
        if (listview == null) {
            Api.applications = null;
            showOrLoadApplications();
        } else {
            this.listview.setAdapter(adapter);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getSupportMenuInflater().inflate(R.menu.menu, menu);
        abs_menu = menu;
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case android.R.id.home:
            if (mDrawerLayout.isDrawerOpen(mDrawerList)) {
                mDrawerLayout.closeDrawer(mDrawerList);
            } else {
                mDrawerLayout.openDrawer(mDrawerList);
            }
            return true;
        case R.id.enableipv4:
            disableOrEnable();
            return true;
        case R.id.applyrules:
            applyOrSaveRules();
            return true;
        case R.id.exit:
            finish();
            System.exit(0);
            return true;
        case R.id.help:
            HelpDialog();
            return true;
        case R.id.usersettings:
            userSettings();
            return true;
        case R.id.sendreport:
            getReports();
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        final MenuItem item_onoff = menu.findItem(R.id.enableipv4);
        final MenuItem item_apply = menu.findItem(R.id.applyrules);
        final boolean enabled = Api.isEnabled(this);
        if (!enabled) {
            item_apply.setTitle(R.string.saverules);
            item_onoff.setChecked(false);
        }
        if (enabled) {
            item_apply.setTitle(R.string.applyrules);
            item_onoff.setChecked(true);
        }
        return super.onPrepareOptionsMenu(menu);
    }

    /**
     * Enables or disables the firewall
     */
    private void disableOrEnable() {
        final boolean enabled = !Api.isEnabled(this);
        Log.d(TAG, "Changing enabled status to: " + enabled);
        Api.setEnabled(this, enabled);
        if (enabled) {
            applyOrSaveRules();
        } else {
            purgeRules();
        }
        refreshHeader();
    }

    /**
     * Set a new lock password
     */
    private void setPassword() {
        new PassDialog(this, true, new android.os.Handler.Callback() {
            public boolean handleMessage(Message msg) {
                if (msg.obj != null) {
                    String confirmPwd = (String) msg.obj;
                    if (confirmPwd.length() > 0) {
                        setConfirmPassword(confirmPwd);
                        Toast.makeText(MainActivity.this, getString(R.string.password_enter_again),
                                Toast.LENGTH_LONG).show();
                        checkPassword();
                    } else {
                        setPassword(confirmPwd);
                    }
                }
                return false;
            }
        }).show();
    }

    private void checkPassword() {
        new PassDialog(this, true, new android.os.Handler.Callback() {
            public boolean handleMessage(Message msg) {
                if (msg.obj != null) {
                    if (getPassword().equals((String) msg.obj)) {
                        setPassword((String) msg.obj);
                    } else {
                        Toast.makeText(MainActivity.this, getString(R.string.password_not_same), Toast.LENGTH_LONG)
                                .show();
                        setPassword();
                    }
                }
                return false;
            }
        }).show();
    }

    /**
     * Ask for password twice and confirm it is the same before setting it to
     * PREF_PASSWORD
     */
    private String userPassword = "";

    public String getPassword() {
        return userPassword;
    }

    public void setConfirmPassword(String userPassword) {
        this.userPassword = userPassword;
    }

    /**
     * Set a new init script
     */
    private void setCustomScript() {
        Intent intent = new Intent();
        intent.setClass(this, CustomScriptActivity.class);
        startActivityForResult(intent, 0);
    }

    // import rules file
    public void importRules() {
        Intent intent = new Intent();
        intent.setClass(this, RulesDialog.class);
        File filepath = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/androidfirewall/");
        if (filepath.isDirectory()) {
            startActivityForResult(intent, IMPORT_RULES_REQUEST);
        } else {
            Toast.makeText(this, R.string.no_rules_file, Toast.LENGTH_LONG).show();
        }

    }

    // export rules file
    public void exportRules() {
        Intent intent = new Intent();
        intent.setClass(this, ExportRulesDialog.class);
        String state = Environment.getExternalStorageState();

        if (Environment.MEDIA_MOUNTED.equals(state)) {
            // We can read and write the media
            startActivityForResult(intent, EXPORT_RULES_REQUEST);
        } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
            // We can only read the media
            Toast.makeText(this, R.string.no_storage, Toast.LENGTH_LONG).show();
        } else {
            // Something else is wrong. It may be one of many other states, but
            // all we need
            // to know is we can neither read nor write
            Toast.makeText(this, R.string.no_storage, Toast.LENGTH_LONG).show();
        }

    }

    // manage Rule files
    public void manageRuleFiles() {
        Intent intent = new Intent();
        intent.setClass(this, DeleteRulesDialog.class);
        File filepath = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/androidfirewall/");
        if (filepath.isDirectory()) {
            startActivityForResult(intent, MANAGE_RULES_REQUEST);
        } else {
            Toast.makeText(this, R.string.no_rules_file, Toast.LENGTH_LONG).show();
        }

    }

    // open save profiles dialog
    public void saveProfile() {
        Intent intent = new Intent();
        intent.setClass(this, SaveProfileDialog.class);
        File filepath = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/androidfirewall/");
        if (filepath.isDirectory()) {
            startActivityForResult(intent, 0);
        } else {
            Toast.makeText(this, R.string.no_rules_file, Toast.LENGTH_LONG).show();
        }

    }

    // open load profile dialog

    public void selectProfile() {
        Intent intent = new Intent();
        intent.setClass(this, LoadProfile.class);
        File filepath = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/androidfirewall/");
        if (filepath.isDirectory()) {
            startActivityForResult(intent, LOAD_PROFILE_REQUEST);
        } else {
            Toast.makeText(this, R.string.no_rules_file, Toast.LENGTH_LONG).show();
        }
    }

    /**
     * Edit profile names
     */
    private void editProfileNames() {
        Intent intent = new Intent();
        intent.setClass(this, EditProfileNames.class);
        startActivityForResult(intent, EDIT_PROFILE_REQUEST);
    }

    /**
     * User Settings
     */
    private void userSettings() {
        Intent intent = new Intent();
        intent.setClass(this, UserSettings.class);
        startActivityForResult(intent, USER_SETTINGS_REQUEST);
    }

    // set Request Code for Rules Import
    static final int IMPORT_RULES_REQUEST = 10;
    // set Request code for Rules export
    static final int EXPORT_RULES_REQUEST = 20;
    // set Request Code for Rule Management
    static final int MANAGE_RULES_REQUEST = 30;
    // set Request Code for Profile loading
    static final int LOAD_PROFILE_REQUEST = 40;
    // set Request Code for Edit Profile Names
    static final int EDIT_PROFILE_REQUEST = 50;
    // set Request Code for User Settings
    static final int USER_SETTINGS_REQUEST = 60;
    // set Request Code for Language Change
    static final int CHANGE_LANGUAGE_REQUEST = 70;

    // @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK && Api.CUSTOM_SCRIPT_MSG.equals(data.getAction())) {
            final String script = data.getStringExtra(Api.SCRIPT_EXTRA);
            final String script2 = data.getStringExtra(Api.SCRIPT2_EXTRA);
            setCustomScript(script, script2);
        }
        if (requestCode == IMPORT_RULES_REQUEST && resultCode == RESULT_OK) {
            Toast.makeText(this, R.string.rules_import_successfully, Toast.LENGTH_SHORT).show();
            Api.applications = null;
            showOrLoadApplications();
            toggleVPNbutton(getApplicationContext());
            toggleRoambutton(getApplicationContext());
            toggleLANbutton(getApplicationContext());
            toggleUserSettings(getApplicationContext());
        }
        if (requestCode == EXPORT_RULES_REQUEST && resultCode == RESULT_OK) {
            Toast.makeText(this, R.string.rules_export_successfully, Toast.LENGTH_SHORT).show();
            String exportedName = data.getStringExtra(Api.EXPORT_EXTRA);
            Api.exportRulesToFile(MainActivity.this, exportedName);

        }
        if (requestCode == MANAGE_RULES_REQUEST && resultCode == RESULT_OK) {
            Toast.makeText(this, R.string.rules_file_deleted, Toast.LENGTH_SHORT).show();
            manageRuleFiles();
        }
        if (requestCode == LOAD_PROFILE_REQUEST && resultCode == RESULT_OK) {
            Toast.makeText(this, R.string.profileapplied, Toast.LENGTH_SHORT).show();
            Api.applications = null;
            showOrLoadApplications();
            refreshHeader();
            refreshSpinner();
            toggleVPNbutton(getApplicationContext());
            toggleRoambutton(getApplicationContext());
            toggleLANbutton(getApplicationContext());
            toggleUserSettings(getApplicationContext());
            if (Api.isEnabled(getApplicationContext())) {
                Api.applyIptablesRules(getApplicationContext(), true);
            } else {
                Api.saveRules(getApplicationContext());
            }
        }
        if (requestCode == EDIT_PROFILE_REQUEST && resultCode == RESULT_OK) {
            updateSpinner();
        }
        if (requestCode == USER_SETTINGS_REQUEST && resultCode == RESULT_OK) {
            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
            Intent intent = getIntent();
            finish();
            toggleVPNbutton(getApplicationContext());
            toggleRoambutton(getApplicationContext());
            toggleLANbutton(getApplicationContext());
            String language = prefs.getString("locale", Locale.getDefault().getDisplayLanguage());
            Api.changeLanguage(getApplicationContext(), language);
            startActivity(intent);
        }
        // for debugging purposes
        // if (resultCode == RESULT_CANCELED)
        // Toast.makeText(this, "Operation Canceled",
        // Toast.LENGTH_SHORT).show();
    }

    /**
     * Set a new init script
     * 
     * @param script
     *            new script (empty to remove)
     * @param script2
     *            new "shutdown" script (empty to remove)
     */
    private void setCustomScript(String script, String script2) {
        final Editor editor = getSharedPreferences(Api.PREFS_NAME, 0).edit();
        // Remove unnecessary white-spaces, also replace '\r\n' if necessary
        script = script.trim().replace("\r\n", "\n");
        script2 = script2.trim().replace("\r\n", "\n");
        editor.putString(Api.PREF_CUSTOMSCRIPT, script);
        editor.putString(Api.PREF_CUSTOMSCRIPT2, script2);
        int msgid;
        if (editor.commit()) {
            if (script.length() > 0 || script2.length() > 0) {
                msgid = R.string.custom_script_defined;
            } else {
                msgid = R.string.custom_script_removed;
            }
        } else {
            msgid = R.string.custom_script_error;
        }
        Toast.makeText(MainActivity.this, msgid, Toast.LENGTH_SHORT).show();
        if (Api.isEnabled(this)) {
            // If the firewall is enabled, re-apply the rules
            applyOrSaveRules();
        }
    }

    /**
     * Show iptable rules on a dialog
     */
    private void showRules() {
        Intent intent = new Intent();
        intent.setClass(this, showRules.class);
        startActivityForResult(intent, 0);
    }

    /**
     * Show logs on a dialog
     */
    private void showLog() {
        Api.dmesgCommand = "dmesg | $GREP \\[AndroidFirewall\\]\n";
        Api.nflogCommand = "[AndroidFirewall]";
        Api.logstring = "[AndroidFirewall]";
        Api.rejectlog = true;
        Intent intent = new Intent();
        intent.setClass(this, showLog.class);
        startActivityForResult(intent, 0);
    }

    /**
     * Show logs on a dialog
     */
    private void showAcceptLog() {
        Api.dmesgCommand = "dmesg | $GREP \\[AndroidFirewallAccept\\]\n";
        Api.nflogCommand = "[AndroidFirewallAccept]";
        Api.logstring = "[AndroidFirewallAccept]";
        Api.rejectlog = false;
        Intent intent = new Intent();
        intent.setClass(this, showLog.class);
        startActivityForResult(intent, 0);
    }

    /**
     * Dispay Help
     */

    private void HelpDialog() {
        Intent intent = new Intent();
        intent.setClass(this, HelpDialog.class);
        startActivityForResult(intent, 0);
    }

    /**
     * Clear logs
     */
    private void clearLog() {
        final Resources res = getResources();
        final ProgressDialog progress = ProgressDialog.show(this, res.getString(R.string.working),
                res.getString(R.string.please_wait), true);
        final Handler handler = new Handler() {
            public void handleMessage(Message msg) {
                try {
                    progress.dismiss();
                } catch (Exception ex) {
                }
                if (!Api.hasRootAccess(MainActivity.this, true))
                    return;
                if (Api.clearLog(MainActivity.this)) {
                    Toast.makeText(MainActivity.this, R.string.log_cleared, Toast.LENGTH_SHORT).show();
                }
            }
        };
        handler.sendEmptyMessageDelayed(0, 100);
    }

    /**
     * Apply or save iptable rules, showing a visual indication
     */
    private void applyOrSaveRules() {
        final Resources res = getResources();
        final boolean enabled = Api.isEnabled(this);
        final ProgressDialog progress = ProgressDialog.show(this, res.getString(R.string.working),
                res.getString(enabled ? R.string.applying_rules : R.string.saving_rules), true);
        final Handler handler = new Handler() {
            public void handleMessage(Message msg) {
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
                int i;
                try {
                    progress.dismiss();
                } catch (Exception ex) {
                }
                if (enabled) {
                    Log.d(TAG, "Applying rules.");
                    if (Api.hasRootAccess(MainActivity.this, true)
                            && Api.applyIptablesRules(MainActivity.this, true)) {
                        Toast.makeText(MainActivity.this, R.string.rules_applied, Toast.LENGTH_SHORT).show();
                        if (abs_menu != null) {
                            final MenuItem item_onoff = abs_menu.findItem(R.id.enableipv4);
                            final MenuItem item_apply = abs_menu.findItem(R.id.applyrules);
                            item_apply.setTitle(R.string.applyrules);
                            item_onoff.setChecked(true);
                        }
                        i = prefs.getInt("itemPosition", 0);
                        if (i == 0) {
                            saveDefaultProfile();
                        }
                        if (i == 1) {
                            saveProfile1();
                        }
                        if (i == 2) {
                            saveProfile2();
                        }
                        if (i == 3) {
                            saveProfile3();
                        }
                        if (i == 4) {
                            saveProfile4();
                        }
                        if (i == 5) {
                            saveProfile5();
                        }
                    } else {
                        Log.d(TAG, "Failed - Disabling firewall.");
                        Api.setEnabled(MainActivity.this, false);
                        if (abs_menu != null) {
                            final MenuItem item_onoff = abs_menu.findItem(R.id.enableipv4);
                            final MenuItem item_apply = abs_menu.findItem(R.id.applyrules);
                            item_apply.setTitle(R.string.saverules);
                            item_onoff.setChecked(false);
                        }
                    }

                }

                else {
                    Log.d(TAG, "Saving rules.");
                    Api.saveRules(MainActivity.this);
                    Toast.makeText(MainActivity.this, R.string.rules_saved, Toast.LENGTH_SHORT).show();
                    i = prefs.getInt("itemPosition", 0);
                    if (i == 0) {
                        saveDefaultProfile();
                    }
                    if (i == 1) {
                        saveProfile1();
                    }
                    if (i == 2) {
                        saveProfile2();
                    }
                    if (i == 3) {
                        saveProfile3();
                    }
                    if (i == 4) {
                        saveProfile4();
                    }
                    if (i == 5) {
                        saveProfile5();
                    }
                }
                MainActivity.this.dirty = false;
            }
        };
        handler.sendEmptyMessageDelayed(0, 100);
    }

    /**
     * Purge iptable rules, showing a visual indication
     */
    private void purgeRules() {
        final Resources res = getResources();
        final ProgressDialog progress = ProgressDialog.show(this, res.getString(R.string.working),
                res.getString(R.string.deleting_rules), true);
        final Handler handler = new Handler() {
            public void handleMessage(Message msg) {
                try {
                    progress.dismiss();
                } catch (Exception ex) {
                }
                if (!Api.hasRootAccess(MainActivity.this, true))
                    return;
                if (Api.purgeIptables(MainActivity.this, true)) {
                    Toast.makeText(MainActivity.this, R.string.rules_deleted, Toast.LENGTH_SHORT).show();
                    if (abs_menu != null) {
                        final MenuItem item_onoff = abs_menu.findItem(R.id.enableipv4);
                        final MenuItem item_apply = abs_menu.findItem(R.id.applyrules);
                        item_apply.setTitle(R.string.saverules);
                        item_onoff.setChecked(false);
                    }
                }
            }
        };
        handler.sendEmptyMessageDelayed(0, 100);
    }

    /**
     * Called an application is check/unchecked
     */
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        final DroidApp app = (DroidApp) buttonView.getTag();
        if (app != null) {
            switch (buttonView.getId()) {
            case R.id.itemcheck_wifi:
                if (app.selected_wifi != isChecked) {
                    app.selected_wifi = isChecked;
                    this.dirty = true;
                }
                break;
            case R.id.itemcheck_3g:
                if (app.selected_3g != isChecked) {
                    app.selected_3g = isChecked;
                    this.dirty = true;
                }
                break;
            case R.id.itemcheck_roam:
                if (app.selected_roaming != isChecked) {
                    app.selected_roaming = isChecked;
                    this.dirty = true;
                }
                break;
            case R.id.itemcheck_vpn:
                if (app.selected_vpn != isChecked) {
                    app.selected_vpn = isChecked;
                    this.dirty = true;
                }
                break;
            case R.id.itemcheck_lan:
                if (app.selected_lan != isChecked) {
                    app.selected_lan = isChecked;
                    this.dirty = true;
                }
                break;
            case R.id.itemcheck_input_wifi:
                if (app.selected_input_wifi != isChecked) {
                    app.selected_input_wifi = isChecked;
                    this.dirty = true;
                }
                break;
            }
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.label_mode:
            selectMode();
            break;
        case R.id.label_wifi:
            selectAllWiFi();
            break;
        case R.id.label_data:
            selectAllData();
            break;
        case R.id.label_roam:
            selectAllRoam();
            break;
        case R.id.label_clear:
            clearAllEntries();
            break;
        case R.id.label_invert:
            invertApps();
            break;
        case R.id.label_vpn:
            selectAllVpn();
            break;
        case R.id.label_lan:
            selectAllLan();
            break;
        case R.id.label_input_wifi:
            selectAllInputWifi();
            break;
        }
    }

    /**
     * The following functions are for selecting all of a certain rule
     */

    private void selectAllData() {
        BaseAdapter adapter = (BaseAdapter) listview.getAdapter();
        int count = adapter.getCount();
        for (int item = 0; item < count; item++) {
            DroidApp app = (DroidApp) adapter.getItem(item);
            app.selected_3g = true;
            this.dirty = true;
        }
        adapter.notifyDataSetChanged();
    }

    private void selectAllRoam() {
        BaseAdapter adapter = (BaseAdapter) listview.getAdapter();
        int count = adapter.getCount();
        for (int item = 0; item < count; item++) {
            DroidApp app = (DroidApp) adapter.getItem(item);
            app.selected_roaming = true;
            this.dirty = true;
        }
        adapter.notifyDataSetChanged();
    }

    private void selectAllWiFi() {
        BaseAdapter adapter = (BaseAdapter) listview.getAdapter();
        int count = adapter.getCount();
        for (int item = 0; item < count; item++) {
            DroidApp app = (DroidApp) adapter.getItem(item);
            app.selected_wifi = true;
            this.dirty = true;
        }
        adapter.notifyDataSetChanged();
    }

    private void clearAllEntries() {
        SharedPreferences prefs = getSharedPreferences(Api.PREFS_NAME, Context.MODE_PRIVATE);
        boolean vpnenabled = prefs.getBoolean(Api.PREF_VPNENABLED, false);
        boolean roamenabled = prefs.getBoolean(Api.PREF_ROAMENABLED, false);
        boolean lanenabled = prefs.getBoolean(Api.PREF_LANENABLED, false);
        boolean inputwifienabled = prefs.getBoolean(Api.PREF_INPUTENABLED, false);
        BaseAdapter adapter = (BaseAdapter) listview.getAdapter();
        int count = adapter.getCount();
        for (int item = 0; item < count; item++) {
            DroidApp app = (DroidApp) adapter.getItem(item);
            app.selected_wifi = false;
            if (roamenabled) {
                app.selected_roaming = false;
            }
            app.selected_3g = false;
            if (vpnenabled) {
                app.selected_vpn = false;
            }
            if (lanenabled) {
                app.selected_lan = false;
            }
            if (inputwifienabled) {
                app.selected_input_wifi = false;
            }
            this.dirty = true;
        }
        adapter.notifyDataSetChanged();
    }

    private void invertApps() {
        BaseAdapter adapter = (BaseAdapter) listview.getAdapter();
        SharedPreferences prefs = getSharedPreferences(Api.PREFS_NAME, Context.MODE_PRIVATE);
        boolean vpnenabled = prefs.getBoolean(Api.PREF_VPNENABLED, false);
        boolean lanenabled = prefs.getBoolean(Api.PREF_LANENABLED, false);
        boolean inputwifienabled = prefs.getBoolean(Api.PREF_INPUTENABLED, false);
        int count = adapter.getCount();
        for (int item = 0; item < count; item++) {
            DroidApp app = (DroidApp) adapter.getItem(item);
            app.selected_3g = !app.selected_3g;
            app.selected_wifi = !app.selected_wifi;
            if (vpnenabled) {
                app.selected_vpn = !app.selected_vpn;
            }
            if (lanenabled) {
                app.selected_lan = !app.selected_lan;
            }
            if (inputwifienabled) {
                app.selected_input_wifi = !app.selected_input_wifi;
            }
            this.dirty = true;
        }
        adapter.notifyDataSetChanged();
    }

    private void selectAllVpn() {
        BaseAdapter adapter = (BaseAdapter) listview.getAdapter();
        int count = adapter.getCount();
        for (int item = 0; item < count; item++) {
            DroidApp app = (DroidApp) adapter.getItem(item);
            app.selected_vpn = true;
            this.dirty = true;
        }
        adapter.notifyDataSetChanged();
    }

    private void selectAllLan() {
        BaseAdapter adapter = (BaseAdapter) listview.getAdapter();
        int count = adapter.getCount();
        for (int item = 0; item < count; item++) {
            DroidApp app = (DroidApp) adapter.getItem(item);
            app.selected_lan = true;
            this.dirty = true;
        }
        adapter.notifyDataSetChanged();
    }

    private void selectAllInputWifi() {
        BaseAdapter adapter = (BaseAdapter) listview.getAdapter();
        int count = adapter.getCount();
        for (int item = 0; item < count; item++) {
            DroidApp app = (DroidApp) adapter.getItem(item);
            app.selected_input_wifi = true;
            this.dirty = true;
        }
        adapter.notifyDataSetChanged();
    }

    @Override
    public boolean onKeyDown(final int keyCode, final KeyEvent event) {
        // Handle the back button when dirty
        if (this.dirty && (keyCode == KeyEvent.KEYCODE_BACK)) {
            final DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    switch (which) {
                    case DialogInterface.BUTTON_POSITIVE:
                        applyOrSaveRules();
                        finish();
                        break;
                    case DialogInterface.BUTTON_NEGATIVE:
                        // Propagate the event back to perform the desired
                        // action
                        MainActivity.super.onKeyDown(keyCode, event);
                        finish();
                        break;
                    }
                }
            };
            final AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle(R.string.unsaved_changes).setMessage(R.string.unsaved_changes_message)
                    .setPositiveButton(R.string.apply, dialogClickListener)
                    .setNegativeButton(R.string.discard, dialogClickListener).show();
            // Say that we've consumed the event
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    /**
     * Asynchronous task used to load icons in a background thread.
     */
    private static class LoadIconTask extends AsyncTask<Object, Void, View> {
        @Override
        protected View doInBackground(Object... params) {
            try {
                final DroidApp app = (DroidApp) params[0];
                final PackageManager pkgMgr = (PackageManager) params[1];
                final View viewToUpdate = (View) params[2];
                if (!app.icon_loaded) {
                    app.cached_icon = pkgMgr.getApplicationIcon(app.appinfo);
                    app.icon_loaded = true;
                }
                // Return the view to update at "onPostExecute"
                // Note that we cannot be sure that this view still references
                // "app"
                return viewToUpdate;
            } catch (Exception e) {
                Log.e(TAG, "Error loading icon", e);
                return null;
            }
        }

        protected void onPostExecute(View viewToUpdate) {
            try {
                // This is executed in the UI thread, so it is safe to use
                // viewToUpdate.getTag()
                // and modify the UI
                final ListEntry entryToUpdate = (ListEntry) viewToUpdate.getTag();
                entryToUpdate.icon.setImageDrawable(entryToUpdate.app.cached_icon);
            } catch (Exception e) {
                Log.e(TAG, "Error showing icon", e);
            }
        };
    }

    /**
     * Entry representing an application in the screen
     */
    private static class ListEntry {
        private CheckBox box_wifi;
        private CheckBox box_3g;
        private CheckBox box_roaming;
        private CheckBox box_vpn;
        private CheckBox box_lan;
        private CheckBox box_input_wifi;
        private TextView text;
        private ImageView icon;
        private DroidApp app;
    }

    private void LoadDefaultProfile() {
        SharedPreferences prefs = getSharedPreferences(Api.PREFS_NAME, Context.MODE_PRIVATE);
        final SharedPreferences prefs2 = getSharedPreferences(Api.PREF_PROFILE, Context.MODE_PRIVATE);
        final Editor editRules = prefs.edit();
        editRules.clear();
        for (Entry<String, ?> entry : prefs2.getAll().entrySet()) {
            Object rule = entry.getValue();
            String keys = entry.getKey();
            if (rule instanceof Boolean)
                editRules.putBoolean(keys, ((Boolean) rule).booleanValue());
            else if (rule instanceof Float)
                editRules.putFloat(keys, ((Float) rule).floatValue());
            else if (rule instanceof String)
                editRules.putString(keys, ((String) rule));
            else if (rule instanceof Long)
                editRules.putLong(keys, ((Long) rule).longValue());
            else if (rule instanceof Integer)
                editRules.putInt(keys, ((Integer) rule).intValue());
        }
        editRules.commit();
        Api.applications = null;
        showOrLoadApplications();
        refreshHeader();
        toggleVPNbutton(getApplicationContext());
        toggleRoambutton(getApplicationContext());
        toggleLANbutton(getApplicationContext());
        toggleInputWifiButton(getApplicationContext());
        toggleUserSettings(getApplicationContext());
        if (Api.isEnabled(getApplicationContext())) {
            Api.applyIptablesRules(getApplicationContext(), true);
            if (abs_menu != null) {
                final MenuItem item_onoff = abs_menu.findItem(R.id.enableipv4);
                final MenuItem item_apply = abs_menu.findItem(R.id.applyrules);
                item_apply.setTitle(R.string.applyrules);
                item_onoff.setChecked(true);
            }
        } else {
            Api.saveRules(getApplicationContext());
            if (abs_menu != null) {
                final MenuItem item_onoff = abs_menu.findItem(R.id.enableipv4);
                final MenuItem item_apply = abs_menu.findItem(R.id.applyrules);
                item_apply.setTitle(R.string.saverules);
                item_onoff.setChecked(false);
            }
        }
    }

    private void LoadProfile1() {
        SharedPreferences prefs = getSharedPreferences(Api.PREFS_NAME, Context.MODE_PRIVATE);
        final SharedPreferences prefs2 = getSharedPreferences(Api.PREF_PROFILE1, Context.MODE_PRIVATE);
        final Editor editRules = prefs.edit();
        editRules.clear();
        for (Entry<String, ?> entry : prefs2.getAll().entrySet()) {
            Object rule = entry.getValue();
            String keys = entry.getKey();
            if (rule instanceof Boolean)
                editRules.putBoolean(keys, ((Boolean) rule).booleanValue());
            else if (rule instanceof Float)
                editRules.putFloat(keys, ((Float) rule).floatValue());
            else if (rule instanceof String)
                editRules.putString(keys, ((String) rule));
            else if (rule instanceof Long)
                editRules.putLong(keys, ((Long) rule).longValue());
            else if (rule instanceof Integer)
                editRules.putInt(keys, ((Integer) rule).intValue());
        }
        editRules.commit();
        Api.applications = null;
        showOrLoadApplications();
        refreshHeader();
        toggleVPNbutton(getApplicationContext());
        toggleRoambutton(getApplicationContext());
        toggleLANbutton(getApplicationContext());
        toggleInputWifiButton(getApplicationContext());
        toggleUserSettings(getApplicationContext());
        if (Api.isEnabled(getApplicationContext())) {
            Api.applyIptablesRules(getApplicationContext(), true);
            if (abs_menu != null) {
                final MenuItem item_onoff = abs_menu.findItem(R.id.enableipv4);
                final MenuItem item_apply = abs_menu.findItem(R.id.applyrules);
                item_apply.setTitle(R.string.applyrules);
                item_onoff.setChecked(true);
            }
        } else {
            Api.saveRules(getApplicationContext());
            if (abs_menu != null) {
                final MenuItem item_onoff = abs_menu.findItem(R.id.enableipv4);
                final MenuItem item_apply = abs_menu.findItem(R.id.applyrules);
                item_apply.setTitle(R.string.saverules);
                item_onoff.setChecked(false);
            }
        }
    }

    private void LoadProfile2() {
        SharedPreferences prefs = getSharedPreferences(Api.PREFS_NAME, Context.MODE_PRIVATE);
        final SharedPreferences prefs2 = getSharedPreferences(Api.PREF_PROFILE2, Context.MODE_PRIVATE);
        final Editor editRules = prefs.edit();
        editRules.clear();
        for (Entry<String, ?> entry : prefs2.getAll().entrySet()) {
            Object rule = entry.getValue();
            String keys = entry.getKey();
            if (rule instanceof Boolean)
                editRules.putBoolean(keys, ((Boolean) rule).booleanValue());
            else if (rule instanceof Float)
                editRules.putFloat(keys, ((Float) rule).floatValue());
            else if (rule instanceof String)
                editRules.putString(keys, ((String) rule));
            else if (rule instanceof Long)
                editRules.putLong(keys, ((Long) rule).longValue());
            else if (rule instanceof Integer)
                editRules.putInt(keys, ((Integer) rule).intValue());
        }
        editRules.commit();
        Api.applications = null;
        showOrLoadApplications();
        refreshHeader();
        toggleVPNbutton(getApplicationContext());
        toggleRoambutton(getApplicationContext());
        toggleLANbutton(getApplicationContext());
        toggleInputWifiButton(getApplicationContext());
        toggleUserSettings(getApplicationContext());
        if (Api.isEnabled(getApplicationContext())) {
            Api.applyIptablesRules(getApplicationContext(), true);
            if (abs_menu != null) {
                final MenuItem item_onoff = abs_menu.findItem(R.id.enableipv4);
                final MenuItem item_apply = abs_menu.findItem(R.id.applyrules);
                item_apply.setTitle(R.string.applyrules);
                item_onoff.setChecked(true);
            }
        } else {
            Api.saveRules(getApplicationContext());
            if (abs_menu != null) {
                final MenuItem item_onoff = abs_menu.findItem(R.id.enableipv4);
                final MenuItem item_apply = abs_menu.findItem(R.id.applyrules);
                item_apply.setTitle(R.string.saverules);
                item_onoff.setChecked(false);
            }
        }
    }

    private void LoadProfile3() {
        SharedPreferences prefs = getSharedPreferences(Api.PREFS_NAME, Context.MODE_PRIVATE);
        final SharedPreferences prefs2 = getSharedPreferences(Api.PREF_PROFILE3, Context.MODE_PRIVATE);
        final Editor editRules = prefs.edit();
        editRules.clear();
        for (Entry<String, ?> entry : prefs2.getAll().entrySet()) {
            Object rule = entry.getValue();
            String keys = entry.getKey();
            if (rule instanceof Boolean)
                editRules.putBoolean(keys, ((Boolean) rule).booleanValue());
            else if (rule instanceof Float)
                editRules.putFloat(keys, ((Float) rule).floatValue());
            else if (rule instanceof String)
                editRules.putString(keys, ((String) rule));
            else if (rule instanceof Long)
                editRules.putLong(keys, ((Long) rule).longValue());
            else if (rule instanceof Integer)
                editRules.putInt(keys, ((Integer) rule).intValue());
        }
        editRules.commit();
        Api.applications = null;
        showOrLoadApplications();
        refreshHeader();
        toggleVPNbutton(getApplicationContext());
        toggleRoambutton(getApplicationContext());
        toggleLANbutton(getApplicationContext());
        toggleInputWifiButton(getApplicationContext());
        toggleUserSettings(getApplicationContext());
        if (Api.isEnabled(getApplicationContext())) {
            Api.applyIptablesRules(getApplicationContext(), true);
            if (abs_menu != null) {
                final MenuItem item_onoff = abs_menu.findItem(R.id.enableipv4);
                final MenuItem item_apply = abs_menu.findItem(R.id.applyrules);
                item_apply.setTitle(R.string.applyrules);
                item_onoff.setChecked(true);
            }
        } else {
            Api.saveRules(getApplicationContext());
            if (abs_menu != null) {
                final MenuItem item_onoff = abs_menu.findItem(R.id.enableipv4);
                final MenuItem item_apply = abs_menu.findItem(R.id.applyrules);
                item_apply.setTitle(R.string.saverules);
                item_onoff.setChecked(false);
            }
        }
    }

    private void LoadProfile4() {
        SharedPreferences prefs = getSharedPreferences(Api.PREFS_NAME, Context.MODE_PRIVATE);
        final SharedPreferences prefs2 = getSharedPreferences(Api.PREF_PROFILE4, Context.MODE_PRIVATE);
        final Editor editRules = prefs.edit();
        editRules.clear();
        for (Entry<String, ?> entry : prefs2.getAll().entrySet()) {
            Object rule = entry.getValue();
            String keys = entry.getKey();
            if (rule instanceof Boolean)
                editRules.putBoolean(keys, ((Boolean) rule).booleanValue());
            else if (rule instanceof Float)
                editRules.putFloat(keys, ((Float) rule).floatValue());
            else if (rule instanceof String)
                editRules.putString(keys, ((String) rule));
            else if (rule instanceof Long)
                editRules.putLong(keys, ((Long) rule).longValue());
            else if (rule instanceof Integer)
                editRules.putInt(keys, ((Integer) rule).intValue());
        }
        editRules.commit();
        Api.applications = null;
        showOrLoadApplications();
        refreshHeader();
        toggleVPNbutton(getApplicationContext());
        toggleRoambutton(getApplicationContext());
        toggleLANbutton(getApplicationContext());
        toggleInputWifiButton(getApplicationContext());
        toggleUserSettings(getApplicationContext());
        if (Api.isEnabled(getApplicationContext())) {
            Api.applyIptablesRules(getApplicationContext(), true);
            if (abs_menu != null) {
                final MenuItem item_onoff = abs_menu.findItem(R.id.enableipv4);
                final MenuItem item_apply = abs_menu.findItem(R.id.applyrules);
                item_apply.setTitle(R.string.applyrules);
                item_onoff.setChecked(true);
            }
        } else {
            Api.saveRules(getApplicationContext());
            if (abs_menu != null) {
                final MenuItem item_onoff = abs_menu.findItem(R.id.enableipv4);
                final MenuItem item_apply = abs_menu.findItem(R.id.applyrules);
                item_apply.setTitle(R.string.saverules);
                item_onoff.setChecked(false);
            }
        }
    }

    private void LoadProfile5() {
        SharedPreferences prefs = getSharedPreferences(Api.PREFS_NAME, Context.MODE_PRIVATE);
        final SharedPreferences prefs2 = getSharedPreferences(Api.PREF_PROFILE5, Context.MODE_PRIVATE);
        final Editor editRules = prefs.edit();
        editRules.clear();
        for (Entry<String, ?> entry : prefs2.getAll().entrySet()) {
            Object rule = entry.getValue();
            String keys = entry.getKey();
            if (rule instanceof Boolean)
                editRules.putBoolean(keys, ((Boolean) rule).booleanValue());
            else if (rule instanceof Float)
                editRules.putFloat(keys, ((Float) rule).floatValue());
            else if (rule instanceof String)
                editRules.putString(keys, ((String) rule));
            else if (rule instanceof Long)
                editRules.putLong(keys, ((Long) rule).longValue());
            else if (rule instanceof Integer)
                editRules.putInt(keys, ((Integer) rule).intValue());
        }
        editRules.commit();
        Api.applications = null;
        showOrLoadApplications();
        refreshHeader();
        toggleVPNbutton(getApplicationContext());
        toggleRoambutton(getApplicationContext());
        toggleLANbutton(getApplicationContext());
        toggleInputWifiButton(getApplicationContext());
        toggleUserSettings(getApplicationContext());
        if (Api.isEnabled(getApplicationContext())) {
            Api.applyIptablesRules(getApplicationContext(), true);
            if (abs_menu != null) {
                final MenuItem item_onoff = abs_menu.findItem(R.id.enableipv4);
                final MenuItem item_apply = abs_menu.findItem(R.id.applyrules);
                item_apply.setTitle(R.string.applyrules);
                item_onoff.setChecked(true);
            }
        } else {
            Api.saveRules(getApplicationContext());
            if (abs_menu != null) {
                final MenuItem item_onoff = abs_menu.findItem(R.id.enableipv4);
                final MenuItem item_apply = abs_menu.findItem(R.id.applyrules);
                item_apply.setTitle(R.string.saverules);
                item_onoff.setChecked(false);
            }
        }
    }

    private void saveDefaultProfile() {
        SharedPreferences prefs2 = getSharedPreferences(Api.PREFS_NAME, Context.MODE_PRIVATE);
        final SharedPreferences prefs = getSharedPreferences(Api.PREF_PROFILE, Context.MODE_PRIVATE);
        final Editor editRules = prefs.edit();
        editRules.clear();
        for (Entry<String, ?> entry : prefs2.getAll().entrySet()) {
            Object rule = entry.getValue();
            String keys = entry.getKey();
            if (rule instanceof Boolean)
                editRules.putBoolean(keys, ((Boolean) rule).booleanValue());
            else if (rule instanceof Float)
                editRules.putFloat(keys, ((Float) rule).floatValue());
            else if (rule instanceof String)
                editRules.putString(keys, ((String) rule));
            else if (rule instanceof Long)
                editRules.putLong(keys, ((Long) rule).longValue());
            else if (rule instanceof Integer)
                editRules.putInt(keys, ((Integer) rule).intValue());
        }
        editRules.commit();
    }

    private void saveProfile1() {
        SharedPreferences prefs2 = getSharedPreferences(Api.PREFS_NAME, Context.MODE_PRIVATE);
        final SharedPreferences prefs = getSharedPreferences(Api.PREF_PROFILE1, Context.MODE_PRIVATE);
        final Editor editRules = prefs.edit();
        editRules.clear();
        for (Entry<String, ?> entry : prefs2.getAll().entrySet()) {
            Object rule = entry.getValue();
            String keys = entry.getKey();
            if (rule instanceof Boolean)
                editRules.putBoolean(keys, ((Boolean) rule).booleanValue());
            else if (rule instanceof Float)
                editRules.putFloat(keys, ((Float) rule).floatValue());
            else if (rule instanceof String)
                editRules.putString(keys, ((String) rule));
            else if (rule instanceof Long)
                editRules.putLong(keys, ((Long) rule).longValue());
            else if (rule instanceof Integer)
                editRules.putInt(keys, ((Integer) rule).intValue());
        }
        editRules.commit();
    }

    private void saveProfile2() {
        SharedPreferences prefs2 = getSharedPreferences(Api.PREFS_NAME, Context.MODE_PRIVATE);
        final SharedPreferences prefs = getSharedPreferences(Api.PREF_PROFILE2, Context.MODE_PRIVATE);
        final Editor editRules = prefs.edit();
        editRules.clear();
        for (Entry<String, ?> entry : prefs2.getAll().entrySet()) {
            Object rule = entry.getValue();
            String keys = entry.getKey();
            if (rule instanceof Boolean)
                editRules.putBoolean(keys, ((Boolean) rule).booleanValue());
            else if (rule instanceof Float)
                editRules.putFloat(keys, ((Float) rule).floatValue());
            else if (rule instanceof String)
                editRules.putString(keys, ((String) rule));
            else if (rule instanceof Long)
                editRules.putLong(keys, ((Long) rule).longValue());
            else if (rule instanceof Integer)
                editRules.putInt(keys, ((Integer) rule).intValue());
        }
        editRules.commit();
    }

    private void saveProfile3() {
        SharedPreferences prefs2 = getSharedPreferences(Api.PREFS_NAME, Context.MODE_PRIVATE);
        final SharedPreferences prefs = getSharedPreferences(Api.PREF_PROFILE3, Context.MODE_PRIVATE);
        final Editor editRules = prefs.edit();
        editRules.clear();
        for (Entry<String, ?> entry : prefs2.getAll().entrySet()) {
            Object rule = entry.getValue();
            String keys = entry.getKey();
            if (rule instanceof Boolean)
                editRules.putBoolean(keys, ((Boolean) rule).booleanValue());
            else if (rule instanceof Float)
                editRules.putFloat(keys, ((Float) rule).floatValue());
            else if (rule instanceof String)
                editRules.putString(keys, ((String) rule));
            else if (rule instanceof Long)
                editRules.putLong(keys, ((Long) rule).longValue());
            else if (rule instanceof Integer)
                editRules.putInt(keys, ((Integer) rule).intValue());
        }
        editRules.commit();
    }

    private void saveProfile4() {
        SharedPreferences prefs2 = getSharedPreferences(Api.PREFS_NAME, Context.MODE_PRIVATE);
        final SharedPreferences prefs = getSharedPreferences(Api.PREF_PROFILE4, Context.MODE_PRIVATE);
        final Editor editRules = prefs.edit();
        editRules.clear();
        for (Entry<String, ?> entry : prefs2.getAll().entrySet()) {
            Object rule = entry.getValue();
            String keys = entry.getKey();
            if (rule instanceof Boolean)
                editRules.putBoolean(keys, ((Boolean) rule).booleanValue());
            else if (rule instanceof Float)
                editRules.putFloat(keys, ((Float) rule).floatValue());
            else if (rule instanceof String)
                editRules.putString(keys, ((String) rule));
            else if (rule instanceof Long)
                editRules.putLong(keys, ((Long) rule).longValue());
            else if (rule instanceof Integer)
                editRules.putInt(keys, ((Integer) rule).intValue());
        }
        editRules.commit();
    }

    private void saveProfile5() {
        SharedPreferences prefs2 = getSharedPreferences(Api.PREFS_NAME, Context.MODE_PRIVATE);
        final SharedPreferences prefs = getSharedPreferences(Api.PREF_PROFILE5, Context.MODE_PRIVATE);
        final Editor editRules = prefs.edit();
        editRules.clear();
        for (Entry<String, ?> entry : prefs2.getAll().entrySet()) {
            Object rule = entry.getValue();
            String keys = entry.getKey();
            if (rule instanceof Boolean)
                editRules.putBoolean(keys, ((Boolean) rule).booleanValue());
            else if (rule instanceof Float)
                editRules.putFloat(keys, ((Float) rule).floatValue());
            else if (rule instanceof String)
                editRules.putString(keys, ((String) rule));
            else if (rule instanceof Long)
                editRules.putLong(keys, ((Long) rule).longValue());
            else if (rule instanceof Integer)
                editRules.putInt(keys, ((Integer) rule).intValue());
        }
        editRules.commit();
    }

    private TextWatcher filterTextWatcher = new TextWatcher() {

        public void afterTextChanged(Editable s) {
            createListView(s.toString());
        }

        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        public void onTextChanged(CharSequence s, int start, int before, int count) {
            createListView(s.toString());
        }
    };

    @Override
    public boolean onKeyUp(final int keyCode, final KeyEvent event) {

        if (event.getAction() == KeyEvent.ACTION_UP) {
            switch (keyCode) {
            case KeyEvent.KEYCODE_MENU:
                if (abs_menu != null) {
                    abs_menu.performIdentifierAction(R.id.menu_items, 0);
                    return true;
                }
            }
        }
        return super.onKeyUp(keyCode, event);
    }

    /**
     * many thanks to Mr. Cernekee for this GPLv3 code Original code located
     * here:
     * 
     * https://github.com/ukanth/afwall/blob/master/src/dev/ukanth/ufirewall/Api
     * .java
     * 
     */

    private void toggleLogtarget() {
        final Context ctx = getApplicationContext();

        LogProbeCallback cb = new LogProbeCallback();
        cb.ctx = ctx;

        new RootCommand().setReopenShell(true).setFailureToast(R.string.log_failed).setCallback(cb).setLogging(true)
                .run(ctx, "cat /proc/net/ip_tables_targets");
    }

    private class LogProbeCallback extends RootCommand.Callback {
        public Context ctx;

        SharedPreferences prefs = getApplicationContext().getSharedPreferences(Api.PREFS_NAME, 0);
        final Editor editor = prefs.edit();
        boolean nflog = false;
        boolean log = false;

        public void cbFunc(RootCommand state) {
            if (state.exitCode != 0) {
                return;
            }

            for (String str : state.lastCommandResult.toString().split("\n")) {
                if ("NFLOG".equals(str)) {
                    nflog = true;
                    Log.d(TAG, "NFLOG fetch " + Api.PREF_LOGTARGET);
                } else if ("LOG".equals(str)) {
                    Log.d(TAG, "LOG fetch " + Api.PREF_LOGTARGET);
                    log = true;
                }
                if (nflog == true && log == true) {
                    editor.putString(Api.PREF_LOGTARGET, "LOG");
                    editor.commit();
                }
                if (log == true && nflog == false) {
                    editor.putString(Api.PREF_LOGTARGET, "LOG");
                    editor.commit();
                }
                if (log == false && nflog == true) {
                    editor.putString(Api.PREF_LOGTARGET, "NFLOG");
                    editor.commit();
                }
                if (log == false && nflog == false) {
                    editor.putString(Api.PREF_LOGTARGET, "");
                    editor.commit();
                    Log.d(TAG, "Empty fetch " + Api.PREF_LOGTARGET);
                }
            }
        }
    }

    @SuppressLint("NewApi")
    public void isCurrentUserOwner(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            try {
                Method getUserHandle = UserManager.class.getMethod("getUserHandle");
                int userHandle = (Integer) getUserHandle.invoke(context.getSystemService(Context.USER_SERVICE));
                Log.d(TAG, String.format("Found user value = %d", userHandle));
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
                SharedPreferences.Editor editor = prefs.edit();
                editor.putLong("userID", userHandle);
                editor.commit();
            } catch (Exception e) {
                Log.d(TAG, "Exception on isCurrentUserOwner " + e.getMessage());
            }
        }
    }

    public void toggleUser() {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        SharedPreferences.Editor editor = prefs.edit();
        boolean multiuserenabled = getApplicationContext().getSharedPreferences(Api.PREFS_NAME, 0)
                .getBoolean(Api.PREF_MULTIUSER, false);
        if (prefs.getLong("userID", 0) == 0) {
            Log.d(TAG, "userHandle is 0");
            editor.putString("chainName", "droidwall");
            editor.commit();
            Log.d(TAG, "User = " + prefs.getLong("userID", 0) + " and CHAINNAME = "
                    + prefs.getString("chainName", ""));
        } else {
            Log.d(TAG, "userHandle greater than 0");
            if (multiuserenabled) {
                editor.putString("chainName", prefs.getLong("userID", 0) + "droidwall");
                editor.commit();
                Log.d(TAG, "User = " + prefs.getLong("userID", 0) + " and CHAINNAME = "
                        + prefs.getString("chainName", ""));
            } else {
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setTitle(R.string.multiuser_title);
                builder.setMessage(R.string.multiuser_disabled);
                builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        userSettings();
                    }
                });
                AlertDialog dialog = builder.show();
                TextView msg = (TextView) dialog.findViewById(android.R.id.message);
                msg.setGravity(Gravity.CENTER);
            }
        }
    }

    /**
     * get error reports
     */

    private void getReports() {
        String state = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED.equals(state)) {
            // We can read and write the media
            Toast.makeText(MainActivity.this, R.string.generate_reports, Toast.LENGTH_SHORT).show();
            getInterfaceInfo();
            Log.d(TAG, "Able to read/write to external storage while running reports");
        } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
            // We can only read the media
            Toast.makeText(this, R.string.no_storage, Toast.LENGTH_LONG).show();
            Log.d(TAG, "Read only access to external storage while trying to run reports");
        } else {
            // Something else is wrong. It may be one of many other states, but
            // all we need
            // to know is we can neither read nor write
            Toast.makeText(this, R.string.no_storage, Toast.LENGTH_LONG).show();
            Log.d(TAG, "Something is wrong with access to external storage while trying to run reports");
        }
    }

    /**
     * get Interface Information
     */

    private void getInterfaceInfo() {
        final Context ctx = getApplicationContext();

        InterfaceCallback cb = new InterfaceCallback();
        cb.ctx = ctx;

        new RootCommand().setReopenShell(true).setFailureToast(R.string.interface_fail).setCallback(cb)
                .setLogging(true).run(ctx, "ls /sys/class/net");
    }

    private class InterfaceCallback extends RootCommand.Callback {
        public Context ctx;
        File sdCard = Environment.getExternalStorageDirectory();
        File dir = new File(sdCard.getAbsolutePath() + "/af_error_reports/");
        String filename = "interfaces.txt";
        File file = new File(dir, filename);
        FileOutputStream fout = null;
        OutputStreamWriter output = null;

        public void cbFunc(RootCommand state) {
            if (state.exitCode != 0) {
                return;
            }
            dir.mkdirs();

            try {
                for (String str : state.lastCommandResult.toString().split("\r\n")) {
                    Log.d(TAG, str);
                    fout = new FileOutputStream(file);
                    output = new OutputStreamWriter(fout);
                    output.write(str, 0, str.length());
                }
            } catch (IOException e) {
                Log.e(TAG, "File write failed: " + e.toString());
            } finally {
                try {
                    if (output != null) {
                        output.close();
                        Log.d(TAG, "OUTPUT Closed");
                    }
                    if (fout != null) {
                        fout.close();
                        Log.d(TAG, "FOUT Closed");
                        getIptablesInfo();
                    }
                } catch (IOException e) {
                    Log.e(TAG, String.format("File close failed: %s", e.toString()));
                }
            }
        }
    }

    /**
     * Get iptables information
     */

    private void getIptablesInfo() {
        final Context ctx = getApplicationContext();
        File sdCard = Environment.getExternalStorageDirectory();
        File dir = new File(sdCard.getAbsolutePath() + "/af_error_reports/");
        String filename = "iptables.txt";
        File file = new File(dir, filename);
        FileOutputStream fout = null;
        OutputStreamWriter output = null;
        String iptables = Api.showIptablesRules(ctx);

        try {
            for (String str : iptables.split("\r\n")) {
                fout = new FileOutputStream(file);
                output = new OutputStreamWriter(fout);
                output.write(str, 0, str.length());
            }
        } catch (IOException e) {
            Log.e(TAG, "File write failed: " + e.toString());
        } finally {
            try {
                if (output != null) {
                    output.close();
                    Log.d(TAG, "OUTPUT Closed");
                }
                if (fout != null) {
                    fout.close();
                    Log.d(TAG, "FOUT Closed");
                    getLogcatInfo();
                }
            } catch (IOException e) {
                Log.e(TAG, String.format("File close failed: %s", e.toString()));
            }
        }
    }

    /**
     * get Logcat Information
     */

    private void getLogcatInfo() {
        final Context ctx = getApplicationContext();

        LogcatCallback cb = new LogcatCallback();
        cb.ctx = ctx;

        new RootCommand().setReopenShell(true).setFailureToast(R.string.interface_fail).setCallback(cb)
                .setLogging(true).run(ctx, "logcat -d");
    }

    private class LogcatCallback extends RootCommand.Callback {
        public Context ctx;
        File sdCard = Environment.getExternalStorageDirectory();
        File dir = new File(sdCard.getAbsolutePath() + "/af_error_reports/");
        String filename = "logcat.txt";
        File file = new File(dir, filename);
        FileOutputStream fout = null;
        OutputStreamWriter output = null;

        public void cbFunc(RootCommand state) {
            if (state.exitCode != 0) {
                return;
            }
            dir.mkdirs();

            try {
                for (String str : state.lastCommandResult.toString().split("\r\n")) {
                    fout = new FileOutputStream(file);
                    output = new OutputStreamWriter(fout);
                    output.write(str, 0, str.length());
                }
            } catch (IOException e) {
                Log.e(TAG, "File write failed: " + e.toString());
            } finally {
                try {
                    if (output != null) {
                        output.close();
                        Log.d(TAG, "OUTPUT Closed");
                    }
                    if (fout != null) {
                        fout.close();
                        Log.d(TAG, "FOUT Closed");
                        zipFiles();
                    }
                } catch (IOException e) {
                    Log.e(TAG, String.format("File close failed: %s", e.toString()));
                }
            }
        }
    }

    /**
     * Zip error reports
     */

    public void zipFiles() {
        File sdCard = Environment.getExternalStorageDirectory();
        File dir = new File(sdCard.getAbsolutePath() + "/af_error_reports/");
        String filename = "af_error_reports.zip";
        String[] reports = { dir + "/iptables.txt", dir + "/logcat.txt", dir + "/interfaces.txt" };
        File file = new File(dir, filename);

        try {
            BufferedInputStream origin = null;
            FileOutputStream dest = new FileOutputStream(file);
            ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));
            byte data[] = new byte[2048];

            for (int i = 0; i < reports.length; i++) {
                Log.v(TAG, "Compressing folder: " + reports[i]);
                FileInputStream fi = new FileInputStream(reports[i]);
                origin = new BufferedInputStream(fi, 2048);
                ZipEntry entry = new ZipEntry(reports[i].substring(reports[i].lastIndexOf("/") + 1));
                out.putNextEntry(entry);
                int count;
                while ((count = origin.read(data, 0, 2048)) != -1) {
                    out.write(data, 0, count);
                }
                origin.close();
            }
            out.close();
            Toast.makeText(MainActivity.this, R.string.generate_zip, Toast.LENGTH_SHORT).show();
            emailErrorReports();
        } catch (Exception e) {
            Log.e(TAG, "Error zipping folder");
            e.printStackTrace();
        }
    }

    /**
     * Email error reports
     */

    private void emailErrorReports() {
        File sdCard = Environment.getExternalStorageDirectory();
        File dir = new File(sdCard.getAbsolutePath() + "/af_error_reports/");
        String filename = "af_error_reports.zip";
        File file = new File(dir, filename);
        String af_version;
        try {
            af_version = getApplicationContext().getPackageManager()
                    .getPackageInfo(getApplicationContext().getPackageName(), 0).versionName;
        } catch (NameNotFoundException e) {
            af_version = "Unknown";
        }
        Intent intent = new Intent(Intent.ACTION_SEND);
        intent.setType("text/plain");
        intent.putExtra(Intent.EXTRA_EMAIL, new String[] { "androidfirewall.developer@gmail.com" });
        intent.putExtra(Intent.EXTRA_SUBJECT, "Android Firewall Error Report for version " + af_version);
        intent.putExtra(Intent.EXTRA_TEXT, "");
        if (!file.exists() || !file.canRead()) {
            Toast.makeText(this, R.string.no_zip, Toast.LENGTH_SHORT).show();
            Log.d(TAG, "No zip file is available");
            finish();
            return;
        }
        Uri uri = Uri.fromFile(file);
        intent.putExtra(Intent.EXTRA_STREAM, uri);
        startActivity(Intent.createChooser(intent, getString(R.string.send_email)));
        return;
    }
}