com.z299studio.pb.Settings.java Source code

Java tutorial

Introduction

Here is the source code for com.z299studio.pb.Settings.java

Source

/*
* Copyright 2015 Qianqian Zhu <zhuqianqian.299@gmail.com> All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.z299studio.pb;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SwitchCompat;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.text.DateFormat;
import java.util.Date;

public class Settings extends AppCompatActivity implements AdapterView.OnItemClickListener,
        SettingListDialog.OnOptionSelected, ImportExportTask.TaskListener, ActionDialog.ActionDialogListener,
        SyncService.SyncListener, FingerprintDialog.FingerprintListener, DecryptTask.OnTaskFinishListener {

    private static final String TAG_DIALOG = "action_dialog";
    private static final int PERMISSION_REQUEST = 1;

    private String mText;
    private int mActionType;
    private int mOperation;
    private int mOption;
    private byte[] mData;

    private interface ActionListener {
        void onAction(SettingItem sender);
    }

    private class SettingItem {
        public static final int TYPE_CATEGORY = 0;
        public static final int TYPE_SWITCH = 1;
        public static final int TYPE_SELECTION = 2;
        public static final int TYPE_ACTION = 3;
        public int mType;
        public int mId;
        public String mTitle;
        public String mDescription;

        public SettingItem(int id, String title, String description) {
            mId = id;
            mTitle = title;
            mDescription = description;
            mType = TYPE_CATEGORY;
        }

        public void onClick(View view) {
        }

        public Object getValue() {
            return null;
        }
    }

    private class SettingItemSwitch extends SettingItem {
        private boolean mValue;

        public SettingItemSwitch(int id, String title, String description) {
            super(id, title, description);
            mType = TYPE_SWITCH;
        }

        @Override
        public void onClick(View view) {
            mValue = !mValue;
        }

        @Override
        public Object getValue() {
            return mValue;
        }

        public SettingItemSwitch setValue(boolean initial) {
            mValue = initial;
            return this;
        }
    }

    private class SettingItemAction extends SettingItem {
        private ActionListener mListener;

        public SettingItemAction(int id, String title, String description) {
            super(id, title, description);
            mType = TYPE_ACTION;
        }

        public SettingItemAction setListener(ActionListener l) {
            mListener = l;
            return this;
        }

        @Override
        public void onClick(View view) {
            if (mListener != null) {
                mListener.onAction(this);
            }
        }
    }

    private class SettingItemSelection extends SettingItem {
        private String[] mOptions;
        private int mSelection;

        public SettingItemSelection(int id, String title, String description) {
            super(id, title, description);
            mType = TYPE_SELECTION;
        }

        public SettingItemSelection setOptions(String[] options) {
            mOptions = options;
            return this;
        }

        @Override
        public void onClick(View view) {
            SettingListDialog.build(mTitle, mOptions, mSelection).show(getSupportFragmentManager(), TAG_DIALOG);
        }

        @Override
        public Object getValue() {
            return mSelection;
        }

        public SettingItemSelection setValue(int initial) {
            mSelection = initial;
            mDescription = mOptions[mSelection];
            return this;
        }

        public String getText() {
            return mOptions[mSelection];
        }

    }

    private class SettingItemAdapter extends BaseAdapter {

        private Context mContext;
        private SettingItem[] mItems;

        @Override
        public int getCount() {
            return mItems.length;
        }

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

        @Override
        public long getItemId(int position) {
            return mItems[position].mId;
        }

        @Override
        public boolean isEnabled(int position) {
            return mItems[position].mType != SettingItem.TYPE_CATEGORY;
        }

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            final SettingItem item = mItems[position];
            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View view;
            switch (item.mType) {
            default:
            case SettingItem.TYPE_CATEGORY:
                view = inflater.inflate(R.layout.list_item_title, parent, false);
                break;
            case SettingItem.TYPE_SWITCH:
                view = inflater.inflate(R.layout.list_item_switch, parent, false);
                break;
            case SettingItem.TYPE_SELECTION:
            case SettingItem.TYPE_ACTION:
                view = inflater.inflate(R.layout.list_item_selection, parent, false);
                break;
            }
            TextView description = (TextView) view.findViewById(R.id.description);
            ((TextView) view.findViewById(R.id.title)).setText(item.mTitle);
            if (item.mDescription != null) {
                description.setText(item.mDescription);
                view.setTag(description);
            } else {
                if (description != null) {
                    description.setVisibility(View.GONE);
                }
            }
            if (item.mType == SettingItem.TYPE_SWITCH) {
                SwitchCompat sc = (SwitchCompat) view.findViewById(R.id.switch_ctrl);
                sc.setChecked((boolean) item.getValue());
                view.setTag(sc);
                sc.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        onItemClick(null, null, position, item.mId);
                    }
                });
            }
            return view;
        }

        public SettingItemAdapter(Context context, SettingItem[] items) {
            mContext = context;
            mItems = items;
        }

        public void updateDescription(String text, int position, ListView listView) {
            int firstVisible = listView.getFirstVisiblePosition();
            View view = listView.getChildAt(position - firstVisible);
            if (view != null) {
                TextView description = (TextView) view.getTag();
                description.setText(text);
            }
        }
    }

    private ActionListener mActionListener = new ActionListener() {
        @Override
        public void onAction(SettingItem sender) {
            int type = 0;
            switch (sender.mId) {
            case R.string.export_data:
                type = ActionDialog.ACTION_EXPORT;
                break;
            case R.string.import_data:
                type = ActionDialog.ACTION_IMPORT;
                break;
            case R.string.change_pwd:
                type = ActionDialog.ACTION_RESET_PWD;
                break;
            case R.string.licence:
                type = ActionDialog.ACTION_LICENSE;
                break;
            case R.string.credits:
                type = ActionDialog.ACTION_CREDITS;
                break;
            case R.string.last_sync:
                if (Application.Options.mSync != C.Sync.NONE) {
                    SyncService.getInstance(Settings.this, Application.Options.mSync).initialize()
                            .setListener(Settings.this).connect(Application.getInstance().getLocalVersion());
                }
                return;
            case R.string.guide:
                Intent intent = new Intent(Settings.this, TourActivity.class);
                intent.putExtra(C.ACTIVITY, C.Activity.SETTINGS);
                startActivity(intent);
                overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
                return;
            }
            ActionDialog.create(type).show(getSupportFragmentManager(), TAG_DIALOG);
        }
    };

    private SettingItemAdapter mAdapter;
    private boolean mShowOtherInitial;
    private int mRequestingPosition;
    private ListView mListView;

    private SettingItemAdapter initSettings() {
        int itemSize = 19;
        if (Application.Options.mFpStatus != C.Fingerprint.UNKNOWN) {
            itemSize += 1;
        }
        SettingItem[] items = new SettingItem[itemSize];
        int index = 0;
        String desc;
        items[index++] = new SettingItem(0, getString(R.string.general), null);
        items[index++] = new SettingItemAction(R.string.import_data, getString(R.string.import_data), null)
                .setListener(mActionListener);
        items[index++] = new SettingItemAction(R.string.export_data, getString(R.string.export_data), null)
                .setListener(mActionListener);
        items[index++] = new SettingItemSwitch(R.string.show_ungrouped, getString(R.string.show_ungrouped), null)
                .setValue(Application.Options.mShowOther);
        items[index++] = new SettingItemSelection(R.string.theme, getString(R.string.theme), null)
                .setOptions(getResources().getStringArray(R.array.theme_names))
                .setValue(Application.Options.mTheme);
        items[index++] = new SettingItemAction(R.string.guide, getString(R.string.guide), null)
                .setListener(mActionListener);
        items[index++] = new SettingItem(0, getString(R.string.sync), null);
        items[index++] = new SettingItemSelection(R.string.sync_server, getString(R.string.sync_server), null)
                .setOptions(getResources().getStringArray(R.array.sync_methods))
                .setValue(Application.Options.mSync);
        if (Application.Options.mSyncTime.after(new Date(0L))) {
            DateFormat df = DateFormat.getDateTimeInstance();
            desc = df.format(Application.Options.mSyncTime);
        } else {
            desc = getString(R.string.never);
        }
        items[index++] = new SettingItemAction(R.string.last_sync, getString(R.string.last_sync), desc)
                .setListener(mActionListener);
        items[index++] = new SettingItemSwitch(R.string.sync_msg, getString(R.string.sync_msg), null)
                .setValue(Application.Options.mSyncMsg);
        items[index++] = new SettingItem(0, getString(R.string.security), null);
        int lock_options[] = { 1000, 5 * 60 * 1000, 30 * 60 * 1000, 0 };
        int selection = 0;
        int saved = Application.Options.mAutoLock;
        for (int i = 0; i < lock_options.length; ++i) {
            if (lock_options[i] == saved) {
                selection = i;
            }
        }
        items[index++] = new SettingItemSelection(R.string.auto_lock, getString(R.string.auto_lock), null)
                .setOptions(getResources().getStringArray(R.array.lock_options)).setValue(selection);
        items[index++] = new SettingItemSwitch(R.string.show_password, getString(R.string.show_password), null)
                .setValue(Application.Options.mAlwaysShowPwd);
        items[index++] = new SettingItemSwitch(R.string.warn_copy, getString(R.string.warn_copy), null)
                .setValue(Application.Options.mWarnCopyPwd);
        items[index++] = new SettingItemAction(R.string.change_pwd, getString(R.string.change_pwd), null)
                .setListener(mActionListener);
        if (Application.Options.mFpStatus != C.Fingerprint.UNKNOWN) {
            items[index++] = new SettingItemSwitch(R.string.fp_title, getString(R.string.fp_title),
                    getString(R.string.fp_desc)).setValue(Application.Options.mFpStatus == C.Fingerprint.ENABLED);
        }

        items[index++] = new SettingItem(0, getString(R.string.about), null);
        items[index++] = new SettingItemAction(R.string.licence, getString(R.string.licence), null)
                .setListener(mActionListener);
        items[index++] = new SettingItemAction(R.string.credits, getString(R.string.credits), null)
                .setListener(mActionListener);
        String versionName;
        try {
            versionName = this.getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
        } catch (PackageManager.NameNotFoundException e) {
            versionName = "2.2.0";
        }
        desc = getString(R.string.version, versionName);
        items[index] = new SettingItemAction(R.string.build, getString(R.string.build), desc);
        mAdapter = new SettingItemAdapter(this, items);
        return mAdapter;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        if (Application.getInstance() == null || Application.getInstance().getAccountManager() == null) {
            super.onCreate(savedInstanceState);
            startActivity(new Intent(this, HomeActivity.class));
            this.finish();
            return;
        }
        if (savedInstanceState != null) {
            mRequestingPosition = savedInstanceState.getInt("requested_position");
        }
        setTheme(C.THEMES[Application.Options.mTheme]);
        if (Application.getInstance().queryChange(Application.THEME)) {
            int[] primaryColors = { R.attr.colorPrimary, R.attr.colorPrimaryDark, R.attr.colorAccent,
                    R.attr.textColorNormal, R.attr.iconColorNormal };
            TypedArray ta = obtainStyledAttributes(primaryColors);
            for (int i = 0; i < C.ThemedColors.length; ++i) {
                C.ThemedColors[i] = ta.getColor(i, 0);
            }
            ta.recycle();
        }
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_settings);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            View v = findViewById(R.id.activity_root);
            v.setBackgroundColor(C.ThemedColors[C.colorPrimary]);
        }
        //        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        //            mFingerprintManager = (FingerprintManager)getSystemService(FINGERPRINT_SERVICE);
        //        }
        mShowOtherInitial = Application.Options.mShowOther;
        setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
        getSupportActionBar().setDisplayShowHomeEnabled(true);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        mListView = (ListView) findViewById(R.id.list);
        mListView.setAdapter(initSettings());
        mListView.setOnItemClickListener(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (Application.getInstance().needAuth()) {
            Intent homeIntent = new Intent(this, HomeActivity.class);
            homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(homeIntent);
            finish();
        }
    }

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

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putInt("requested_position", mRequestingPosition);
        super.onSaveInstanceState(outState);
    }

    @Override
    public void onBackPressed() {
        if (mShowOtherInitial != Application.Options.mShowOther) {
            Application.getInstance().notifyChange(Application.DATA_OTHER);
        }
        super.onBackPressed();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case android.R.id.home:
            onBackPressed();
            break;
        }
        return true;
    }

    @Override
    protected void onActivityResult(final int requestCode, final int resultCode, Intent data) {
        switch (requestCode) {
        case SyncService.REQ_RESOLUTION:
            SyncService.getInstance().onActivityResult(requestCode, resultCode, data);
            break;
        case ActionDialog.REQ_CODE_FILE_SELECTION:
            ActionDialog dialog = (ActionDialog) getSupportFragmentManager().findFragmentByTag(TAG_DIALOG);
            dialog.onFileSelected(this, resultCode, data);
            Application.getInstance().ignoreNextPause();
            break;
        }
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        SettingItem item = (SettingItem) mAdapter.getItem(position);
        item.onClick(view);
        mRequestingPosition = position;
        if (item.mType == SettingItem.TYPE_SWITCH) {
            boolean value = (boolean) item.getValue();
            if (view != null) {
                SwitchCompat sc = (SwitchCompat) view.getTag();
                sc.setChecked(value);
            }
            handleSwitchOption(item.mId, value);
        }
    }

    @Override
    public void onSelected(int selection) {
        SettingItemSelection item = (SettingItemSelection) mAdapter.getItem(mRequestingPosition);
        item.setValue(selection);
        mAdapter.updateDescription(item.getText(), mRequestingPosition, mListView);
        SharedPreferences.Editor editor = Application.getInstance().mSP.edit();
        switch (item.mId) {
        case R.string.theme:
            Application.getInstance().notifyChange(Application.THEME);
            Application.Options.mTheme = (int) item.getValue();
            editor.putInt(C.Keys.THEME, Application.Options.mTheme);
            startActivity(new Intent(this, Settings.class));
            finish();
            overridePendingTransition(0, 0);
            break;
        case R.string.sync_server:
            Application.Options.mSync = (int) item.getValue();
            if (Application.Options.mSync == C.Sync.NONE) {
                editor.putInt(C.Sync.SERVER, Application.Options.mSync);
            } else {
                SyncService.getInstance(this, Application.Options.mSync).initialize().setListener(this)
                        .connect(Application.getInstance().getLocalVersion());
                mRequestingPosition += 1; // Bad design
            }
            break;
        case R.string.auto_lock:
            int lock_options[] = { 1000, 5 * 60 * 1000, 30 * 60 * 1000, 0 };
            Application.Options.mAutoLock = lock_options[(int) item.getValue()];
            editor.putInt(C.Keys.AUTO_LOCK_TIME, Application.Options.mAutoLock);
            break;
        }
        editor.apply();
    }

    @Override
    public void onFinish(boolean authenticate, int operation, String result) {
        if (result == null) {
            if (authenticate) {
                ActionDialog.create(ActionDialog.ACTION_AUTHENTICATE).show(getSupportFragmentManager(), TAG_DIALOG);
                return;
            }
            Application.showToast(Settings.this,
                    operation == ActionDialog.ACTION_EXPORT ? R.string.export_failed : R.string.import_failed,
                    Toast.LENGTH_LONG);
        } else {
            if (operation == ActionDialog.ACTION_EXPORT) {
                Application.showToast(Settings.this, getResources().getString(R.string.export_success, result),
                        Toast.LENGTH_LONG);
            } else {
                if (Application.getInstance().getAccountManager().saveRequired()) {
                    Application.getInstance().saveData();
                    Application.getInstance().notifyChange(Application.DATA_ALL);
                }
                Application.showToast(Settings.this, R.string.import_success, Toast.LENGTH_LONG);
            }
        }
    }

    @Override
    public void onConfirm(String text, int type, int operation, int option) {
        String permission;
        if (operation == ActionDialog.ACTION_AUTHENTICATE) {
            new ImportExportTask(this, text).execute();
        } else if (operation == ActionDialog.ACTION_RESET_PWD
                && Application.Options.mFpStatus == C.Fingerprint.ENABLED) {
            FingerprintDialog.build(true).show(getSupportFragmentManager(), "dialog_fp");
        } else if (operation == ActionDialog.ACTION_AUTHENTICATE2) {
            Application.FileHeader header = Application.FileHeader.parse(mData);
            if (text != null) {
                new DecryptTask(mData, header, this).execute(text);
            } else {
                Application.getInstance().increaseVersion(header.revision);
                SyncService.getInstance().send(Application.getInstance().getData());
            }
        } else {
            if (operation == ActionDialog.ACTION_IMPORT || operation == ActionDialog.ACTION_EXPORT) {
                permission = operation == ActionDialog.ACTION_IMPORT ? Manifest.permission.READ_EXTERNAL_STORAGE
                        : Manifest.permission.WRITE_EXTERNAL_STORAGE;

                if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(this, new String[] { permission }, PERMISSION_REQUEST);
                    mActionType = type;
                    mText = text;
                    mOperation = operation;
                    mOption = option;
                } else {
                    new ImportExportTask(this, text, Application.getInstance().getPassword(), type, operation,
                            option).execute();
                }
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResult) {
        if (requestCode == PERMISSION_REQUEST) {
            if (grantResult[0] == PackageManager.PERMISSION_GRANTED) {
                new ImportExportTask(this, mText, Application.getInstance().getPassword(), mActionType, mOperation,
                        mOption).execute();
            }
        }
    }

    @Override
    public void onSyncFailed(int errorCode) {
    }

    @Override
    public void onSyncProgress(int actionCode) {
        String time = null;
        Application app = Application.getInstance();
        app.mSP.edit().putInt(C.Sync.SERVER, Application.Options.mSync).apply();
        if (actionCode == SyncService.CA.AUTH) {
            app.ignoreNextPause();
        } else if (actionCode == SyncService.CA.DATA_RECEIVED) {
            time = app.onSyncSucceed();
            byte[] data = SyncService.getInstance().requestData();
            Application.FileHeader fh = Application.FileHeader.parse(data);
            if (fh.valid && fh.revision > app.getLocalVersion()) {
                new DecryptTask(data, fh, this).execute(app.getPassword());
            } else if (fh.revision < app.getLocalVersion()) {
                SyncService.getInstance().send(app.getData());
            }
            if (fh.revision != Application.Options.mSyncVersion) {
                app.onVersionUpdated(fh.revision);
            }
        } else if (actionCode == SyncService.CA.DATA_SENT) {
            time = app.onSyncSucceed();
            Application.showToast(this, R.string.sync_success_server, Toast.LENGTH_SHORT);
            app.onVersionUpdated(app.getLocalVersion());
        }
        if (time != null) {
            mAdapter.updateDescription(time, mRequestingPosition, mListView);
        }
    }

    @Override
    public void preExecute() {
    }

    @Override
    public void onFinished(boolean isSuccessful, AccountManager manager, String password, byte[] data,
            Application.FileHeader header, Crypto crypto) {
        if (isSuccessful) {
            Application app = Application.getInstance();
            Application.showToast(this, R.string.sync_success_local, Toast.LENGTH_SHORT);
            Application.Options.mSyncVersion = header.revision;
            app.setAccountManager(manager, -1, getString(R.string.def_category));
            app.setCrypto(crypto);
            app.saveData(data, header);
            app.onVersionUpdated(header.revision);
            app.notifyChange(Application.DATA_ALL);
            if (!app.getPassword().equals(password)) {
                app.setPassword(password, false);
                if (Application.Options.mFpStatus == C.Fingerprint.ENABLED) {
                    FingerprintDialog.build(true).show(getSupportFragmentManager(), "dialog_fp");
                }
            }
        } else {
            mData = data;
            ActionDialog.create(ActionDialog.ACTION_AUTHENTICATE2).show(getSupportFragmentManager(),
                    "dialog_auth2");
        }
    }

    private void handleSwitchOption(int id, boolean value) {
        SharedPreferences.Editor editor = Application.getInstance().mSP.edit();
        switch (id) {
        case R.string.show_ungrouped:
            Application.Options.mShowOther = value;
            editor.putBoolean(C.Keys.SHOW_OTHER, value);
            break;
        case R.string.sync_msg:
            Application.Options.mSyncMsg = value;
            editor.putBoolean(C.Sync.MSG, value);
            break;
        case R.string.show_password:
            Application.Options.mAlwaysShowPwd = value;
            editor.putBoolean(C.Keys.SHOW_PWD, value);
            break;
        case R.string.warn_copy:
            Application.Options.mWarnCopyPwd = value;
            editor.putBoolean(C.Keys.WARN_COPY, value);
            break;
        case R.string.fp_title:
            if (value) {
                FingerprintDialog.build(true).show(getSupportFragmentManager(), "dialog_fp");
            } else {
                Application.getInstance().clearFpData();
            }
        }
        editor.apply();
    }

    @Override
    public void onCanceled(boolean isFirstTime) {
    }

    @Override
    public void onConfirmed(boolean isFirstTime, byte[] password) {
    }

}