public class SettingsSpinnerAdapter implements SpinnerAdapter {

    private String[] displayText = {"3x3", "4x4"};
    private long[] ids = {UserDefault.v3x3, UserDefault.v4x4};
    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        AppCompatTextView ret = new AppCompatTextView(parent.getContext());
        ret.setText(displayText[position]);
        ret.setTextSize(16);
        ret.setPadding(0, 10, 0, 10);
        ret.setTextColor(Color.BLACK);
        return ret;
    }

    @Override
    public void registerDataSetObserver(DataSetObserver observer) {

    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {

    }

    @Override
    public int getCount() {
        return 2;
    }

    @Override
    public Object getItem(int position) {
        return displayText[position];
    }

    @Override
    public long getItemId(int position) {
        return ids[position];
    }

    @Override
    public boolean hasStableIds() {
        return false;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        AppCompatTextView ret = new AppCompatTextView(parent.getContext());
        ret.setText(displayText[position]);
        ret.setTextSize(16);
        ret.setPadding(0, 10, 0, 10);
        ret.setTextColor(Color.BLACK);
        return ret;
    }

    @Override
    public int getItemViewType(int position) {
        return 0;
    }

    @Override
    public int getViewTypeCount() {
        return 0;
    }

    @Override
    public boolean isEmpty() {
        return false;
    }
} public class Account {

    private Long id;
    /** Not-null value. */
    private String name;
    private long type;
    private String account;
    private String masked_account;
    private Boolean hide_name;
    private String account_salt;
    /** Not-null value. */
    private String salt;
    /** Not-null value. */
    private String hash;
    private String additional;
    private String additional_salt;
    private long category;
    /** Not-null value. */
    private String tag;
    private String website;
    private Long last_access;
    private String icon;

    // KEEP FIELDS - put your custom fields here
    // KEEP FIELDS END

    public Account() {
    }

    public Account(Long id) {
        this.id = id;
    }

    public Account(Long id, String name, long type, String account, String masked_account, Boolean hide_name, String account_salt, String salt, String hash, String additional, String additional_salt, long category, String tag, String website, Long last_access, String icon) {
        this.id = id;
        this.name = name;
        this.type = type;
        this.account = account;
        this.masked_account = masked_account;
        this.hide_name = hide_name;
        this.account_salt = account_salt;
        this.salt = salt;
        this.hash = hash;
        this.additional = additional;
        this.additional_salt = additional_salt;
        this.category = category;
        this.tag = tag;
        this.website = website;
        this.last_access = last_access;
        this.icon = icon;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    /** Not-null value. */
    public String getName() {
        return name;
    }

    /** Not-null value; ensure this value is available before it is saved to the database. */
    public void setName(String name) {
        this.name = name;
    }

    public long getType() {
        return type;
    }

    public void setType(long type) {
        this.type = type;
    }

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getMasked_account() {
        return masked_account;
    }

    public void setMasked_account(String masked_account) {
        this.masked_account = masked_account;
    }

    public Boolean getHide_name() {
        return hide_name;
    }

    public void setHide_name(Boolean hide_name) {
        this.hide_name = hide_name;
    }

    public String getAccount_salt() {
        return account_salt;
    }

    public void setAccount_salt(String account_salt) {
        this.account_salt = account_salt;
    }

    /** Not-null value. */
    public String getSalt() {
        return salt;
    }

    /** Not-null value; ensure this value is available before it is saved to the database. */
    public void setSalt(String salt) {
        this.salt = salt;
    }

    /** Not-null value. */
    public String getHash() {
        return hash;
    }

    /** Not-null value; ensure this value is available before it is saved to the database. */
    public void setHash(String hash) {
        this.hash = hash;
    }

    public String getAdditional() {
        return additional;
    }

    public void setAdditional(String additional) {
        this.additional = additional;
    }

    public String getAdditional_salt() {
        return additional_salt;
    }

    public void setAdditional_salt(String additional_salt) {
        this.additional_salt = additional_salt;
    }

    public long getCategory() {
        return category;
    }

    public void setCategory(long category) {
        this.category = category;
    }

    /** Not-null value. */
    public String getTag() {
        return tag;
    }

    /** Not-null value; ensure this value is available before it is saved to the database. */
    public void setTag(String tag) {
        this.tag = tag;
    }

    public String getWebsite() {
        return website;
    }

    public void setWebsite(String website) {
        this.website = website;
    }

    public Long getLast_access() {
        return last_access;
    }

    public void setLast_access(Long last_access) {
        this.last_access = last_access;
    }

    public String getIcon() {
        return icon;
    }

    public void setIcon(String icon) {
        this.icon = icon;
    }

    // KEEP METHODS - put your custom methods here
    // KEEP METHODS END

}
 public class AccountHelper {
    private static AccountHelper ourInstance;
    private Context context;
    private DaoMaster daoMaster;
    private DaoSession daoSession;
    private AccountDao accountDao;

    public static AccountHelper getInstance(Context context) {
        if (ourInstance == null) {
            ourInstance = new AccountHelper(context);
        }
        return ourInstance;
    }

    private AccountHelper(Context context) {
        this.context = context;
        getDaoMaster();
        getDaoSession();
        accountDao = daoSession.getAccountDao();
    }

    public DaoMaster getDaoMaster(){
        if (daoMaster == null) {
            DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(context, AppConstants.DB_NAME, null);
            daoMaster = new DaoMaster(helper.getWritableDatabase());
        }
        return daoMaster;
    }

    public DaoSession getDaoSession(){
        if (daoSession == null) {
            if (daoMaster == null) {
                daoMaster = getDaoMaster();
            }
            daoSession = daoMaster.newSession();
        }
        return daoSession;
    }

    public Account getAccount(long id) {
        return accountDao.load(id);
    }

    public ArrayList<Account> getAllAccount() {
        return (ArrayList<Account>) accountDao.loadAll();
    }

    public ArrayList<Account> queryAccount(String where,String ... params) {
        return (ArrayList<Account>) accountDao.queryRaw(where, params);
    }

    public long saveAccount(Account account) {
        if (account.getId() == null || getAccount(account.getId()) == null)
            return accountDao.insertOrReplace(account);
        accountDao.update(account);
        return account.getId();
    }

    public void deleteAccount(long id) {
        accountDao.deleteByKey(id);
    }

    public void deleteAccount(Account account) {
        accountDao.delete(account);
    }

    public boolean hasMasterPassword() {
        List result = accountDao.queryBuilder()
                .where(AccountDao.Properties.Type.eq(AppConstants.TYPE_MASTER))
                .list();
        return result.size() != 0;
    }

    public boolean hasQuickAccess() {
        List result = accountDao.queryBuilder()
                .where(AccountDao.Properties.Type.eq(AppConstants.TYPE_QUICK))
                .list();
        return result.size() != 0;
    }

    public Account getMasterAccount() {
        List result = accountDao.queryBuilder()
                .where(AccountDao.Properties.Type.eq(AppConstants.TYPE_MASTER))
                .list();
        return result.size() == 0 ? null : (Account) result.get(0);
    }

    public Account getQuickAccount() {
        List result = accountDao.queryBuilder()
                .where(AccountDao.Properties.Type.eq(AppConstants.TYPE_QUICK))
                .list();
        return result.size() == 0 ? null : (Account) result.get(0);
    }

    public void clearQuickAccount() {
        accountDao.queryBuilder()
                .where(AccountDao.Properties.Type.eq(AppConstants.TYPE_QUICK))
                .buildDelete()
                .executeDeleteWithoutDetachingEntities();
    }

    public ArrayList<Account> getAccountsByCategory(Long category) {
        return (ArrayList) accountDao.queryBuilder()
                .where(AccountDao.Properties.Category.eq(category),
                        AccountDao.Properties.Type.notEq(AppConstants.TYPE_MASTER),
                        AccountDao.Properties.Type.notEq(AppConstants.TYPE_QUICK))
                        .orderDesc(AccountDao.Properties.Id)
                        .list();
    }

    public  ArrayList<Account> getRecentUsed(int limit) {
        return (ArrayList) accountDao.queryBuilder()
                .where(AccountDao.Properties.Type.notEq(AppConstants.TYPE_MASTER),
                        AccountDao.Properties.Type.notEq(AppConstants.TYPE_QUICK))
                .orderDesc(AccountDao.Properties.Last_access)
                .limit(limit)
                .list();

    }
} public class CryptoEvent {
    private String result, field;
    private int type;

    public CryptoEvent(String result, int type){
        this.result = result;
        this.type = type;
    }

    public CryptoEvent(String result, int type, String field){
        this.result = result;
        this.type = type;
        this.field = field;
    }

    public String getResult() {
        return result;
    }

    public int getType() {
        return type;
    }

    public String getField() {
        return field;
    }
} public class DBExportEvent {
    public boolean success;
    public String filePath;

    public DBExportEvent(boolean success, String filePath) {
        this.success = success;
        this.filePath = filePath;
    }
} public class ChangePasswordRunnable implements Runnable {

    private Context context;
    private ArrayList<Account> accounts;
//    private Stack<Account> accounts;
    private String oldPassword, newPassword;
    public ChangePasswordRunnable(Context context, String oldPassword, String newPassword) {
        this.context = context;
        this.oldPassword = oldPassword;
        this.newPassword = newPassword;

        EventBus.getDefault().register(this);

        accounts = AccountHelper.getInstance(null).getAllAccount();
    }
    @Override
    public void run() {
        CryptoEvent result = null;
        new PBKDFRunnable(newPassword.toString()).run();
        try {
            for (Account account : accounts) {
                if (account.getType() == AppConstants.TYPE_QUICK || account.getType() == AppConstants.TYPE_MASTER)
                    continue;

                    String acct = new String(decrypt(Base64.decode(account.getAccount(), Base64.DEFAULT)));//.replace(account.getAccount_salt(), "");
                    String passwd = new String(decrypt(Base64.decode(account.getHash(), Base64.DEFAULT)));//.replace(account.getSalt(), "");
                    String addt = new String(decrypt(Base64.decode(account.getAdditional(), Base64.DEFAULT)));//.replace(account.getAdditional_salt(), "");

                    account.setAccount(Base64.encodeToString(encrypt(acct), Base64.DEFAULT));
                    account.setHash(Base64.encodeToString(encrypt(passwd), Base64.DEFAULT));
                    account.setAdditional(Base64.encodeToString(encrypt(addt), Base64.DEFAULT));

                    AccountHelper.getInstance(null).saveAccount(account);
            }
            result = new CryptoEvent("", AppConstants.TYPE_MASTER_CHANGE, "master");
        } catch (Exception e) {
            e.printStackTrace();
            result = new CryptoEvent("", AppConstants.TYPE_SHTHPPN, "master");
        } finally {
            EventBus.getDefault().post(result);
        }

    }

    private byte[] encrypt(String text) throws Exception{
        SecretKeySpec skeySpec = new SecretKeySpec(newPassword.getBytes("UTF-8"), "Blowfish");
        Cipher cipher = Cipher.getInstance("Blowfish");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(text.getBytes());
        return encrypted;
    }

    public byte[] decrypt(byte[] rawText) throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(oldPassword.getBytes("UTF-8"), "Blowfish");
        Cipher cipher = Cipher.getInstance("Blowfish");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        byte[] decrypted = cipher.doFinal(rawText);
        return decrypted;
    }

    public void onEventMainThread(CryptoEvent event) {
        if (!event.getField().equalsIgnoreCase("master")) {
            return;
        }
        if (event.getType() == AppConstants.TYPE_ENCRYPT) {
            Account account = AccountHelper.getInstance(null).getMasterAccount();
            if (account == null) {
                account = new Account();
            }
            account.setHash(event.getResult());
            account.setSalt("");
            account.setName("");
            account.setType(AppConstants.TYPE_MASTER);
            account.setCategory(AppConstants.CAT_ID_PRIVATE);
            account.setTag("");
            AccountHelper.getInstance(null).saveAccount(account);
            EventBus.getDefault().unregister(this);
        }
    }
} public class DBExportRunnable implements Runnable {

    private Context context;
    private String dbSrcPath;
    private String dbDstPath;

    public DBExportRunnable(Context context) {
        this.context = context;
        dbSrcPath = context.getDatabasePath(AppConstants.DB_NAME).getAbsolutePath();
        dbDstPath = Environment.getExternalStorageDirectory() + "/data/data/leela/";
        File dstPath = new File(dbDstPath);
        if (!dstPath.exists()) {
            dstPath.mkdirs();
        }
        dbDstPath += "database.db";
    }

    @Override
    public void run() {
        try {
            File source = new File(dbSrcPath);
            File dest   = new File(dbDstPath);
            if (dest.exists()) {
                dest.delete();
            } else {
                dest.createNewFile();
            }
            FileInputStream fis = new FileInputStream(source);
            FileOutputStream fos = new FileOutputStream(dest);
            byte[] cache = new byte[512];
            int byteRead;
            while ((byteRead = fis.read(cache)) > 0) {
                fos.write(cache, 0, byteRead);
            }
            fis.close();
            fos.close();
            EventBus.getDefault().post(new DBExportEvent(true, dest.getAbsolutePath()));
        } catch (IOException e) {
            e.printStackTrace();
            EventBus.getDefault().post(new DBExportEvent(false, null));
        }

    }
} public class SelectorItem extends MaterialSettingsItem {

    private SpinnerAdapter adapter;
    private int selectedPos = -1;
    private AdapterView.OnItemSelectedListener onItemSelectedListener;

    public SelectorItem(Context ctx, String name) {
        super(ctx, name);
    }

    @Override
    public int getViewResource() {
        return R.layout.layout_selector_item;
    }

    @Override
    public void setupView(View view) {
        AppCompatSpinner spinner = (AppCompatSpinner)view.findViewById(R.id.settings_spinner);
        spinner.setAdapter(adapter);
        spinner.setOnItemSelectedListener(onItemSelectedListener);
        if (selectedPos != -1)
            spinner.setSelection(selectedPos);
    }

    @Override
    public void save() {

    }

    public SpinnerAdapter getAdapter() {
        return adapter;
    }

    public SelectorItem setAdapter(SpinnerAdapter adapter) {
        this.adapter = adapter;
        return this;
    }

    public AdapterView.OnItemSelectedListener getOnItemClickListener() {
        return onItemSelectedListener;
    }

    public SelectorItem setOnItemClickListener(AdapterView.OnItemSelectedListener onItemClickListener) {
        this.onItemSelectedListener = onItemClickListener;
        return this;
    }

    public void setSelectedPos(int pos) {
        selectedPos = pos;
    }
} public class AppConstants {

    public static final Boolean debug = true;

    public static final String DB_NAME = "account.db";

    //Events Types
    public static final int TYPE_ENCRYPT = 0x233;
    public static final int TYPE_DECRYPT = 0x234;
    public static final int TYPE_SHTHPPN = 0x235;
    public static final int TYPE_MASTERPWD  = 0x236; //Event with master password.
    public static final int TYPE_FINISHED = 0x257;
    public static final int TYPE_CANCELED = 0x258;
    public static final int TYPE_MASTER_OK = 0x259;  //Master passwd is correct
    public static final int TYPE_MASTER_NO = 0x260;  //Master passwd is wrong

    public static final int TYPE_MASTER_CHANGE = 0x261; //Change master password

    //Category Type
    //Only custom type category can be deleted.
    public static final int CAT_TYPE_BUILTIN = 0x100;
    public static final int CAT_TYPE_CUSTOM  = 0x101;

    //Builtin Category ID
    public static final long CAT_ID_PRIVATE  = -1;
    public static final long CAT_ID_RECENT  = 1;
    public static final long CAT_ID_MAIL     = 2;
    public static final long CAT_ID_SOCIAL   = 3;
    public static final long CAT_ID_CARDS    = 4;
    public static final long CAT_ID_COMPUTERS  = 5;
    public static final long CAT_ID_DEVICE   = 6;
    public static final long CAT_ID_ENTRY    = 7;
    public static final long CAT_ID_WEBSITE  = 8;

    public static final int TYPE_MASTER = 0x5020;//The account type in db
    public static final int TYPE_QUICK  = 0x5022;

    public static final int REQUEST_CODE_ADD_TYPE = 0x6001;
    public static final int REQUEST_CODE_ADD_CATE = 0x6002;
    public static final int REQUEST_CODE_IMAGE     = 0x6003;
    public static final int REQUEST_CODE_CROP      = 0x6004;
    public static final int REQUEST_CODE_GEN_PWD   = 0x6005;
    public static final int REQUEST_CODE_EDIT      = 0x6006;

    public static final String SERVICE_CMD_START = "start";
    public static final String SERVICE_CMD_PASTE_ACCT = "paste_acct";
    public static final String SERVICE_CMD_PASTE_PSWD = "paste_pswd";
    public static final String SERVICE_CMD_PASTE_ADDT = "paste_addt";
} public class CryptoUtil {

    private Context context;
    private OnEncryptedListener onEncryptedListener;
    private OnDecryptedListener onDecryptedListener;
    private String account, passwd, addt, accountHash, passwdHash, addtHash;
    private String[] salts;
    private AppCompatDialog dialog;
    private int type;

    public CryptoUtil(Context context, OnEncryptedListener onEncryptedListener) {
        this.context = context;
        this.onEncryptedListener = onEncryptedListener;
        this.type = AppConstants.TYPE_ENCRYPT;
        init();
    }

    public CryptoUtil(Context context, OnDecryptedListener onDecryptedListener) {
        this.context = context;
        this.onDecryptedListener = onDecryptedListener;
        this.type = AppConstants.TYPE_DECRYPT;
        init();
    }

    private void init(){
        EventBus.getDefault().register(this);
        salts = new String[3];
        for(int i = 0; i < salts.length; i++) {
            salts[i] = UUID.randomUUID().toString();
        }
    }

    public CryptoUtil setOnEncryptedListener(OnEncryptedListener onEncryptedListener) {
        this.onEncryptedListener = onEncryptedListener;
        this.type = AppConstants.TYPE_ENCRYPT;
        return this;
    }

    public CryptoUtil setOnDecryptedListener(OnDecryptedListener onDecryptedListener) {
        this.onDecryptedListener = onDecryptedListener;
        this.type = AppConstants.TYPE_DECRYPT;
        return this;
    }

    public void runEncrypt(String account, String password, String addtional) {
        /**
         * To encrypt an account information, we need -
         * i. Hash Account name
         * ii. Hash Password
         * iii. Hash Additional Code if exists.
         */
        //Wait for main password.
        assert this.onEncryptedListener != null;
        this.account = account;
        this.passwd = password;
        this.addt = addtional;
        askForMasterPassword();
    }

    public void runDecrypt(String account, String password, String additional,
                           String acctSlt, String psswdSlt, String addtSalt) {
        assert this.onDecryptedListener != null;
        this.accountHash = account;
        this.passwdHash = password;
        this.addtHash = additional;
        this.salts[0] = acctSlt;
        this.salts[1] = psswdSlt;
        this.salts[2] = addtSalt;
        askForMasterPassword();
    }

    private void runEncrypt(String password) {
        // TODO: 16/4/4 Actual encrypt process.
        new Thread(new CryptoRunnable(this.account + salts[0], password, AppConstants.TYPE_ENCRYPT, "account")).start();
        new Thread(new CryptoRunnable(this.passwd + salts[1], password, AppConstants.TYPE_ENCRYPT, "password")).start();
        new Thread(new CryptoRunnable(this.addt + salts[2], password, AppConstants.TYPE_ENCRYPT, "addt")).start();

    }

    private void runDecrypt(String password) {
        new Thread(new CryptoRunnable(this.accountHash, password, AppConstants.TYPE_DECRYPT, "account")).start();
        new Thread(new CryptoRunnable(this.passwdHash, password, AppConstants.TYPE_DECRYPT, "password")).start();
        new Thread(new CryptoRunnable(this.addtHash, password, AppConstants.TYPE_DECRYPT, "addt")).start();
    }


    public interface OnEncryptedListener {
        void onEncrypted(String acctHash, String passwdHash, String addtHash,
                         String acctSalt, String passwdSalt, String addtSalt);
    }
    public interface OnDecryptedListener {
        void onDecrypted(String account, String passwd, String addt);
    }

    public void askForMasterPassword() {
        if (!AccountHelper.getInstance(this.context).hasMasterPassword()) {
            return;
        }

        if (UserDefault.getInstance(this.context).hasQuickPassword()) {
            Intent intent = new Intent(this.context, SetQuickPasswordActivity.class);
            intent.putExtra("type", SetQuickPasswordActivity.ShowTypeVerify);
            this.context.startActivity(intent);

        } else {
            Intent intent = new Intent(this.context, AuthorizeActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
            this.context.getApplicationContext().startActivity(intent);
        }
    }

    public void onEventMainThread(CryptoEvent event) {
        switch (event.getType()) {
            case AppConstants.TYPE_MASTERPWD:
                if (type == AppConstants.TYPE_DECRYPT) {
                    this.dialog = ResUtil.getInstance(null).showProgressbar((Activity) context);
                    runDecrypt(event.getResult());
                } else {
                    this.dialog = ResUtil.getInstance(null).showProgressbar((Activity) context);
                    runEncrypt(event.getResult());
                }
                break;
            case AppConstants.TYPE_DECRYPT:
                // TODO: 16/4/4 Decrypted, dismiss dialog & publish event.
                switch (event.getField()) {
                    case "account":
                        this.account = event.getResult();
                        break;
                    case "password":
                        this.passwd = event.getResult();
                        break;
                    case "addt":
                        this.addt = event.getResult();
                        break;
                    default:
                        if (dialog != null) {
                            dialog.dismiss();
                        }
                        return;
                }
                if (this.account != null && this.passwd != null && this.addt != null) {
//                    Log.e("LEELA", "Decrypted Callback");
                    account = account.replace(salts[0], "");
                    passwd = passwd.replace(salts[1], "");
                    addt = addt.replace(salts[2], "");
                    this.onDecryptedListener.onDecrypted(account, passwd, addt);
                    EventBus.getDefault().unregister(this);
                }
                dialog.dismiss();
                break;
            case AppConstants.TYPE_ENCRYPT:
                if (event.getField() == null) {
                    if (dialog != null) {
                        dialog.dismiss();
                    }
                    return;
                }
                switch (event.getField()) {
                    case "account":
                        this.accountHash = event.getResult();
                        break;
                    case "password":
                        this.passwdHash = event.getResult();
                        break;
                    case "addt":
                        this.addtHash = event.getResult();
                        break;
                    default:
                        if (dialog != null) {
                            dialog.dismiss();
                        }
                        return;
                }
                if (this.accountHash != null && this.passwdHash != null && this.addtHash != null) {
                    dialog.dismiss();
                    this.onEncryptedListener.onEncrypted(accountHash, passwdHash, addtHash,
                            salts[0], salts[1], salts[2]);
                    EventBus.getDefault().unregister(this);
                }
                break;
            case AppConstants.TYPE_CANCELED:
                EventBus.getDefault().unregister(this);
                break;
            case AppConstants.TYPE_SHTHPPN:
                if (dialog != null) {
                    dialog.dismiss();
                }
                break;
            default:
                if (dialog != null) {
                    dialog.dismiss();
                }
                break;
        }
    }


} public class ResUtil {
    private static ResUtil ourInstance;
    private Context context;
    public static ResUtil getInstance(Context context) {
        if (ourInstance == null) {
            ourInstance = new ResUtil(context);
        }
        return ourInstance;
    }

    private ResUtil(Context context) {
        this.context = context;
    }

    public float getDP(){
        return context.getResources().getDisplayMetrics().density;
    }

    public int pointToDp(int point) {
        return (int) (point * getDP());
    }

    public Bitmap getBmpInAssets(String assetName) throws IOException {
        return BitmapFactory.decodeStream(context.getResources().getAssets().open(assetName));
    }

    public Bitmap getBmp(String fileName) throws IOException {
        if (fileName.startsWith("/")) {
            //File System
            return BitmapFactory.decodeStream(new FileInputStream(fileName));
        } else {
            //Assets
            return BitmapFactory.decodeStream(context.getResources().getAssets().open(fileName));
        }
    }

    public Uri getBmpUri(String fileName) {
        if (fileName.startsWith("/")) {
            return Uri.fromFile(new File(fileName));
        } else {
            return Uri.parse("file:///android_asset/" + fileName);
        }

    }

    public Object getBmpPath(String fileName) {
        if (fileName.startsWith("/")) {
            return fileName;
        } else {
            InputStream ret;
            try {
                ret =  context.getResources().getAssets().open(fileName);
            } catch (IOException e) {
                e.printStackTrace();
                return "";
            }
            return ret;
        }
    }

    public AppCompatDialog showProgressbar(Activity activity, long timeout, boolean cancelable) {
        final AppCompatDialog dialog = new AppCompatDialog(activity);
        dialog.setContentView(R.layout.dialog_progress);
        dialog.setCancelable(cancelable);
        dialog.setTitle("Progressing...");
        ProgressBar progressBar = (ProgressBar) dialog.findViewById(R.id.progress);
        if (timeout > 0) {
            Handler handler = new Handler(activity.getMainLooper());
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    dialog.cancel();
                    dialog.dismiss();
                }
            }, timeout);
            dialog.show();
        } else {
            dialog.show();
        }
        return dialog;
    }

    public AppCompatDialog showProgressbar(Activity activity, long timeout) {
        return showProgressbar(activity, timeout, true);
    }

    public AppCompatDialog showProgressbar(Activity activity) {
        return showProgressbar(activity, 0, false);
    }

    public static void hideSoftKeyboard(View view) {
        if (view != null) {
            InputMethodManager imm = (InputMethodManager)view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }
    }
} public class UserDefault extends StorageInterface {
    private Context context;
    private static UserDefault ourInstance;
    private SharedPreferences sharedPreferences;

    public static UserDefault getInstance(Context context) {
        if (ourInstance == null)
            ourInstance = new UserDefault(context);
        return ourInstance;
    }

    private UserDefault(Context context) {
        this.context = context;
        this.sharedPreferences = context.getSharedPreferences("UserDefaultPrivate", Context.MODE_PRIVATE);
    }

    public UserDefault writeInt(String key, int value) {
        sharedPreferences.edit().putInt(key, value).commit();
        return this;
    }

    public UserDefault writeString(String key, String value){
        sharedPreferences.edit().putString(key, value).commit();
        return this;
    }

    public UserDefault writeBoolean(String key, boolean value) {
        sharedPreferences.edit().putBoolean(key, value).commit();
        return this;
    }

    public boolean hasQuickPassword() {
        return sharedPreferences.getBoolean(kSettingsHasQuickPassword, false);
    }

    public void setHasQuickPassword() {
        sharedPreferences.edit().putBoolean(kSettingsHasQuickPassword, true).commit();
    }

    public void clearQuickPassword() {
        sharedPreferences.edit().putBoolean(kSettingsHasQuickPassword, false).commit();
    }

    public int getInt(String key) {
        return sharedPreferences.getInt(key, -1);
    }

    public boolean getBoolean(String key) {
        return sharedPreferences.getBoolean(key, true);
    }

    public String getString(String key) {
        return sharedPreferences.getString(key, "");
    }

    public int getAutoClearTimeInSeconds() {
        return 60;
    }

    @Override
    public void save(String s, Boolean aBoolean) {
        sharedPreferences.edit().putBoolean(s, aBoolean).commit();
    }

    @Override
    public boolean load(String s, Boolean aBoolean) {
        return sharedPreferences.getBoolean(s, false);
    }

    @Override
    public void save(String s, String s1) {
        sharedPreferences.edit().putString(s, s1).commit();
    }

    @Override
    public String load(String s, String s1) {
        return sharedPreferences.getString(s, s1);
    }

    @Override
    public void save(String s, Integer integer) {
        sharedPreferences.edit().putInt(s, integer).commit();
    }

    @Override
    public Integer load(String s, Integer integer) {
        return sharedPreferences.getInt(s, integer);
    }

    @Override
    public void save(String s, Float aFloat) {
        sharedPreferences.edit().putFloat(s, aFloat).commit();
    }

    @Override
    public Float load(String s, Float aFloat) {
        return sharedPreferences.getFloat(s, aFloat);
    }

    @Override
    public void save(String s, Long aLong) {
        sharedPreferences.edit().putLong(s, aLong).commit();
    }

    @Override
    public Long load(String s, Long aLong) {
        return sharedPreferences.getLong(s, aLong);
    }

    @Override
    public Map<String, ?> getAll() {
        return sharedPreferences.getAll();
    }

    public long getQuickPassByte() {
        return sharedPreferences.getLong(kSettingsQuickPassByte, v4x4);
    }

    public void setQuickPassByte(long b) {
        sharedPreferences.edit().putLong(kSettingsQuickPassByte, b).commit();
    }

    public void setNeedPasswordWhenLaunch(boolean need) {
        sharedPreferences.edit().putBoolean(kNeedPasswordWhenLaunch, need).commit();
    }

    public boolean needPasswordWhenLaunch() {
        return sharedPreferences.getBoolean(kNeedPasswordWhenLaunch, false);
    }

    public static final String kSettingsHasQuickPassword    = "kSettingsHasQuickPassword";
    public static final String kSettingsQuickPassByte       = "kSettingsQuickPassByte";
    public static final String kNeedPasswordWhenLaunch      = "kNeedPasswordWhenLaunch";
    public static final long v3x3                           = 0x1033;
    public static final long v4x4                           = 0x1044;
}
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.provider.Settings;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatDialog;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Toast;
import com.kenumir.materialsettings.MaterialSettings;
import com.kenumir.materialsettings.items.CheckboxItem;
import com.kenumir.materialsettings.items.HeaderItem;
import com.kenumir.materialsettings.items.SwitcherItem;
import com.kenumir.materialsettings.items.TextItem;
import com.kenumir.materialsettings.storage.StorageInterface;
import de.greenrobot.event.EventBus;
import sun.bob.leela.R;
import sun.bob.leela.adapters.SettingsSpinnerAdapter;
import sun.bob.leela.db.Account;
import sun.bob.leela.db.AccountHelper;
import sun.bob.leela.events.CryptoEvent;
import sun.bob.leela.events.DBExportEvent;
import sun.bob.leela.runnable.ChangePasswordRunnable;
import sun.bob.leela.runnable.DBExportRunnable;
import sun.bob.leela.ui.views.SelectorItem;
import sun.bob.leela.utils.AppConstants;
import sun.bob.leela.utils.CryptoUtil;
import sun.bob.leela.utils.ResUtil;
import sun.bob.leela.utils.UserDefault;
package sun.bob.leela.ui.activities;




/**
 * Created by bob.sun on 16/6/21.
 */
public class SettingsActivity extends MaterialSettings {

    public static final int RequestCodeSetMainPassword = 0x700;
    private TextItem quickSwitcher;
    private SelectorItem selectorItem;
    private AppCompatDialog dialog;
    private boolean didClickedChangeMaster;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setTitle(R.string.settings);

        EventBus.getDefault().register(this);

        addItem(new HeaderItem(this).setTitle(getString(R.string.security)));
        addItem(new CheckboxItem(this, UserDefault.kNeedPasswordWhenLaunch).setTitle(getString(R.string.need_password_when_launch)).setOnCheckedChangeListener(new CheckboxItem.OnCheckedChangeListener() {
            @Override
            public void onCheckedChange(CheckboxItem cbi, boolean isChecked) {
                UserDefault.getInstance(null).setNeedPasswordWhenLaunch(isChecked);
            }
        }));

        String title = UserDefault.getInstance(null).hasQuickPassword() ? getString(R.string.disable_gesture_lock) : getString(R.string.enable_gesture_lock);

        quickSwitcher = new TextItem(this, "quick_pass").setTitle(title).setOnclick(new TextItem.OnClickListener() {
            @Override
            public void onClick(TextItem textItem) {
                if (UserDefault.getInstance(null).hasQuickPassword()) {
                    UserDefault.getInstance(null).clearQuickPassword();
                    quickSwitcher.updateTitle(getString(R.string.enable_gesture_lock));
                } else {
                    Intent intent = new Intent(SettingsActivity.this, SetQuickPasswordActivity.class);
                    intent.putExtra("type", SetQuickPasswordActivity.ShowTypeSet);
                    startActivityForResult(intent, RequestCodeSetMainPassword);
                }
            }
        });
        addItem(quickSwitcher);

        didClickedChangeMaster = false;
        addItem(new TextItem(this, "change_password").setTitle(getString(R.string.change_master_password)).setOnclick(new TextItem.OnClickListener() {
            @Override
            public void onClick(TextItem textItem) {
                didClickedChangeMaster = true;
                startActivity(new Intent(SettingsActivity.this, AuthorizeActivity.class));
            }
        }));

        addItem(new HeaderItem(this).setTitle(getString(R.string.puff_secure_keyboard)));
        addItem(new TextItem(this, "ime").setTitle(getString(R.string.enable_puff_secure_keyboard)). setOnclick(new TextItem.OnClickListener() {
            @Override
            public void onClick(TextItem textItem) {
                startActivity(new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS));
                Toast.makeText(SettingsActivity.this, getString(R.string.please_enable_puf_ime), Toast.LENGTH_LONG).show();
            }
        }));

        addItem(new HeaderItem(this).setTitle(getString(R.string.database)));
        addItem(new TextItem(this, "database").setTitle(getString(R.string.export_database))
                .setSubtitle(getString(R.string.database_file_can_be_used))
                .setOnclick(new TextItem.OnClickListener() {
            @Override
            public void onClick(TextItem textItem) {

                new AlertDialog.Builder(SettingsActivity.this).setTitle(getString(R.string.export_database))
                        .setMessage(R.string.confrim_export_database)
                        .setCancelable(false)
                        .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface d, int which) {
                                d.dismiss();
                                dialog = ResUtil.getInstance(null).showProgressbar(SettingsActivity.this);
                                DBExportRunnable runnable = new DBExportRunnable(SettingsActivity.this);
                                new Thread(runnable).run();
                            }
                        })
                        .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                            }
                        }).show();

            }
        }));

        addItem(new HeaderItem(this).setTitle(getString(R.string.about)));
        addItem(new TextItem(this, "about").setTitle(getResources().getString(R.string.about_puff_title)).setOnclick(new TextItem.OnClickListener() {
            @Override
            public void onClick(TextItem textItem) {
                startActivity(new Intent(SettingsActivity.this, AboutActivity.class));
            }
        }));


    }

    @Override
    public void onResume() {
        super.onResume();
        quickSwitcher.updateTitle(UserDefault.getInstance(null).hasQuickPassword()
                ? getString(R.string.disable_gesture_lock)
                : getString(R.string.enable_gesture_lock));
    }

    @Override
    public void onStop() {
        super.onStop();
        EventBus.getDefault().unregister(this);
    }


    public void onEventMainThread(Object event) {
//        if (!(event instanceof DBExportEvent)) {
//            return;
//        }
        if (event instanceof CryptoEvent && didClickedChangeMaster) {